Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

What would a 'Clojure on Rails' framework look like? I think that's the primary reason why such a framework has yet to find traction; there's no single, obvious way to go about it.

The efforts made so far in this space have taken many different approaches, because they're all experiments. Explorations of what an idiomatic Clojure web framework might potentially look like. Clojure has been around for over a decade now, and it's fairly mature as a language; but it's ideology is young in comparison to more established paradigms like OOP.

To make matters more complex, Rails came to prominence in an era where web applications were mostly of one type: server-side HTML with a sprinkling of JavaScript. Nowadays there tends to be more options, e.g. a web application may consist of a single HTML shim, with a thick React client that talks to a GraphQL back end.

So on the one hand we have a language that's still exploring its identity; on the other we have a rapidly changing idea of what a web application should be.

My guess is that an idiomatic Clojure web service would look like a client-accessible relational database with a strong security model and datalog queries, along with some system for adding in side-effectful hooks to respond to data change. In other words, something rather different in design to Rails.



Something like Phoenix? Elixir is a newer language, with a lot of similarities to Clojure. Phoenix even made the most loved web framework in the Stack Overflow 2022 survey.

Why did they converge on something so, apparently, great, in such a low amount of time? And why is this so hard for Clojure?

Not taking sides or trying to be negative, just honestly curious what the driving factor is.


Because there's no alternative in Elixir.

In Clojure, you can make a website many other ways, use any existing Java server, implement your own server quickly, use any templating language you want, implement your own quickly, use whatever routing lib you want, implement your own quickly, etc.

Not only are there existing options from Java, but implementing your own is approachable to your average dev, and can be done in a reasonably short amount of time.

Maybe it's a bit of the Lisp curse afterall. A language too productive, that no one bothers settling for the one framework.

I also think Elixirs Ruby friendly syntax brought in a lot of Rubyists with Rails experience, and that attracted people who used Rails to Phoenix, giving it that inertia.

Chris McCord used to be a Rails developer, so he came directly from Rails, so it made sense to rebuild a similar framework for Elixir, and a lot of people followed from Rails to Elixir as a better ruby with better scaling.


> In Clojure, you can make a website many other ways, use any existing Java server, implement your own server quickly, use any templating language you want, implement your own quickly, use whatever routing lib you want, implement your own quickly, etc.

The thing is, many (most?) developers are interested in building the end product, not building or heavily researching the ideal framework/library/stack itself. Without something easy to use, widely understood, and that has all the pieces hooked together, a lot of developers will get frustrated and seek different pastures so they can just concentrate on a product. That's why Rails and other similar libraries in other languages are so successful and make those languages successful, because a key layer is handled for you so you can just get higher-level work done.

I used Clojure many years full-time and liked so many things about it, but the myriad ways to do the same thing does not appeal to everyone. This also extends to other aspects of the language -- the many different development environments and tooling, hooking together all the various ways to actually write, develop Clojure code. Many developers also don't want a lot of their time spent building a development workflow.


Maybe since I consider myself more of a software engineer than a developer, I have a different viewpoint, but to me, as a SE, my job is not just to deliver the end product, but actually to produce the version of the end product that is also of as good quality as it can be within the budget and constraints of the business, as well as guarantee enough architectural runway to meet the business future goals and needs without increasing the future cost or lowering the delivery velocity over time. Often, I even contribute to what the end product should be, by consulting and informing on what can or cannot be achieved with technologies, or how by changing certain aspect of the product we can enable a lot more functionality in other ways.

That means, throwing a scaffolded template and a prefab framework might be good for an initial proof of concept and v0 testing the market launch, but with Clojure you can often deliver POCs and v0s just as fast, but then have the flexibility to grow it as it needs too, where frameworks often become big drag on what you can do and how quickly you can do so as you need to grow the product.

Basically, the inner working matters to the end product, especially when products don't have an end, but are really a lifetime of support and continued changes in feature-set and compatibility/scale.


Valid perspective for some developers, yet thousands of software engineers enjoy creative, satisfying careers building projects without concerns for the inner workings of a web library or the extra effort to engineer the stack directly. They just want to build the product using an established framework.


and clojure has several such frameworks.


... but nothing like rails, hence this article and discussion


I totally respect that, and Clojure could invest more in offering frameworks or even no-code platforms or such features, but the truth is it doesn't. The language very much targets the people who are interested in not just the functional requirements, but also the non-functional requirements of performance, scale, architectural runway, future extensibility, operations, maintainability, correctness, re-usability, etc. Especially, Clojure targets those who believe a balance between all these and functional requirements is the holy grail. That's why it won't be the most correct, the most performant, the most productive, but a pragmatic balance of all these in almost equal parts.

Maybe it should also embrace the people looking to get a product out by simply using a framework, and I'd say there's more of that in Clojure today than ever before, but the community I think is more composed of the former people that I describe, which is why you don't see any attempted framework take hold in the community, because most current members are not in the group that "just want to build the product using an established framework".

I think the community has settled, ounce again, on a bit of a balanced approach, Kit (https://github.com/kit-clj/kit) and Edge (https://github.com/juxt/edge) are such hybrids. And some more direct viable frameworks have come along like Biff (https://biffweb.com/) and Fulcro (https://fulcro.fulcrologic.com/).

That said, since the community is more composed of people like me, you don't see a mass move of every Clojurian switching to one of those.

So it creates some questions?

1. Is it a problem that the language targets engineers more interested in a balance between non-functional and functional?

2. Should it be mutually exclusive, or can Clojure equally serve both niche? And if so, should it, why?

3. Is the claim that you can be as productive and it is just as easy to build a product without using a framework in Clojure true? Does this apply to everyone, or only certain personalities or people with certain amount of lower level knowledge?

4. Is Clojure's marketing misleading? Are people looking to just "build the product using an established framework" mislead in thinking Clojure will offer them salvation?

5. Where do most developer fall in, if they don't fall in the category Clojure currently targets, then does that mean Clojure cannot become mainstream? To go mainstream does it mean you have to target frameworks because there are more developers looking to just make a product using a framework?

I don't have answers to these, I'm just trying to define the current state and what the problem with it might be, or if it even is a problem.


Elixir is close to a different syntax for Erlang/OTP. It has high quality built-in alternatives since it came into existence.


Erlang is not commonly used for web applications though, with Clojure, you had existing Java shops with Java web app who transitioned to using Clojure, simply keeping their Java web framework and writing their business logic in Clojure instead.

If you adopted Elixir, you most likely were starting from scratch, a green field project. Since Erlang is already great at concurrent distributed systems, Elixir's niche became web application development, and it didn't have much existing libraries or frameworks to leverage, so I think it makes more sense for an initial popular framework to come to existence and rally others around.

It still built on Erlang fundamentals, its web server is Cowboy for example, but there wasn't much on top to help with other parts of a web app.


I haven't used Elixir enough to be particularly confident in an opinion about it. However, Phoenix appears to have a similar design to many other MVC frameworks, and if a conventional design works for a language, there's less need to experiment. Initial development can converge around something that's tried and tested.

A conventional framework doesn't fit Clojure particularly well, so the community has been forced to tread new ground to figure out what works with the language.


Elixir is a functional language as well, and borrows inspiration from Clojure in particular.

I haven't dug into Clojure enough, but I'm curious why you think a conventional MVC-style framework wouldn't be a good fit (not that the article is making this argument).


This is a topic that I think requires a more in depth article, but I'll attempt to justify myself as best I can in the limited space of a comment.

In most languages, related data is generally represented by some manner of closed record, struct or object. In Clojure, this data is represented by open maps instead.

This distinction may seem minor or even irrelevant, but in my view it's the key difference between Clojure and other languages, and the reason why the MVC pattern has never quite fit comfortably in Clojure.

In a language that uses closed records, complex data tends to align itself in terms of fixed hierarchies. Think of how the models in Rails are typically laid out. You have a few dozen models, with a handful of fields each, arranged in some sort of static tree or graph.

In Clojure, data doesn't tend to align itself in the same way. Data doesn't need to be artificially grouped if there's no benefit in doing so; its structure can be much more amorphous.

There's a similar problem at the "view" end. REST tends to assume a hierarchy of resources, when that may not be the best way for the client to get the data it wants, or for the server to represent the data.


> Data doesn't need to be artificially grouped if there's no benefit in doing so; its structure can be much more amorphous.

I'm curious, just because Clojure offers that flexibility to a developer when writing the logic in their app, why does this flexibility need to "interfere" (for lack of a better word) with the design of a web framework?


For the same reason you wouldn't design a web framework in Ruby that doesn't use classes. Technically possible, but you'd be fighting against the design of the language.


In Clojure, this data is represented by open maps instead.

Is Clojure unique here? seems this is the norm for Javascript applications too, that are done mostly with a FP style, instead of open clojure maps you have open JS objects. Most JS SDKs and libraries I have work with is just passing JS objects between them and your code.


Javascript objects have some differences to Clojure maps that make them harder to use in the same way.

For example, you don't have to store functions in objects in Javascript, but the language design encourages it. This is problematic because we can't pull data out of an object without considering the functions that rely on it.

Another issue is that keys are not unique. Two objects might contain an "id" key, for example, that identifies them in different ways. This is problematic if you want to arbitrarily merge objects together.

Idiomatic Javascript might look like this:

    user.orders.total_cost()
But if we want to program in the same way as Clojure, we'd perhaps be writing something more like:

    Orders.total_cost(user["user/orders"]);
Not impossible, but certainly more inconvenient.

The more you force rigid categorisations and behaviour on data, the harder it is to manipulate and organise in different ways. In-memory data is almost always ordered with a hierarchical structure, because that's what closed records gravitate toward. But if we take a look at databases, its rare to find any organised along strict hierarchical lines.


Another issue is that keys are not unique. Two objects might contain an "id" key, for example, that identifies them in different ways. This is problematic if you want to arbitrarily merge objects together.

Don't exactly understand this part, if one of your objects has its unique identifier as "userID" and the other as "invoiceID" you can merge them without conflict or what I'm missing? "id" is indeed use widely in blog examples/tutorials and even books but it's not the norm for enterprise data.


If you ensure that all object keys are uniquely named, then merging objects wouldn't be a problem. But unless you use some sort of naming convention to enforce it, the more keys you have, the more likely it is for naming clashes to occur.


Ok, so this normally tackle in Clojure using namespace keywords correct?


Yep. And the advantage of namespaces over a naming convention is that they can be enforced by the compiler and shortened with aliases.


JS offers classes (or a similar construct pre-ES2015) and you can’t easily merge two objects (there’s the spread syntax, but that doesn’t bring along the prototype).

So you’re mostly rewarded by keeping object «types» seperate


I don’t know, JS is famously a lisp hidden under the C syntax.


and under the rest of the stuff Lisp does not have at its base, like an prototype object system.


It’s interesting though that JS never picked up a Rails alternative.


Elixir is still Actor based though, and relies on modeling behavior through something very akin to objects. You could even call it OOP if you went back to the more original message passing/late binding roots of OOP.


Kinda? I guess it depends upon what exactly you mean. If you mean behaviours, structs, protocols, modules and maps, then I can kinda see that, although Clojure has most of these too. But if you mean actors? Well...

I view Elixir as two languages in one: an actor language, and a functional programming language. Sometimes you gotta use the actor language (processes) to model behavior, but it's far better to leave that to the FP aspects.

The problem with using processes is there are a lot of concerns that only they can handle.

To be fair, I'm only a hobbyist Elixir dev. But there's lots of misinformation about how easy Elixir makes certain things. In my experience, it's not easy to build a process tree that factors in concurrency and synchronization, much less fault tolerance on top of that. Nevermind performance and gc isolation. Adding modelling on top of that just makes the job way harder.

The only real thing processes have in common with objects is they both hold state. Messages are kinda similar to methods if you squint hard enough, but there's more differences than similarities. Everything else listed above has nothing in common with any given object in your average object oriented programming language.


> If you mean behaviours, structs, protocols, modules and maps, then I can kinda see that, although Clojure has most of these too. But if you mean actors? Well

I kind of implied all of that, but I was specifically referring to the concept of modules and all its feature-sets, which together, in my opinion, does lead to a more OO like style of programming, especially structs, processes, behaviors and use, those things I feel are really similar to classes and inheritance. And there's also the dotted syntax for both map and struct access.

While yes, it's different than your common OO, in practice, you end up using these things similarly.

In Pheonix, simply put, almost all extension points relies on the __using__ macro, __MODULE__ compile time macro and use keyword. So it ends up very similar to an OOP framework, you basically extend classes, but you do so by using `use` instead of using `extend`, and a macro that copies over code and dynamically set the module name, instead of having an inherited lookup table.

How it's achieved is very different, but as a user of Pheonix, the ergonomics end up very similar.

Look at this:

    defmodule TodoWeb.ItemsController do
      use TodoWeb, :controller
    
      alias Todo.Items
    
      def index(conn, _params) do
        items = Items.list_items()
        render(conn, "index.html", items: items)
      end
    end
Yes, this isn't exactly a class, but like:

    package TodoWeb;
    
    import Todo.Items;
    
    class ItemsController extends TodoWebController
    
      public index(conn, params) {
        var items = Items.listItems();
        this.render(conn, "index.html", items);
      }
    }
How similar is the user experience?

And TodoWebController similary uses Phoenix.Controller, etc. It gives you a very similar feel to an inheritance tree, and pluging-in behavior in the framework by class extension.

Namespaces in Clojure really don't have this feel to them at all, now maybe you could shenaningan something similar with some similar macro convention over namespaces in Clojure, but it definitely isn't encouraged by the language or community the way it is in Elixir.

So in general, I feel modules in Elixir have a much closer feel to them to classes/objects in OO languages, and you end up using them similarly, where-as that's not the case for Clojure namespaces.


Maybe it's because Clojure has typically attracted a demographic who are more shy about self-promoting and marketing their new ideas and tools. Photon is an exciting (and relevant) example defying that trend though: https://www.hytradboi.com/2022/uis-are-streaming-dags

Also relevant as a Phoenix-like alternative for Clojure: https://github.com/tatut/ripley


Case in point. Ripley looks promising but it's just one dev and his single page Github doc. Useless to a newcomer or business looking for a framework for the long haul. Clojure has dozens of these projects.


Thanks for the reply James.

I agree with everything you said.

To clarify, I'm not advocating to re-create Rails for Clojure, rather, I'm arguing open-source efforts are too focused on the search for Clojure's Big Web Framework TM. However, I do like your guess as to what a Clojure Web service might look like.


Your observation is simply not true. To the contrary, the consensus of the community seems to be that there's no need for a rails-like framework for Clojure. Most of Clojurians are satisfied with what we have in the Web front, and are not worrying about the lack of "big Web framework" at all. I don't know where you got your impression from.


> the consensus of the community seems to be that there's no need for a rails-like framework for Clojure

Maybe (I’m not really sure how you judge community consensus) but, tangibly, the problem of libraries being old, broken and unmaintained while people go off and build new things is real.

It’s also undeniable that (see https://www.reddit.com/r/Clojure/comments/w9roqv/is_there_an... for example) that there are tonne of half baked efforts in the web space.

Maybe they’re unrelated.

There are lots of argument you could make;

Clojure has simultaneously tried to distance itself from the JVM and but also eat the cake of “just use the Java library for that”.

I personally think the “you don’t need to use the Java runtime” has seen a de facto split in the ecosystem which is also partially to blame.

Kotlin has been very successful at what is basically the same model, and it is different how? Stronger guiding principles? Found a silver bullet use case in android apps? Benefit of strongly opinionated steering from jetbrains?

I don’t think is technically more sophisticated than clojure, but it’s definitely more successful and popular.

I think we have to face the facts; clojure is flat if not already in decline. I know, usage goes up every year in the survey, but the ecosystem isn’t healthy. Especially in the web space.

> Most of Clojurians are satisfied with what we have in the Web front

Most? Geez. I think that’s a big call. I literally only ever hear people complain about this.

I am not satisfied by the current state of affairs. :/


I think this attitude in the Clojure community is sealing Clojure's fate. You discover the incredible genius of Clojure's simplicity then hit this brick wall of intransigence when you search for a framework which will give you leverage in the business world. Sad.


I got that impression from the relentless amount of web frameworks for Clojure that keep popping up. Anytime I see Clojure on the front page of HN, it's about some new Clojure web framework, so this post is a protest of that in a sense.

The big web framework is an idea, one where people won't reinvent the wheel over and over again, so that we can have a lot more non-web packages for Clojure. I'm quite literally saying, the effort could be better spent elsewhere.


I must admit, I do not understand why (some) people seem to get so excited about the latest "Web Framework" for Clojure, over and over again.

Yes, there seem to be a lot of them but they are mostly failures -- they rarely get any traction, and the creators often quickly move on (several to other tech altogether).

I don't think those people would have directed their efforts into other things -- libraries -- to any degree that would mitigate some of the other points in your article. People tend to work on what interests them and if someone wants to design and build a web framework, persuading them not to isn't going to encourage them to work on a "more useful" library I suspect.

I think the abandoned API library problem is real but partly because they were wrong-headed in the first place: Clojure is designed as a hosted language, specifically to take advantage of the vast, mature ecosystem that already exists on the JVM. When we got started with Clojure at work over a decade ago, it was common to see "all-Clojure" as a mindset and reject interop as a solution. I think that has changed a lot over the years and people now leverage interop and Java libraries as a "first solution" these days, perhaps with a thin wrapper around those libraries just to provide a more fluid, more functional approach.

At work, we've certainly taken a conscious decision to switch away from "all-Clojure" where there are mature Java libraries that are reasonable to use via interop (unless, of course, the "all-Clojure" equivalent is very well-maintained and really adds a lot of value).


Thanks for the reply Sean.

You're probably right about people working on what interests them.

I may have started Clojure during the "all-Clojure" years and failed to recognize the shift.


I am quite interested reading all this from both sides.. I saw a talk where Rich talked about clojure avoiding the HttpServletRequest calling it life sucking, and that one huge advantage clojure has is it's all data... but without wrappers, don't we have to then use these life sucking things? So many java api's are like this, the reason I use clojure is to not have these things, so I actually prefer the all clojure approach..


As noted elsewhere, it's not either/or here. Some wrappers are worth having and add huge value: Ring vs HttpServletRequest is a classic example, Cognitect's AWS libraries -- built on the same principle -- are another.

Wrapping Java Time, on the other hand, is a bit pointless because it's already a value-based system with a "mostly functional" approach that is straightforward to use via interop.

On the other hand, if you want to write portable -- .cljc -- code that manipulates date/time values, you _do_ want a wrapper so that your code works on both the JVM (using Java Time under the hood) and in JS (using whatever is the appropriate JS lib behind the scenes).


yes makes perfect sense everything you just said..so I suppose this is one reason why clojure doesn't have one library/framework to rule them all, Rich saying he gave us a tool to do what we want/need, and clojurists do just that! Do what makes best sense in your situation etc

unrelated sorta..

Really makes me wonder if the lisp curse is really not a curse, now that I also google it I see Eric Normand has something to say about it https://ericnormand.me/podcast/what-is-the-curse-of-lisp so maybe i should give that a listen!


So we should all just use Spring Boot? The need for a big Clojure framework is because Java and its frameworks are mostly object oriented.


I don't think the HN mentions of Clojure is representative of what the Clojure community thinks. If you are talking about the frontpage of HN, it is even less representative.

The Clojurians slack, Clojure Reddits and Clojurverse are more representative, and you can hardly see anything about Web frameworks in those places.


This is kinda like when go developers said the go community doesn't want generics. The people that really want these things will self select out of your community.


That's fine.

But I was merely pointing out a false premise. The article was saying too much focus was spent on "big web frameworks" in Clojure, but the reality is that most people in the community do not care about these at all.


I would agree, except this is different, anyone can be the one to provide this framework, you don't depend on the language stewards for it.

With Generics in Go, it's more about asking for more power to the community itself to be able to extend the language.

Clojure is strange in a way how much it can be extended by the community itself.

Now, it might still self-select out people who don't want to contribute to a big web framework and just want one they can use right away. But it wouldn't self-select against people wanting to build a web framework.


I'm not part of that "consensus".


> Nowadays there tends to be more options, e.g. a web application may consist of a single HTML shim, with a thick React client that talks to a GraphQL back end.

Best part about Rails is that you can do this as well. Rails has done a great job of being adaptable to new web technologies.


along with some system for adding in side-effectful hooks to respond to data change

Curious, can you elaborate on what you mean by this?


So, for example, email verification. There could be a watch that triggers when a new user is inserted into the database, and this triggers a side-effectful function that sends an email.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: