If you're really lucky, someone will have thrown in a bunch of 'specs' that make a bunch of assertions about the data, put them on the API entry points, and then scattered some slightly different specs with slightly more restrictive assertions on various 'internal APIs', resulting in random explosions in production!
And the joy of working with an esoteric language is that it attracts esoteric developers, who often get frustrated by the requirements of being a software engineer in a large company (i.e. everything that's not writing code), which leads to the aforementioned 100% dev churn (after a lot of shouting).
There are plenty of ways to mitigate the problems the author describes. A few of these things would be having coding standards to ensure that code is written in a way everyone is comfortable with. This also covers things like adding schemas and documentation for maintainability. Doing pairing and code reviews so that multiple developers are familiar with different parts of the codebase. Having good tests so that you can have confidence that the code does what's intended when you make changes.
I'm also not sure what makes Clojure esoteric. It's a clean and well designed language that embodies good principles. It's a niche language, but far from being esoteric. I've been using Clojure for over a decade now, and I've seen the opposite of developer churn. Most people are pretty happy to stay at a company using Clojure. The fact that there is high churn is suggestive of a toxic environment that drives people away.
Finally, here's [1] a talk from a founder of a Clojure startup that grew into a large successful company. Clojure didn't get in the way of that.
For example, Emacs has a massive amount of Elisp. Elisp is much more primitive than Clojure, and traditionally libraries don't use e.g. data schemas [1] as runtime contracts for data.
Obviously, once a system built on top of a dynamic language grows beyond certain threshold, you need to be very disciplined as there are no static types to ensure some degree of correctness.
With that said, it would be interesting to have a language from the ML family as a viable contender. Perhaps a modernized version of Standard ML. Or perhaps OCaml, if it gains some traction with multicore and algebraic effects.
F# is nice, but it's a bit of a watered down version of SML due to the lack of functors. Scala is too complex and far from ML in some regards. Haskell is good, but lacks critical developer mass and some libraries / laziness overcomplicate certain usecases.
In Lisp, function names describe actions. In OO, classes, inheritance, static properties, and getters and setters give at-a-glance hints as to the shape of the application's data model. In Clojure, we compensate, as you pointed out, with forms of documentation. I'll take that trade-off any day—I never want to go back to classes! But it's perhaps one reason for which Clojure has a reputation of being hard to read by other devs.
And many times purveyors of a bad tool blame the workman.
But I absolutely hate maintaining an old Clojure codebase (unless it's tiny).
The REPL helps a lot with discovering what the proper way is to call any random function you have in your code, but this is still really super annoying. I really hate to get into a dynamic-versus-static-typing debate, but I've long since come to the conclusion that -- all other things being equal (hah!) -- if I have to dig into a large and old project, I'd much rather have types by my side than not. Code will not ever be adequately documented or commented (and even if it _seems_ to be at first glance, you will always have nagging doubts about how up to date that info really is). This is where type definitions help to figure out the shape of the data that any piece of code is working with. People talk about adding spec/schema definitions but that doesn't solve all the problems with not having type definitions unless you add these spec/schema definitions _everywhere_ ... and let's face it, you just aren't going to do that in any Clojure project. So, best case scenario is you still have a large collection of functions in your project that are calling each other, etc that you are left having to deduce yourself what this random map or list actually contains.
However, I find myself running Ruby/Rails (console) in debug mode in RubyMine (Jetbrains IDE). The REPL-like experience seems quite close to that of Clojure, with the added benefit of being able to easily enable and disable breakpoints and see my local data (and snapshots of all previous local data up the call stack).
And honestly, the Clojure thing that always stops me from actually getting a full anything built is the lack of frameworks and approaches which have critical mass. It's always the same answer, "We like to choose our own libraries." That's lovely once you know what you're doing, but the ramp-up time is just SO much slower than with other languages.
Considering the time to working proof of concept is critical quite often, few beginners have time to figure out all the libraries and tooling and integrations to build something in Clojure.
I think despite still wishing I had a Clojure backend with Clojurescript/React frontend, I'll step from my Rails PoC to a Phoenix/Elixir product and be successful and happy (and have a lot of people doing something similar, with similar tools and libraries).
However, I do think that it harder to keep a large code base understandable when using a dynamic language v.s. a statically typed language.
Having problems with understanding the shape of expected data is certainly a problem experienced in larger Clojure code bases, I guess this is just a disadvantage of using Clojure.
Documentation, tests, spec/schema and good naming conventions can mitigate this disadvantage to some extent.
I found some the advice in this blog post useful: https://tech.redplanetlabs.com/2021/06/03/tour-of-our-250k-l...
everybody hates their language when they have 100k LOC of tech debt from 8 years ago
You're right that Clojure's sequence soup problem is painful at that scale (really any scale) but have you ever debugged Java? It's barely even possible, the project needs to drive $10M+/yr revenue to just not collapse once it reaches 500k+ LOC Java, 500k XML, 300k SQL ...
hard disagree ... Java is a dream to debug. I've hacked into complex applications countless times by remote attaching the debugger and setting breakpoints to step through what they are doing. You don't even need source code in many cases. I'd pick Java ahead of any other language on that front.
And let's be frank, XML, other than for Maven (where it can make sense), is not really a thing in modern Java.
- dev churn is just a fact of life in this industry
- I'd love to know which language stops you from having 100k LOC codebase that nobody understands! Certainly not C#, typescript, Java...
- "esoteric developers" - that's a bit glass half empty! In my experience people who have taken the time to learn functional programming or any non top-10 language are usually pretty smart and motivated.
Clojure, in the hands of someone that knows this, works wonders. It gives your team 10x productivity, safer more correct code, that's simple to extend and grow over time, keeping your velocity high and your tech dept low.
But if you don't know how to leverage it's strengths, what best practices to follow, you can end up in a mess like that.
And this is true of all languages honestly. I've seen this for C++, Java, JavaScript, C#, Scala, all kind of code bases that suffered this same fate, with 100% team attrition, and all kind of other issues.
I say this from first hand experience, 6 years on a team that transitioned to Clojure, in that time the team rotated fully twice, during the pandemic it had 100% attrition, even I left (working on another team), but all the new developers, even though they have zero Clojure experience, had no issue understand the code base and start making improvements and building new features, velocity saw no impact whatsoever. You get the usual some of them would rather it be something their more familiar with, others are loving it, some don't care either way. But no complaints about the code base itself, no talks of spaghetti code, or challenges to debug anything, or understand what's going on.
Basically don't expect Clojure to save you from yourself, it's an asset when you know what you're doing, not a safeguard when you don't.
Startups that act too much like big companies just don't ever get product out the door and fail before you can bitch about technical debt...
And to the article's title, "building a startup on Clojure," you're better off building a startup on a customer base.
This is a big problem with Dynamic languages. If you are new to the codebase, you have no idea of what the shape of the data is, what to expect etc.
Wow. Pretty insightful :)
When I did my last startup we switched from a Python API to Node for this reason. Python is a great language but there are no devs available where I live. I can't even imagine considering Clojure unless I was in a major tech hub.
The move to remote work is probably going to be a massive benefit to building in less mainstream languages.
Yes, definitely in growth periods you get the best developers migrating to it. I'd say Rust is like this now. The problem is a few years time they'll move on to the next big thing leaving you stuck. I'd think Clojure is in this spot right now.
Clojure is... esoteric now? I would understand if we were talking about, I don't know, INTERCAL. But Clojure? Is Scala 'esoteric' too?
> Python is a great language but there are no devs available where I live.
Ah, I see. Yeah, by that measure Clojure will be esoteric indeed. Python developers being rare is very surprising.
Yes, remote work for sure is an edge when hiring!
Also reminds me of the essay "The Python Paradox" by Paul Graham (http://www.paulgraham.com/pypar.html)
Wow. Where on Earth do you live? Real question, not being sarcastic.
Presumably not the US. I've found Python developers even in some fairly small towns (approx 25K people).
Focusing only on web stuff.. If you have a good grasp of design patterns and you can build out your system in a modular way, I think node is a great starting point.
I love starting with node because typescript is awesome, the performance is nice, the community support is tremendous, the scaling is easy, and finally it’s easy to move off it. If some part of the system starts becoming a bottleneck, just swap that piece out for something more suitable. One thing I like about this time right now is that most things are built just fine to be used in creating something new and useful products.
Getting to the point where you're writing good Python and taking advantage of what the language provides, knowing the ecosystem, and building things that other Python devs won't look at and think "Wtf?" takes much longer than weeks.
Then the library ecosystem is probably good for a lifetime.
If only there was a worldwide information technology network allowing people to work together remotely.
If you're wondering what's so great about the Clojure repl (and other lisp repls) in particular, the thing is that you never have to actually type something into it. You can run evaluations from the code file itself. The structure of lisps makes it clear exactly which code you want to evaluate. To do this, I use the excellent CIDER package for emacs. I understand Calva for VS Code and Cursive for IntellJ offer similar functionality.
Here's a good talk on what this looks like:
I have been working with ClojureScript (re-frame and reagent) on front-end stuff and, unfortunately, the REPL does not seem to help me that much on my workflow. I miss the REPL driven development, by the way... The real "interactive programming" seems to happen on Chrome Dev Tools + Browser's reactions to Chrome Dev Tools tweaks on the UI + (lastly) changes on the source code via the editor (Emacs in my case).
Namespaces as prefix of invocations on the REPL are not that trustworthy on ClojureScript, apparently. It could also be that I am a noob and I missed something, so... How do you feel about ClojureScript?
For view code I think hot reloading has been a great thing with Clojure/Script too. Everything is reloaded properly and the state remains.
I know that the setup for cljs is a bit more involved and things will break sometimes (putting a browser in the loop will do that). I have dev tools open ... but I use it less and less, between hot-reloading and a data browser (portal or reveal) hooked up to the clojurescript repl I only use dev-tools stuff occasionally (the network tab is still very important of course).
It does sound like you are missing something, I'd try out one of the shadow-cljs example projects or walkthroughs to see what an example setup includes as features to see what you might be missing.
[0]: https://figwheel.org
In the same way that most languages have lambdas, it's very different from being able to trivially compose functions into new functions. (This one I can't even describe well, but if you try and write SICP exercises in a lisp vs. python, the difference is obvious.
After six years, I would absolutely (without hesitation) start another business with Clojure as the core.
Together with ClojureScript it's one of very few solutions for writing server/browser apps with shared code, which enables interesting economies.
If I were to start a new company I'd absolutely run it on clojure. Even without frontend/backend code reuse, REPL-driven dev---paredit is the killer app for me. It just makes editing text files, which is what we're doing if we admit it, so much easier.
It's a data point.
As far as the code goes, they wrote a custom DB that is O(nm) when counting tables---that is, it must count every record in the DB to count how many tables there are.
(Incidentally, I had forgotten this the other day and tried to do a "quick" table count...oops!)
I don't know Elixir or TS well enough to say if we have Ex/ts problems---from what I can tell:
- Elixir seems alright, I'd love to learn what the BEAM magic I keep hearing about is
- however, syntactically I find it pretty garbage, or at least uninspired. (Note that I am a spoiled Clojure guy and have this reaction to Python, Ruby, etc. I acknowledge people can get productive work done in them.)
- TS I have ha-ha-kinda-seriously trauma about from a previous job. I'm not a good person to ask here b/c I'm pretty firmly pro-dynamic in the Type wars. I will say that it is pretty freaking great to be able to have an emacs buffer open w/a repl to the cljs frontend we have for other apps, and that I really miss it whenever I have to go through the ts code.
> Any sufficiently complicated TypeScript or Java program contains an ad hoc,
> informally-specified, bug-ridden, slow implementation of half of Clojure.
Once you grokk the approach and workflow Clojure takes in solving problems, the distance between having an idea and writing a rock solid implementation of that idea is the shortest I've experienced in my ~20 years of programming.If you want to write succinct, transparent code whilst minimizing the future potential of introducing bugs, Clojure is as good as it gets.
> Any sufficiently complicated Clojure program contains an ad hoc, > informally-specified, bug-ridden, slow implementation of half of Spring.
Keep in mind that they have to juggle between almost four different languages, Java, Javascript, Clojure and Clojurescript, almost because there are differences between Clojure and Clojurescript. Instead of for example just using one language: JS.
ClojureScript is one of the main reasons why Clojure makes sense in my business. I can use the same language and share the same business logic code between the server and the browser app. That's huge!
Also, I avoid a load of problems related to communication and serialization, because the native serialization format is EDN, e.g. Clojure data structures. There is no need to adapt your data structures to the limitations of, say, JSON.
Also, what are the limitations of JSON that EDN handles better?
Conversely, you can also get to the end of your roadmap quickly (Clojure being great) and end up overstaffed.
There's a different line to walk with languages like Clojure.
Source: I walked this line.
Most engineers we hired has no prior experience but learned quickly. It gave us a great advantage to hire the best.
I think this is the key here. Clojure developers are expensive (see the Stack Overflow charts for how being a Clojure dev essentially guarantees a great salary) — but that's not because of them being Clojure developers, but rather because of them being more experienced, knowledgeable, and flexible than your "average" developer.
If you start a business and use Clojure, you should expect to hire more expensive developers. You will, however, need fewer of them, so this might all balance out in the end, especially as we all know that teams don't scale infinitely.
Dynamic typing and the lack of a formal compilation step are great for productivity, but they come at a cost. You need a proper CI pipeline to run linters (granted, you need that in statically typed languages too) and, most importantly, you need to write tests. Sure, you need to write tests for any language, but not having them for languages like Python is going to bite you that much harder.
I've seen pretty large Python codebases that worked just fine. And smaller Java codebases that were unmaintainable.
Full disclojure: I work for the company in the talk, though I'm not one of the presenters.
I use leiningen, too. I tried other approaches, but had trouble getting them to do everything that I need (for example, AOT compilation of the entire code that goes into the final .jar), and I couldn't really see any massive advantages.
I usually default to leiningen: I can't be arsed to spend time configuring deps to do what lein does out of the box. (For example: building an uberjar)
In addition i have to say, that a lot of libraries are falling into clj-commons because the original developers no longer works on the project, other like compojure, that is mentioned in the blog post last stable release is from 2016 and version 2 is in alpha since then.
I am curious why are you using c3p0 on 2022 when hikaricp is being maintained, and last release of c3p0 is from 2019. Also no support for R2DBC.
My impression is that in the last 2 years, the ecosystem has shrink, less talks, less new libraries, new libraries that are no longer maintained.
Others problems arise is that Clojure lag a bit with compatibility with new Java features, still i think Clojure cannot pass Clojure functions as parameter to Java functions. It results in awkwardly having to reify Java function interface to pass function when using a Java library. No conversion from Java 8 CompletableFuture to clojure async primitives in 2022. And i think they not going to support it in the near future.
What i am saying is that Java is in the future, and Clojure is in the past. They just cannot catch with new Java features and i doubt they are going to support it ever. You can still run it on modern jvm because they update the bytecode but that is all.
Ouch, Java 8 was released in 2014. To be fair, Clojure was never a community project though.
- Tons of developers know it - Tons of Java developers can be made to know it with ease - A good default IDE experience within VS and VSCode, and a JetBrains product if you prefer it. - A good LSP implementation with OmniSharp if you don't want to use an IDE. - ASP.NET, a good default Web framework. - NuGet as a package manager with tens of thousands of packages. - Better than java reflection and runtime generics. - Cross-platform CLI tooling since .NET Core, now it's just .NET. - Ability to deploy self-contained applications. - Mono version of C# is used for making games. - A continuously evolving cohesive language with minimal competitors (like Groovy, Kotlin, Scala, Clojure, etc... on the JVM) - F# if you want a stricter functional language that interoperates with C# seamlessly. - PowerShell as a way of interactively running any .NET assembly, regardless of how it was compiled.
And many more... C# is one language you can build a career on and also use for hobbying and have fun.
The haters will complain that MSBuild (the default build system) and Visual Studio suck. If you've tried them in the past, you're probably right. Try them again in 2022 and see if your opinion doesn't change.
I do want to branch into F# and FP but i didnt want to miss on the C# train so i tried it and it blew my mind how well the language has been designed (i mean at C# 10, .NET 6). They even made the Java-esque boilerplate thingies become automated so the code reads and feels almost like a better version of Javascript.
I am a new programmer (with only Intermediate Python and tid bits of CS under my belt) but i think choosing C# for a language made sense because of all the things you mentioned, and it also helps that it is aesthetically very beautiful, and worlds apart from C and C++ in many respects.
- you have to
- skip a line
- between each bullet
- item
Clojure has pitfalls for sure, but no need to be dishonest in order to flag them.
That said I would love to work in a lisp full time. There's just something appealingly elegant about it.
There's one framework that looks promising to build fully dynamic apps in pure CL with one code base (websockets inside). It provides a GUI-like experience to build all kind of apps (a website, a chat, the snake game…): https://github.com/rabbibotton/clog/
I am using Hunchentoot, a routing library on top (easy-routes), the Mito ORM, and for the client side I am conservative: HTML templates with Djula, interactivity with HTMX, Vue if required, JS.
The great thing is that I can build a standalone binary of my web app, including the static assets, the webserver, the lisp compiler and debugger… for ±28MB unzipped and instantaneous startup times.
https://lispcookbook.github.io/cl-cookbook/web.html
https://github.com/CodyReichert/awesome-cl#web-frameworks
https://lisp-journey.gitlab.io/blog/lisp-for-the-web-deploy-...
I use cl-who[1] for generating html and parenscript for javascript. I use clack on the backend, but hunchentoot is probably more popular. Both backends have plenty of routing libraries available (hunchentoot comes with a decent one baked in, clack does not).
postmodern is a Postgres specific sql backend that is great. There are database-agnostic SQL libraries as well (clsql and cl-dbi I believe are the two big ones) but I haven't tried them.
1: People whose opinions I trust have told me that spinneret is a better choice. It did not exist when I learned cl-who. cl-who is "good enough" for me that I haven't switched.
Example apps I can think of:
Screenshot bot: https://github.com/screenshotbot/screenshotbot-oss
Webcheckout: https://webcheckout.net/ (they were hiring recently)
Math Pastebin: https://github.com/susam/mathb
Ultralisp: https://ultralisp.org/ (built with their Weblocks refactoring)
A programmable desktop and bookmark application with CLOG (TEASER) https://www.reddit.com/gallery/w4rj4k (https://codeberg.org/mmontone/mold-desktop/)
so, yeah. while i'm excited with lisp, i don't think i have the gut to start my own shop with clojure as the main language.