5/20/2025 at 1:15:52 PM
The ongoing discussion for Biff [1] prompted me to re-share my post because I'd like more people to understand this "other way". Outside Clojureville, it is not obvious most of these Clojure "frameworks" are not monoliths.The consummate Clojurist's default (and very normal-feeling way) to build a web application (or any application for that matter) is to roll their own web stack from production-grade libraries.
Of course, this state of affairs is a double-edged sword, just like is true for traditional web frameworks. In my post, I try to go into the whys and the wherefores, building upward from first principles.
[1] Biff – a batteries-included web framework for Clojure https://news.ycombinator.com/item?id=44037426
by adityaathalye
5/20/2025 at 1:23:01 PM
A fantastic post! Enjoyed re-reading it.I'd say the nice thing with the Clojure way of building your own stack is it becomes quite easy to swap parts out. On a previous project we swapped out our web server three different times with minimal changes (jetty -> aleph -> httpkit) as for the most part they all shared the same interface.
After a while you get good at seeing where you want things to be configurable and where you don't. It also gives you the confidence to roll your own micro stack/framework which means you are not dependent on third party aggregates to adopt new features.
by andersmurphy
5/20/2025 at 3:52:32 PM
Thank you for the kind appreciation. Made my day :)Yes; next to the sheer stability of parts, their fungibility is a business-critical feature of the Clojure ecosystem. Of course said fungibility does not magically manifest. However the effort to get there is "not much", I'd say. The use of "system" libraries, with some well-reasoned module design brings it pretty close to magic.
As in the post, a fungible, production-grade part can be just a multimethod (e.g. the router in the post). Why? Because "production" comes in all sizes. A small SaaS with a few hundred customers may chug along happily with a bunch of functions.
by adityaathalye
5/21/2025 at 5:57:11 AM
This suggests to me that “production grade” isn’t much of a qualifier at all then.You could just as well say that PHP has “production grade” functions.
by yakshaving_jgt
5/21/2025 at 7:03:25 AM
Hm, I'm saying a given function can be production grade. I'm not saying all functions are production-grade. Also, I'm saying production comes in all sizes. If your micro-SaaS app gives you a livelihood, that's hella production --- real skin in game, real stakes in ground.To analogise further...
- HackerNews is a "production" system, you would agree. Back in 2015, it was still true. Are flat files a "production grade" primary data storage choice? [1]
- Suppose your production service transacts a million requests an hour (say it is a short-link maker). Further, let's say it has only a handful of API endpoints. Do you really need a whole routing library for that, if a single multimethod does exactly what you need, correctly?
etc...
[1] https://news.ycombinator.com/item?id=9990630
(edit: add reference for flat file storage)
by adityaathalye
5/21/2025 at 7:16:05 AM
Right. And what I’m saying is that if “production grade” means all of these things, then it’s not a very meaningful qualifier.My personal site is statically generated — it’s just a bunch of HTML files and some CSS. Do you not think it would be a bit pretentious of me to describe that as “production grade”?
If “production grade” simply means fit for purpose, then given the GP commenter’s reason for their initial web server swap, wouldn’t you say by definition that jetty is not production grade, since it doesn’t (didn’t?) support SSE?
by yakshaving_jgt
5/21/2025 at 7:31:31 AM
I agree with you... "production grade" is in fact a meaningless term without saying what grade one's production needs to be.A static site that serves is most definitely a production system. Perhaps one that could scale in traffic almost without end.
evalapply.org gets (to my continued amazement) 20K+ unique visitors a month when it's business as usual. On a busy HN day, it's easily that much in hours. I don't have to think about "scaling problems". I don't have one.
I'm being the realest real with you.
by adityaathalye
5/21/2025 at 5:55:20 AM
> On a previous project we swapped out our web server three different timesWhy is this desirable?
On all my projects over the past 10 years, I’ve swapped out the web server exactly zero times because the one I have works just fine. The parent comment describes these components as “production grade”, but then if that’s the case, what could be the reason for swapping them out other than self-indulgence?
by yakshaving_jgt
5/21/2025 at 7:15:46 AM
> Why is this desirable?Generally, yes one would not want to swap out their web server willy-nilly...
Yet, this is one of those "YAGNI in 99% of your use cases", but when that 1% use case arises, a server swap would be far more desirable than a whole framework shift.
So while self-indulgence can certainly be a motive (and why not? as long as everyone's having a good time), may I offer a few more charitable reasons for this:
- programming API ergonomics
- performance
- application runtime model (servlets -> embedded server)
- security model
- application server features (websockets, comet?)
- binary size
- server configuration niceties
etc...
That said, a developer only has flexibility if it is built in from the get go.
A counterfactual would be to consider the set of developers who have had to put in ugly hacks because they can't just rip the web server out of the framework of choice they are locked into.
(edit: bullet list formatting)
by adityaathalye
5/21/2025 at 7:17:57 AM
> and why not?Because I pay the people who work for me.
by yakshaving_jgt
5/21/2025 at 7:33:18 AM
Well, if you're paying, you certainly get to set the rules. No self-indulgence, then. The other reasons I enumerated may still hold.by adityaathalye
5/21/2025 at 7:14:01 AM
It's not. But, the fact that we could and it was straight forward still amazes me.In our case the first time we needed to, we needed SSE and at the time there was no ring-jetty async interface (it's a long time ago so I'm forgetting the details) so we moved to aleph. Much later, we wanted to try out http-kit (self-indulgence) as we were operating behind a proxy anyway for performance reasons and it made a significant difference.
If we'd just started with http-kit that would have been fine. I guess it comes down to what features you need.
Also I 100% agree it's something ideally you would want to avoid a in the case of databases for example so much performance is left on the table because for some reason we want to be able to swap between SQLite, postgres and mySQL. Which in practice you never want to do.
by andersmurphy
5/21/2025 at 8:21:09 AM
As the former maintainer of Aleph, I'm very surprised you ran into a situation where http-kit was faster. Or do you mean it was just preferable to develop for?by KingMob
5/22/2025 at 4:23:34 PM
> Why is this desirable?Because Brawndo's got electrolytes.
by 0x1ceb00da
5/21/2025 at 9:03:04 AM
Your comment reminded me of this talk https://www.youtube.com/watch?v=MZy-SNswH2E.The part about building just the functionality you need, using the bare minimum libraries etc stuck out.
by gehrman