
Ask HN: Who is using Clojure in production, and would you do it again? - christophilus
This has been asked before, but it&#x27;s been a while. I&#x27;m picking it up, and am curious to hear from people with experience. What are you using it for? What do you like and&#x2F;or dislike? Would you use it again? If not, what would you use instead?
======
pbiggar
CircleCI uses it - it's great. The upsides are:

\- the great concurrency model

\- the REPL

\- being able to edit with Paredit,

\- it's a great language

\- It's also amazing for hiring devs: there is a niche pool of devs who want
to use clojure, and it's easy to hire them since demand for them is low. (Vs
the thousands of Rails companies who are competing for a much larger pool)

\- being able to use clojurescript, in particular using Om (we use a pattern
which is similar to the Elm Architecture, and it's great for writing frontends
with).

The downsides are: \- mostly related to Java. Startup time is shitty (which is
why you use the REPL a lot).

\- Libraries are often unmaintained (though often it doesn't matter, since
they are typically very composable and don't need changing).

\- The web framework story is poor too - it's not nearly as advanced as the
rails and nodejs worlds - you have to compose different libraries which is
sometimes good and sometimes bad.

\- Finally, Rails encourages good web-app best practices: you can only really
scale Rails horizontally, so you start with queues and horizontal scaling and
workers. With Clojure, it's tempting to run things in threads and pools since
it's so easy to do. But it scales poorly, and leads to concurrency bugs you
wouldn't get in the Rails world.

~~~
chebum
@pbiggar Hi, Paul! Could you elaborate on poor scaling and concurrency bugs,
please? From my understanding Closure's functional nature and immutability
should minimize concurrency bugs.

~~~
pbiggar
Suppose you have a background job you want to run. Clojure has good
concurrency, so it's tempting to just run it in the background. OK, now it
needs to retry: that's great, Clojure has STM so it'll keep retrying until it
succeeds. So you have your process spin off a bunch of threads doing some
background stuff. Easy.

Now, because you're using AWS, or a new deploy, or something else, the server
dies. What happened all that stuff running in the background? Because it was
built with clojure primitives, it never got saved anywhere, like it would if
you had used a queue and workers.

The summary is: Clojure's awesome stuff encourages you to use it, but it's
actually a bad pattern for horizontally scalable apps. Rails - lacking the
cool concurrency stuff - forces you to have better habits, and makes them
easy.

------
ljosa
We use Clojure extensively at Yieldbot. The entire data-science side of the
house is Clojure. That includes Spark jobs that computes forecasts and
estimates click-through rates and a number of Storm topologies that crawl our
publishers' websites and analyze the contents of the pages (so we can use them
as part of the signal for the user's intent and find ads that match). It's
been very powerful to use the same language for experimentation/research and
production; sorenmacbeth talks about that a bit in his Clojure/West talk:
[https://www.youtube.com/watch?v=omSTAwSjYc8](https://www.youtube.com/watch?v=omSTAwSjYc8)

We also use Clojure for the "matcher," which is a webserver that receives a
request every time someone visits one of our publishers' websites. The matcher
must decide very quickly which ads are relevant and decide which one to show.
There is some online machine learning involved. Porting this latency-sensitive
service to Clojure (from Python) has been great: the Clojure version is much
more performant, it is easier to change, scale, and monitor, and it fails more
gracefully.

Our data pipeline moves events for pageviews, ad impressions, clicks, etc.
through kafka queues between AWS regions, archives them, and indexes them into
ES. It's all Clojure.

Finally, we use Clojure and Datomic for the database where campaigns,
creatives, etc., are configured.

Oh, and we're hiring.

------
CRUDmeariver
I use it at work. I am also a relative novice programmer (~2 years exp) so
take what I say with a grain of salt.

Pros

\- Dependency management is so easy and portable.

\- I can write really concise code while keeping it readable (and dare I say
aesthetically pleasing) with ParEdit. Compare this to Scala which tempts you
to write gnarly and dense one liners. In clojure these are so unreadable that
you feed compelled to indent them properly.

\- Clojure feels like playing with Legos. Each individual piece is small and
easy to understand, and it's easy to build something bigger by stacking them
together.

\- I have never once missed OOP

Cons

\- ClojureScript is cool but for a production app I would rather not use it.
Not enough availability of libraries and JS interop is not intuitive. When I'm
debugging CLJS, half the time the stack trace is unreadable transpiled JS

\- Proto Repl (atom plugin) does not consistently work right for me. I still
have not found a good REPL workflow so I am frequently restarting REPLs which
is just sad.

------
puredanger
Not a full answer, but see below a list of companies using Clojure and
ClojureScript:
[http://clojure.org/community/companies](http://clojure.org/community/companies)

~~~
christophilus
Yeah. I'd seen that. I'm more curious about what people love/hate about it
after using it, and what surprises they found (e.g. "We used Clojure in
production, and here's a brief retrospective.") Thanks!

------
kbuchanan
Running a quick `cloc` on my company's codebase shows we have about 40,000
lines of production Clojure code. Most of it supports a couple or three web
apps.

For me, deploying production Clojure has been fantastic. Is it a panacea? No,
definitely not. If you like typing, stay clear. Spec is cool. Very cool. But
it's not static typing. And, if thinking in s-expressions doesn't come natural
within a reasonable amount of time, consider Elixir instead.

I do, however, prefer dynamic languages, and I frankly LOVE LISP, so it suits
me. The JVM has never been a hindrance; in fact, I appreciate the comfort of
knowing there's a deep ecosystem of Java that can be tapped, which I have
(easily!), in extreme situations like PDF manipulation, or whatever.

Clojure also meets its performance claims – it's fast. My company doesn't
carry behemoth level request loads, so I can hardly provide impressive
metrics, but decently considered code will execute plenty fast with room to
spare. Although we're light users, Clojure's concurrency features are nice
too. For most async stuff, forget background job processes – use futures.
core.async is cool, but overkill for most web stuff. We've built a bare-
minimum job processor for must-finish tasks, but that got done in about 100
lines of code.

My major piece of advice, if you plan to use Clojure for the web, is to get
comfortable building custom homes for your web apps. Not in the sense that
you'll HTTP stuff from scratch – no, there are _excellent_ libraries for all
of the critical stuff. Redis, AMQP, ORMs and SQL libraries of all flavors,
caching, routers – everything you'd want for the web is there.

Just be mindful of the fact that your web app will look nothing like your
neighbor's. There are NO integrated web frameworks. Not successful ones, at
least.

And, I think, for good reason. Clojure is not the average Clojure developer's
first language. There was a significant influx of Rails devs several years
ago. Clojure is bereft of black magic. A lot of Clojure libraries are so
small, and so sharp, you can easily unearth their features by reading a few
source files. Which, of course, is good and bad. The side effect, being, very
little of the documentation in the community is geared towards beginner
programmers. Starting out, my single biggest frustration in the Clojure
community was the _knowledge library authors assumed you brought_ to the
library.

I'd compare the ecosystem – loosely – to NPM's, but without the cruft. You
build your web app up from small components (Component and Mount are
awesome!... eh, except for the fact that they are, as are so many Clojure
things, original material that takes time to digest...) that easily fit
together. It's a breath of fresh air knowing almost all libraries live in
harmony.

So, the backend Clojure story, in my view, is great – if you don't mind being
on your own once in a while.

The front-end story, however... well, is a mixed bag, I think. Yes,
ClojureScript is making huge strides in being futuristic and compiling to
negative kilobytes an' all. But some of its highest profile projects are sadly
proving impenetrable. Om and Om.Next are total non-starters for small to mid-
sized projects (YMMV) as their documentation is so beyond comprehensible. I
_have_ made a real project in Om.Next – with tremendous effort – but I've been
developing in Clojure for nearly five years. And, when you can't remember how
something works a day after you wrote it... that's trouble.

If you want Clojure for the front-end (which we've dabbled in to a degree, but
for our company, the return on beginner Javascript developers in React is
still satisfyingly high), I'd recommend Reagent. Keep it simple.

Back to Clojure proper, one thing I enjoy immensely is seeing how far I can
take a program in a single file. Not always practical, but it's fun knowing
you can scan a file (often starting at the bottom) and quickly grok it. Do
know, however, reading Clojure (or any LISP, that is) is sometimes harder than
writing it, especially in a large codebase. It's here, I think, where
statically typed languages have an edge on Clojure – refactoring is more
dangerous: you can never fully tell the shape of data passing between
functions.

Spec has helped, for sure. For simple, obvious tasks, take a risk. On mission-
critical-can't-break-type stuff, however, you'll be grateful for spec. No,
it's not the anxiety-free experience you hear about in Elm or Haskell, but
geez, at least you can get fresh code working _fast_. It's here where I
continue to believe dynamic languages like Clojure have a permanent place in
history – solving problems iteratively, with little pomp and ceremony, without
knowing the end from the beginning. And saying to yourself, "Yes, this works,
and while not perfect, I made it quickly, and it's extensible and
maintainable."

The most beautiful thing about writing a production app in Clojure is this:
you can build a big app from tinier programs. I don't mean microservices. I
mean small, easily divisible namespaces in a single project that talk to each
other via messages. Like, really, you can easily treat separate namespaces as
if they're different actors in a plug and play network.

A talk I heard recently (can't remember where) suggested writing your big
program from small programs, small enough that any individual program can be
rewritten in a week. Clojure does this for us. When I started out, being
unfamiliar with functional paradigms in general, I brought a lot of tightly
coupled OO practices that I had to unlearn. Unfortunately, "real world"
Clojure tutorials are scarcer than they ought to be. But, unlike in my Ruby
and Java days, there are _very few_ things that need to be completely
rewritten in Clojure. The core language is simple enough that almost all
Clojure code resembles itself.

~~~
christophilus
Thanks for the write up! Great tips, especially around ClojureScript. I
haven't even started to look into that ecosystem.

------
dizzystar
I've used it in a few projects years back, haven't used it in a while, then
came back to it recently. The difference is night and day, to say the least,
and that "day" is much brighter than it ever was before.

Back then, you did lein new compojure app then you had to figure out what to
change in your handler file to get the thing up and running. Today, build,
run, and everything just works.

Security has seen a massive improvement, ring comes with CRSF by default, and
the libraries have improved dramatically. The Bedra talk was on point, but no
longer as relevant.

A constant is the few libraries, and I'm pleased to see that they have been
relatively stable. This could be seen as a good or a bad thing, but I
personally don't want a lot of diametric and constantly new choices when I'm
trying to build projects. JavaScript has flavor of the week, Clojure tends to
be very conservative.

With all that said, I don't mind using it in production because it is just me
alone working on my own projects. I've interviewed with a few places that use
it in prod and they are a) very happy using Clojure and b) are on polyglot
stacks. I'm not aware of anyone using Clojure completely alone.

The inherent problem with Clojure is that, rightly or wrongly, the perception
from many programmers is that it is too hard to learn, so there is no
selection of programmers, and the perception matches from the hiring
companies. Companies will be much more picky on who they even talk to. You
also have to consider that the common stacks are large framework / ORM / a lot
of things baked in / etc. Clojure strips away all of this magic. It appears
that many programmers just aren't comfortable working this close to the metal
(have no opinion on this and don't want to get into it).

Since there is a dearth of programmers, I would never build a project that I
intended to hire more people to work with, so really, I'd choose any of the
more-known languages to build very large projects.

My recent project is here:
[https://www.butternotes.com/](https://www.butternotes.com/)

I'm using Clojure / Compojure and using a lot of XML generating code for this.
I'm happy with the speed of development and happy with how easy it is to make
major changes and expand them globally. So, what you lose in defaults you gain
in flexibility, which is the trade-off you are required to take on when
working with Clojure. There is no analog to Rails, Django, etc.

------
heyyyyouguyyys
No

~~~
christophilus
Would you mind expanding? I'm assuming this is: "Yes, I've used Clojure. No, I
wouldn't use it again."

