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.
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.
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.
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
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.
> 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.
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.
I also thought "Clojure needs a Rails" some 5 years ago. Nowadays (multiple, real-world Clojure jobs later) I don't.
I also learned that trying to second-guess why developers spend their time in certain libraries and not in other endeavors (like frameworks) comes across as pretty disrespectful and actually ignorant (considering that those people are very often more skilled/experienced than most of us).
(Good related read: Open Source Is Not About You)
So I'd recommend to anyone, open your mind, be ready to have some preconceptions changed, and contribute a significant deal to (Clojure) OSS to truly appreciate what we have. And write more interop ;)
I think the thing people most struggle with in Clojure is that it looks like it should be an incredibly pure, deeply opinionated language but it’s actually extremely pragmatic. There is never going to be a long lived, vertically integrated, do everything framework for Clojure. If it was going to happen it would have already. Rails took off because burnt out enterprise Java developers wanted to quit and have fun again. Clojure happened because enterprise Java developers wanted to do enterprise Java better.
This is true, clojure is not super opinionated as people tend to think. Its nice, as you get to ramp up easily. There seems to be a steady path where you start with writing "java" in lisp and end up with pure functions and 1 reduce + something to trigger side-effects. I have worked with 4 codebases and they differed vastly.
Apples to oranges. You're comparing a framework to a language. Ruby itself was born out of the desire for developer happiness. It doesn't follow logically that momentum for a large framework could not have evolved out of Clojure's origins.
> If we used interop for everything mundane, Clojure would really just be an S-expression shaped husk over Java code. Not a very good solution.
I don't have a lot of experience with Clojure, but speaking as someone who uses Kotlin on the server side, this attitude strikes me as odd. Most of the reason to use a JVM language is to take advantage of the mature and well-maintained Java libraries for basically everything.
If interop is considered a last resort (to the point where you reach for a 3-year-old unofficial Stripe library over the officially maintained Java one), what's the point of running on the JVM at all?
To expand a little on this, here's Rich Hickey on the subject [0]:
> I dislike writing Java/C# as much as anyone, and Clojure is my ticket
to writing much less of it, while leveraging the efforts of
multitudes. As I've said in my talks, most Clojure users go from "eww,
Java libs" to "ooh, Java libs", leveraging the fact there there is
already a lib for almost anything they need to do. And using the lib
is completely transparent, idiomatic and wrapper free. OTOH, if they
want to customize their interface to a lib, it is trivial to do so in
Clojure.
> If, however, the stigma of Java extends to libraries written in it,
even when consumed from languages like JRuby and Clojure, and people
think it's cooler to reinvent than reuse, they need a new definition
of cool.
It Kotlin it makes a lot more sense to use Java libraries, because for most purposes, the interfaces you'd write in Kotlin and the ones in Java are not all that different, other than coroutines. From Scala or Clojure, the differences in interface design are far larger. You are going from languages where mutable state is an optimization you want to hide, to libraries full of setters that return void. A land of monads, and maybe macros vs imperative programming. This makes the ergonomics of many mature java libraries just too much of a bother to use directly. There are cases where the effort to rewrite is bonkers (say, ApachePOI), and others where wrapping is sensible (see a variety of json serialization libraries which support different parsing backends, some of which will be straight java), but there are many libraries that are sensible from Kotlin, but are worse than a rewrite if you are using an FP language.
Still, I think you are undervaluing the JVM itself, which is almost magical when it comes to production observability. It'd be a whole lot of work to come anywhere near that tooling support for ops if you were avoiding the JVM. Scala, for instance, can also transpile into Javascript if you feel like it, and there's a native project that compiles to LLVM, but the JVM has the vast majority of the use cases, and it's not due to the libraries.
Yeah, I get that. Even in Kotlin there definitely a number of places where I prefer the Kotlin library to the Java, and I can see that it would happen more often in Clojure.
That said, the example in the article is the Stripe API, and I cannot see a good reason not to just use the official Java one. I've used it a ton, and it's as simple as can be—you pass a map in and get back an object. If that's a problem, either Clojure has a way worse interop story than necessary or the author is suffering from a variant of not-invented-here syndrome.
When I started out with Clojure, I was using wrappers everywhere, but after about a year or so realised that they added very little value, hurt performance, and made the code less simple. On top of that, wrapper libraries were often not complete in functionality.
The pivotal moment for me with this was when dealing with Kafka, just using the “raw” Java library ended up being so incredibly much simpler than any of the wrapper libraries.
Why does he say this? I would think the opposite and in a professional environment I've gone in the other direction of regretting not writing _more_ wrappers for external libs.
You should take Alex's words contextually, and with a grain of salt. You can easily see his commits in this project, for example: https://github.com/cognitect-labs/aws-api
Interop with Java libs is decidedly not pleasant in many cases. I haven't used Clojure before, but I've worked on services built in Scala and JRuby over the years.
There are a few challenges you run into:
1. Many libs written in Java follow the worst of Java's design patterns and idioms. Rather than calling a function and passing it some data as an argument, you instead have to instantiate a WhateverClient that itself takes a WhateverThingyStrategy instance and a WhateverConfig class instance, then call a .executeCommand method with a new IWhateverCommand anonymous class instance that implements the execute, doCatch, and doFinally methods. And of course, you can't forget whatever subclass of AbstractOrigamiWhateverResponseMarshaller you need next. Oh, and because all these instances need to be defined as beans that will be DI-friendly later, there's even more boilerplate to look forward to.
2. In comparison to languages like Scala, Java's type system is often quite lacking. You can never trust that a non-Option type is not null.
3. If the rest of your code is free-floating with structural types in some other language, you inevitably need to write a ton of glue code for adapting these structural data type objects to whatever blessed POJO interface Java expects.
All that being said, I still would prefer to use the more mature Java lib if the more native choice isn't as well maintained. But there's no denying that it's painful. The ergonomic hit is just as bad (if not more than) execing a child process to run code in another well-suported target like Rust/Go/Node/whatever that maybe has more sensible idioms. There are of course a lot of reasons why that'd be a bad idea, but still...
> The ergonomic hit is just as bad (if not more than) execing a child process to run code in another well-suported target like Rust/Go/Node/whatever that maybe has more sensible idioms. There are of course a lot of reasons why that'd be a bad idea, but still...
Come on, we both know this is false and it is only your feeling, nothing factual. How is IPC with all of its intricacies anywhere close to as ergonomic as calling one more method in the host language when all of your objects are also of said host language?
Frankly enough, creating a wrapper should not be hard at all, no matter the language. Especially not for libs that are mostly unidirectional in communication.
One problem with interop is you import the design/ergonomic considerations that may come from other languages, while neglecting what is uniquely powerful about your own language.
I think this article vastly undersells the value of Java(script) interop. The ability to call out to a well-maintained library in two of the most widely-used languages in the industry is one of the major selling points of Clojure as a pragmatic LISP, versus e.g. Racket or CL. The reason why there are so many half-baked wrappers around popular Java libraries is that it’s reasonably trivial to write one yourself on demand, so that’s what people do.
At some point, do we have to consider that the problem might be Clojure itself? Does LISP lend itself to "Rails" -- a Rails that people want to work with? I ask, genuinely, as a near-total outsider.
The comparison to Elixir got me really thinking. I appreciate your "call to action", but community consensus gathering wasn't necessary for Phoenix to emerge as an option-of-choice, it gained traction because it is _good_.
Surely there are large organizations using full stack Clojure, similar to the Lawrence World-Journal. Is there something about LISP that makes it hard for them to abstract their "framework" bits into an open source package?
It might be that simply committing strongly to a language, any language, has benefits? Years ago, a long term consulting customer hired me on a short fire-drill job. He had also hired some Clojure celebrities like Stuart Sierra and Stuart Holloway. They were incredible productive and fast. It was a very long time ago, but as far a I remember they had a small set up libraries they used. BTW, I was hired for a few hours a week to help with dev ops, not code.
EDIT: I am currently working (part time) with an all in Common Lisp company. It is really nice to see a group of people who all love a programming language using it. As much as I like virtually ALL Lisp languages, I do sometimes feel guilty not just using Python when there are much better libraries available (e.g., machine learning, linked data, etc.). When a programming language has 1000x as many developers you simply get a richer ecosystem.
> When a programming language has 1000x as many developers you simply get a richer ecosystem
Interesting comment given the article. That's the magic of Clojure being hosted, you get the rich Java ecosystem and get to use your Lisp that you love.
The downside is you still need to deal with the rich ecosystem that isn't as nice as if there was a rich one in Clojure.
The something is probably more philosophical within lisp communities. I’m relatively new to lisp (writing clojure/cl for about a year) and from what I’ve seen people prefer to bolt on small things instead of big frameworks. The full stack frameworks exist but they’re hardly frameworks. They’re closer to project templates than anything.
"community consensus gathering wasn't necessary for Phoenix to emerge as an option-of-choice, it gained traction because it is _good_"
I think it also because there's two camps of elixir devs - those who came from Ruby and those who came from Erlang. The Rubyists have a fairly easy time being productive quickly with Phoenix because it (at a glance) is very similar to Rails. From there you learn about supervisor trees, genserver, etc.
> Surely there are large organizations using full stack Clojure, similar to the Lawrence World-Journal. Is there something about LISP that makes it hard for them to abstract their "framework" bits into an open source package?
There's a fundamental model shift that's not as compatible to frameworks.
Lisp optimizes for it to be really fast to implement perfectly tailored custom solutions, with your own DSL (domain specific language) that best fit your problem. Iterations are quick, development is fast, you can automate away repetitions and ceremony trivially.
The need for scaffolding and for complicated code-gen, which is half of what most web-frameworks provide, is just not there, because Lisps are already meta-programmable.
The other thing is Clojure's functional nature. Objects and Actors and Modules, these things naturally expand to become Singleton state or behavior containers that you call upon. They also naturally lend to a plugin architecture, where configuration setups a chain of implementing interfaces called into by standard modules from the framework, etc.
The functional, higher order, immutable, and data driven nature of Clojure doesn't fit well here either.
What happens instead is that libraries, not frameworks, tend to work better in Clojure. Things you can call and use as you want, instead of things that call you and ask of very specific extension and configuration from your part.
So the Clojure web stack is still full of reusable code, they're just exposed as libraries.
When you know what to do, you can easily put together a Clojure website together, in no less time then it takes using a framework in another language, and you similarly reuse almost as much code as in any other language.
The difference is that because you need to use the libraries, you also need to figure out how to use them and where and what to do to glue all of that stuff together.
In a framework, you can't choose how to glue them all, it's forced on you, that's both the issue with frameworks, and the benefit. So when you don't know how to build a website, a framework really helps, it guides you, and you just follow its strict structure and plug what needs to be plugged, and configure what needs to be configured.
With the library approach, that's left up to you, much harder to get started with, but not any less productive ounce you know.
Finally, a framework forces everything to be a monolith, that is built and designed within the rules of the framework itself. All behavior you'd want to reuse needs to be framework aware and compatible. This means that slowly people grow an ecosystem of compatible libraries all around the framework.
Again, with the library approach, the various libraries you choose to use were all independently designed and built, they weren't built to work together, so again, you have to find how to glue and connect them and map between them yourself.
You could still have a framework, but the mental model a framework follows is often contrary to the mental model Clojure enables, people often choose Clojure because you can quickly customize things to your liking and connect various independent building blocks together in the way you prefer and that works best for you.
That means whenever someone made their code structure available to others as a framework, everyone else went, I don't like the way you did it, so nevermind, I'll just use my way.
If the libraries all only worked with their structure though, it be too much effort to go your own way, but not so in Clojure, because all the building blocks are exposed as libraries, so you can easily structure it however you prefer.
That's fair, I didn't intend to sound entitled, but "let's all decide what Rails-like to use" doesn't seem to be working for Clojurists, so I was hoping that poking at other avenues might spark some productive conversation.
I think this is just a cultural thing where the ecosystem prefers to compose things together. The Node ecosystem also hasn't centralized around a Rails. People tend to just use Express.
Also, the syslog server example doesn't seem like something a Rails would solve.
> can we please just get together at the next Conj conference decide what our "Rails" is going to be?
I think these days we, OP included, tend to use "Rails" to not just mean a monolithic framework, but also one that monopolizes the ecosystem which is one thing that made Rails good.
But since it's been tried before in the Clojure and Node ecosystems, maybe people just don't care for it.
I disagree that Clojure needs a Rails, in the sense that there's a single framework to use for all web server needs. However, I do really think Clojure needs a better documentation story for web development across the board.
Getting a ring + reitit + malli + integrant + core.async + vertx-mongo server running requires putting together a _lot_ of different pieces. A framework is one way to solve this, but so too is documentation. Perhaps it's just my Clojure mindset, but I'd be hesitant to reach for a one-stop-shop framework for all of the above, but I would definitely be interested in some docs which helped guide me hook all of them together. Is there such a thing as a documentation framework? :)
-- Thinking about how Clojure devs feel about libraries makes me realize how ironic it is that so many of them use Emacs.
> but I would definitely be interested in some docs which helped guide me hook all of them together. Is there such a thing as a documentation framework? :)
What's the first step to making those docs?
There are resources floating around, but they can be hard to find. I really like the docs for http-kit and luminous - they are cohesive.
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.
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.
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.
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.
Also relevant as a Phoenix-like alternative for Clojure: https://github.com/tatut/ripley
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.
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.
Curious, can you elaborate on what you mean by this?
I also learned that trying to second-guess why developers spend their time in certain libraries and not in other endeavors (like frameworks) comes across as pretty disrespectful and actually ignorant (considering that those people are very often more skilled/experienced than most of us).
(Good related read: Open Source Is Not About You)
So I'd recommend to anyone, open your mind, be ready to have some preconceptions changed, and contribute a significant deal to (Clojure) OSS to truly appreciate what we have. And write more interop ;)
I don't have a lot of experience with Clojure, but speaking as someone who uses Kotlin on the server side, this attitude strikes me as odd. Most of the reason to use a JVM language is to take advantage of the mature and well-maintained Java libraries for basically everything.
If interop is considered a last resort (to the point where you reach for a 3-year-old unofficial Stripe library over the officially maintained Java one), what's the point of running on the JVM at all?
> I dislike writing Java/C# as much as anyone, and Clojure is my ticket to writing much less of it, while leveraging the efforts of multitudes. As I've said in my talks, most Clojure users go from "eww, Java libs" to "ooh, Java libs", leveraging the fact there there is already a lib for almost anything they need to do. And using the lib is completely transparent, idiomatic and wrapper free. OTOH, if they want to customize their interface to a lib, it is trivial to do so in Clojure.
> If, however, the stigma of Java extends to libraries written in it, even when consumed from languages like JRuby and Clojure, and people think it's cooler to reinvent than reuse, they need a new definition of cool.
[0] https://groups.google.com/g/clojure/c/W_FTvyX6swY/m/UDhgIbkh...
Still, I think you are undervaluing the JVM itself, which is almost magical when it comes to production observability. It'd be a whole lot of work to come anywhere near that tooling support for ops if you were avoiding the JVM. Scala, for instance, can also transpile into Javascript if you feel like it, and there's a native project that compiles to LLVM, but the JVM has the vast majority of the use cases, and it's not due to the libraries.
That said, the example in the article is the Stripe API, and I cannot see a good reason not to just use the official Java one. I've used it a ton, and it's as simple as can be—you pass a map in and get back an object. If that's a problem, either Clojure has a way worse interop story than necessary or the author is suffering from a variant of not-invented-here syndrome.
I am not sure if this really answers your comment, but I really liked his comment because I tend to write wrappers and re-evaluated my habits.
The pivotal moment for me with this was when dealing with Kafka, just using the “raw” Java library ended up being so incredibly much simpler than any of the wrapper libraries.
But if Alex said that, then maybe it's not. ¯\_(ツ)_/¯
For example you hand craft a wrapper for lib-version1. lib-version2 is released but you do not need it any more. So wrapper is outdated.
I prefer recipes to call other language code (or framework) instead of wrappers.
E.g. Call a C library from Dlang instead of waiting??? for some wrapper.
Deleted Comment
There are a few challenges you run into:
1. Many libs written in Java follow the worst of Java's design patterns and idioms. Rather than calling a function and passing it some data as an argument, you instead have to instantiate a WhateverClient that itself takes a WhateverThingyStrategy instance and a WhateverConfig class instance, then call a .executeCommand method with a new IWhateverCommand anonymous class instance that implements the execute, doCatch, and doFinally methods. And of course, you can't forget whatever subclass of AbstractOrigamiWhateverResponseMarshaller you need next. Oh, and because all these instances need to be defined as beans that will be DI-friendly later, there's even more boilerplate to look forward to.
2. In comparison to languages like Scala, Java's type system is often quite lacking. You can never trust that a non-Option type is not null.
3. If the rest of your code is free-floating with structural types in some other language, you inevitably need to write a ton of glue code for adapting these structural data type objects to whatever blessed POJO interface Java expects.
All that being said, I still would prefer to use the more mature Java lib if the more native choice isn't as well maintained. But there's no denying that it's painful. The ergonomic hit is just as bad (if not more than) execing a child process to run code in another well-suported target like Rust/Go/Node/whatever that maybe has more sensible idioms. There are of course a lot of reasons why that'd be a bad idea, but still...
Come on, we both know this is false and it is only your feeling, nothing factual. How is IPC with all of its intricacies anywhere close to as ergonomic as calling one more method in the host language when all of your objects are also of said host language?
Frankly enough, creating a wrapper should not be hard at all, no matter the language. Especially not for libs that are mostly unidirectional in communication.
That stuff removes 90% of the arguments against using another language in a Java shop.
The comparison to Elixir got me really thinking. I appreciate your "call to action", but community consensus gathering wasn't necessary for Phoenix to emerge as an option-of-choice, it gained traction because it is _good_.
Surely there are large organizations using full stack Clojure, similar to the Lawrence World-Journal. Is there something about LISP that makes it hard for them to abstract their "framework" bits into an open source package?
EDIT: I am currently working (part time) with an all in Common Lisp company. It is really nice to see a group of people who all love a programming language using it. As much as I like virtually ALL Lisp languages, I do sometimes feel guilty not just using Python when there are much better libraries available (e.g., machine learning, linked data, etc.). When a programming language has 1000x as many developers you simply get a richer ecosystem.
Interesting comment given the article. That's the magic of Clojure being hosted, you get the rich Java ecosystem and get to use your Lisp that you love.
The downside is you still need to deal with the rich ecosystem that isn't as nice as if there was a rich one in Clojure.
I think it also because there's two camps of elixir devs - those who came from Ruby and those who came from Erlang. The Rubyists have a fairly easy time being productive quickly with Phoenix because it (at a glance) is very similar to Rails. From there you learn about supervisor trees, genserver, etc.
Deleted Comment
There's a fundamental model shift that's not as compatible to frameworks.
Lisp optimizes for it to be really fast to implement perfectly tailored custom solutions, with your own DSL (domain specific language) that best fit your problem. Iterations are quick, development is fast, you can automate away repetitions and ceremony trivially.
The need for scaffolding and for complicated code-gen, which is half of what most web-frameworks provide, is just not there, because Lisps are already meta-programmable.
The other thing is Clojure's functional nature. Objects and Actors and Modules, these things naturally expand to become Singleton state or behavior containers that you call upon. They also naturally lend to a plugin architecture, where configuration setups a chain of implementing interfaces called into by standard modules from the framework, etc.
The functional, higher order, immutable, and data driven nature of Clojure doesn't fit well here either.
What happens instead is that libraries, not frameworks, tend to work better in Clojure. Things you can call and use as you want, instead of things that call you and ask of very specific extension and configuration from your part.
So the Clojure web stack is still full of reusable code, they're just exposed as libraries.
When you know what to do, you can easily put together a Clojure website together, in no less time then it takes using a framework in another language, and you similarly reuse almost as much code as in any other language.
The difference is that because you need to use the libraries, you also need to figure out how to use them and where and what to do to glue all of that stuff together.
In a framework, you can't choose how to glue them all, it's forced on you, that's both the issue with frameworks, and the benefit. So when you don't know how to build a website, a framework really helps, it guides you, and you just follow its strict structure and plug what needs to be plugged, and configure what needs to be configured.
With the library approach, that's left up to you, much harder to get started with, but not any less productive ounce you know.
Finally, a framework forces everything to be a monolith, that is built and designed within the rules of the framework itself. All behavior you'd want to reuse needs to be framework aware and compatible. This means that slowly people grow an ecosystem of compatible libraries all around the framework.
Again, with the library approach, the various libraries you choose to use were all independently designed and built, they weren't built to work together, so again, you have to find how to glue and connect them and map between them yourself.
You could still have a framework, but the mental model a framework follows is often contrary to the mental model Clojure enables, people often choose Clojure because you can quickly customize things to your liking and connect various independent building blocks together in the way you prefer and that works best for you.
That means whenever someone made their code structure available to others as a framework, everyone else went, I don't like the way you did it, so nevermind, I'll just use my way.
If the libraries all only worked with their structure though, it be too much effort to go your own way, but not so in Clojure, because all the building blocks are exposed as libraries, so you can easily structure it however you prefer.
No. I don't know what else to tell you.
Also, the syslog server example doesn't seem like something a Rails would solve.
> can we please just get together at the next Conj conference decide what our "Rails" is going to be?
I think these days we, OP included, tend to use "Rails" to not just mean a monolithic framework, but also one that monopolizes the ecosystem which is one thing that made Rails good.
But since it's been tried before in the Clojure and Node ecosystems, maybe people just don't care for it.
Getting a ring + reitit + malli + integrant + core.async + vertx-mongo server running requires putting together a _lot_ of different pieces. A framework is one way to solve this, but so too is documentation. Perhaps it's just my Clojure mindset, but I'd be hesitant to reach for a one-stop-shop framework for all of the above, but I would definitely be interested in some docs which helped guide me hook all of them together. Is there such a thing as a documentation framework? :)
-- Thinking about how Clojure devs feel about libraries makes me realize how ironic it is that so many of them use Emacs.
Yogthos put together this guide - in book format:
https://pragprog.com/titles/dswdcloj3/web-development-with-c...
-
Additional links:
https://yogthos.net/posts/2022-01-08-IntroducingKit.html
https://kit-clj.github.io/
https://luminusweb.com/
What's the first step to making those docs?
There are resources floating around, but they can be hard to find. I really like the docs for http-kit and luminous - they are cohesive.