
Why I'm Productive in Clojure (2013) - tosh
http://yogthos.net/posts/2013-08-18-Why-I-m-Productive-in-Clojure.html
======
preordained
I've really taken a shine to Clojure. Parentheses and dynamic typing initially
kept me away, but they're far from the thorns they've been made out to be.

Parentheses? You don't even see them after a short while--as a beginner, you
use something like parinfer, you are good to go. That, and like all lisps, you
begin to appreciate programming directly in the abstract syntax tree: the
language you type and the way it is interpreted aren't disjoint things.

Dynamic typing? Being functional, immutable by default, and data orientated
steal the _vast_ majority of the sting from that in my opinion--and leave you
with often downplayed advantages. On the last point, "data oriented", to put
it succinctly, data itself is first class or the prominent currency among
Clojurists, rather than a zoo of abstractions that never quite fit and and all
have to be reconciled and made to play with one another (and often the reason
you _need_ types everywhere to keep it all straight).

But where types--or validation--are more crucial near the boundaries of the
API, there are outside the box solutions like Spec that don't rely on a baked
in type system.

The recent keynote by Rich Hickey covers a lot of these points (and far better
than me):

[https://m.youtube.com/watch?v=2V1FtfBDsLU](https://m.youtube.com/watch?v=2V1FtfBDsLU)

~~~
jasim
If you have used a statically typed language in the ML family (OCaml, Haskell
etc.), could you contrast the development experience between the two?

~~~
preordained
I spent a good year or so with Haskell. I guess at first blush, one thing that
jumped out was that Clojure was made from the jump with a focus on
productivity and pragmatism, whereas you never feel too far from the academic
origins of Haskell. Clojure is a very shrewdly designed--it's not proud, it
takes leverage where it can find it, and makes some very deliberate and
sensible trade offs. A large aspect of that is the JVM it sits atop of. You
will know that it's Java underneath the hood, but this is not a bad thing at
all. You get to have your cake and eat it too. It's done really well in the
sense that while it would be awkward and not Clojure-like to promiscuously
call native Java--especially code with side-effects--it it is perfectly
alright, and practical, to pull in any of the multitude of proven Java
libraries where it can obviously save you time and effort. There is no
snobbery in the core language itself or in the community about "ew, icky
Java". Or put another way, there is no from-scratch ecosystem like in so many
languages where a new language means starting over (so the language needs a
crypto library, and a web server, and...) Not to mention, many of the utility
libraries out there are largely functional in nature anyhow (you can use a
massive chunk of the wealth that is Apache Commons as just an arsenal of pure
functions).

In nitty gritty terms, programming in Clojure actually feels a lot like
programming in Haskell to me, without the heavy type system. Lazy infinite
lists, all your FP classics like map, reduce, filter, etc. work exactly like
you would expect. But I don't miss having to create a stack of monad
transformers in an area of code where I need to mix IO and state or
something...and using type synonyms to mask the monstrous Turing-complete type
signatures I had to make to describe it... In Clojure, you just put the
"dirty" work in its own function, clearly separated from the pure functions
(which are the de facto default), and you push them to the boundaries of the
system while passing extracted data into pure functions (just like Haskell).
If you did anything different, you'd get the stink eye from even the least
principled Clojurists. It's just not done. A ball and chain type system is
unnecessary.

The lack of (explicit) types has been at the very most a minor nuisance.
Occasionally I mistype something or miss a parameter, you're going to see the
error pretty quickly in the REPL. If you run or test your code at all, the
pedestrian type errors (oh, that was a string not an int) will be wrung out
immediately. That benefit of type systems (preventing typos, essentially) has
been much, much overstated IMO. Given you're going to be in the REPL a lot
with Clojure, you'll be iteratatively developing and running your code
constantly, so it's really not an issue. As far as refactoring, I think that's
where there is more meaningful benefit. I use Intellij/Cursive IDE, and the
refactoring capabilities are good--much like if it were a Java project (and
there are hints and such for the typos I mentioned earlier, autocomplete,
etc). So, while it is more of a challenge for IDEs, there are some excellent
ones that do a pretty bang up job of inferring types for you.

I haven't used Clojure on the job (Java dev by day), but I would have no
problem using it for something "real", whereas I never felt anywhere near
confident in using Haskell for something outside my own fiddling.

~~~
jasim
Thanks for the reply, it was very informative.

I've programmed in dynamic languages for most of my career (about a decade
now), and have always missed types. I picked up OCaml (Reason flavoured)
recently, and I've been able to enjoy the Hindley-Milner typesystem without
worrying about side-effects with complex types, since OCaml is a fine mix of
imperative and functional programming.

Language preferences are usually framed as an objective measurement, but I've
always found it to be based on our personal experiences. Since you've been
doing a lot of Java, I'd surmise that the clean, functional yet dynamic nature
of Clojure with Java interop is appealing to you. Me on the other hand has
been burnt enough times with dynamic systems that keep shifting from under
your foot (Ruby metaprogramming), test suites that makes refactoring more
difficult (it provides safety, but the manual labour is unforgiving), and a
general sense of dread everytime I put systems into production. But more than
anything else, the biggest pain has been the sheer difficulty to refactor
growing codebases.

Large dynamic systems, if they manage to not crumble from the inside, usually
gets hammered by a sweeping change in external reality (terminology changes,
shifting of levels in domain hierarchy etc.). When there is a pressure to ship
we add a new mapping without touching existing naming, and slowly the domain
names in the system exhibits a tangled relation with the actual domain.

That's just been my experience, and so I'm here learning me some good old
OCaml and being very happy with what I'm getting out of it.

~~~
freshhawk
Have a look at Spec and the design philosophy behind it if you are still
interested in Clojure at all. Especially how Hickey feels about open specs,
versioning, and names. It is a pretty opinionated stance to take on solving
those issues, but it convinced me and I no longer have the worries you
describe about the dynamic nature of a large Clojure system.

------
tomerbd
I would love to use closure, i just stay away from dynamically typed languages
- after having a bad experience trying to maintain projects written in a
dynamically typed languages which was an awful experience. You see a parameter
named user and you have no idea which type it is, which fields it has, does
this user has a phone number? how can i know? You see functions and you don't
have any idea what is the type they return. just to put things in perspective
I maintained X100 larger projects in a statically typed languages, with even
worse code but maintaining it was easier than these other projects. Simply
because I knew what functions were getting in and what their return type was.

~~~
pron
I generally agree with you, but Clojure is not at all like other dynamic
languages (like, say, JS). For one, Clojure's dynamic dispatch is more like
C++/Java's -- i.e., when you call a function, you can statically know either
the precise target or an explicitly designated set of possible targets.
Second, Clojure allows you to specify the types of arguments (and much more,
in fact), not with a type system, but with a specification system. It's not
exactly the same, but it can be more/less powerful than types, depending on
usage.

~~~
ngrilly
How is the specification checked, statically or dynamically?

~~~
hellofunk
You can see my other comment to your same question. Also, even if you do not
use Spec, you do get a lot of compile-time validation like making sure all
arguments are passed to a function, not leaving them out, etc. Try that in
Javascript!

~~~
ngrilly
Are you sure about _" you do get compile-time validation like making sure all
arguments are passed to a function"_?

If I run this:

    
    
        (defn bar [x y]
            (println x y))
    
        (defn foo [v]
            (if v (bar 12 42 79)))
    
        (foo false)
    

The program prints nothing and Clojure reports no error.

But when I run this:

    
    
        (foo true)
    

Then Clojure reports an error:

    
    
        Exception in thread "main" clojure.lang.ArityException: Wrong number of args (3) passed to: user/bar, compiling:(.../test.clj:6:5)

~~~
hellofunk
I don't spend much time on the JVM, but in ClojureScript, this is what I get
for a similar test (including multiple definitions of foo in my case, i've
elided the whole source file here):

    
    
         (defn foo [a b] :hi)
         (defn bar [] (foo 1 2 3))
    
         WARNING: Wrong number of args (3) passed to prepost.core/foo at line 25 src/cljs/prepost/core.cljs
         WARNING: foo at line 24 is being replaced at line 48 src/cljs/prepost/core.cljs
    

It's a compile-time warning even when the app is not running, but
ClojureScript goes through a different compilation step than JVM Clojure.
Perhaps I was mistaken in the JVM case, or someone else can chime in.

~~~
ngrilly
Maybe ClojureScript is doing something Clojure doesn't at compilation time…

------
tombert
I love Haskell for its type system, but I gotta say that I feel I accomplish
about 10x as much with Clojure than I do with it. Being able to quickly beam
over my code from Vim to the REPL, and seeing my changes happen in real-time
is so incredibly valuable, and I personally feel that Clojure's concurrency is
a lot easier to grok than Haskell's.

I also feel that Clojure's tooling is a lot nicer than most languages, and
especially Haskell; Leiningen is very easy to use and Fireplace is a really
simple and nice plugin for Vim.

------
nickbauman
When I have to write something computationally complex in the language my
employer wants me to write it in, I first write it in Clojure because it's
easier to think about the problem in that language. Then I translate that.

I'm willing to bet that any dev who has learned Clojure does the same thing.
If I'm right, that's a huge indictment of what we've been doing for the last
60 years in programming.

~~~
aaron-lebo
You'd lose that bet. I think it's easier to reason about problems in languages
you are familiar with and that fit how you think, which can change through
continued use. A lot of the other stuff is just post hoc rationalization about
why we like these languages and why they are better.

~~~
cutler
Surely the argument being made here is for the best prototyping language, not
the most familiar. If familiarity was the only yardstick nothing beyond C
would even exist.

~~~
platz
The argument being made is if it's necessarily efficient to prototype in a
different language than the one that will be actually used, especially if one
is more familiar with the target language.

------
ronnier
I’ve already seen large scale clojure projects being rewritten to something
average devs can maintain. Don’t expect much more growth out of this language
in terms of new projects written in clojure.

~~~
hellofunk
Ten years ago (appoximately) I read an article about how PHP was dying, thanks
in part to many new languages cropping up. But I see PHP mentioned all the
time here on HN, and the PHP meetups in my area are frequent and popular, and
major companies run on PHP.

For decades, there have been rumors about the death of dynamic languages in
general. And yet the decades pass and not only do those languages continue to
flourish, but others come along and get popular too.

Clojure just turned 10 years old and I see no signs of it slowing down. They
did consolidate their 2 major conferences in the States into just one annual
conference, so there's that (which may not mean anything). But I am in a large
city and companies keep appearing and starting up with Clojure as their key
language.

With Clojure, it's an oddball because it is very simple and very powerful.
Oftentimes, simple languages are not so powerful, and powerful languages are
not so simple. But with Clojure, you can very easily get yourself into the
situation of having extremely dense logic in just a few lines, where another
language might easily take 10x (or more) lines to accomplish the same. This
leads to code that can indeed be difficult to read later, especially if you
are on a team and others must help maintain it. The Clojure community has come
up with some excellent solutions to this problem, most recently the
Clojure.spec library which is gaining wide adoption, which not only makes such
"cleverness" easier to understand when reading it, but also makes a codebase
automatically testable with property generators, which is a major feature. But
your point about readability is always going to exist with a language like
Clojure if it isn't written with a team in mind. That doesn't take away from
its power though, in my opinion.

However, there is one particularly indispensable tool that Clojure offers that
I have not seen anything to meaningfully compete with for productivity, and
that's ClojureScript. Writing a front end with Reagent or even the alternative
libraries is such a major win over everything else I've tried. I've worked a
bit with Elm, Typescript, Reason, Bucklescript -- I am so spoiled by the
extremely fast turnaround and easy interaction with very powerful features
like React in Clojurescript that I don't see anything on the horizon that will
come close to replacing that workflow for now. Perhaps some day something will
come along to shine an even brighter light on how front ends can be developed,
but for now, ClojureScript remains one of the most significant contributions
to the software industry in many, many years.

~~~
user5994461
PHP has a massive following. It was basically the only language for the web
1-2 decades ago, everything had to be written in PHP. Of course, it cannot be
extinguished since the existing sites will drag on forever.

Clojure never had much usage on real world projects. It cannot be extinguishes
as it never took of.

~~~
hellofunk
> It cannot be extinguishes as it never took of.

I'm not sure what you mean by "never took off" but thousands of developers
around the world, myself included, have made their living just writing Clojure
code for many years. So, it has certainly taken off for them. And there are
many, many companies using it all over the world. I live in a town of about
half a million people, so not super big, and there are about 12 companies
primarily operating on a Clojure codebase.

~~~
cutler
I'm genuinely intrigued. Which town is that?

~~~
hellofunk
A lovely place in Western Europe.

------
erichmond
I've been debating whether or not to give a talk / write a blog post on this,
but I think this might just be the kind of thing that people make their
assumptions about, and thats it.

I do wish people would give clojure a real go, not just running a toy program,
but taking the time to setup a REPL in clojure and clojurescript, learn about
sending commands from the editor directly into the REPL, etc.

The reasons for choosing clojure are un-obvious at first glance. Moving from
Java -> Ruby for example is something that you feel immediately. People
understand in < 5 mins why ruby might be a better fit for a number of
solutions then Java.

I don't dig clojure because it's a LISP, or it's homoiconic, or because of
most of the academic ideas here in this thread. I picked clojure because with
it, I get clojure and clojurescript.

With clojure I get to target all java libraries, great concurrency primitives,
the ability to live code a running system, the ability to experiment extremely
quickly due to the REPL based workflow, now with spec/generative testing, I
get __better __testing then I had before, with writing fewer tests. I get
systems are often easier to reason about or debug. There 's rarely a ton of
libraries to do a single thing. Existing libraries don't change much. We
launched our first service in clojure 1.6, we've never had to do anything but
bump the version number. No breakage.

With clojurescript we get just as many benefits. CLJS gives us access to all
javascript libraries that have been written, Re-Frame/Om Next are incredible
frameworks on top of react, figwheel allows us to never (rarely actually) have
to refresh a page when doing layout / css things. Because we have access to a
running REPL we can change the state of the app via function, allowing for way
rigamarole when trying to test out inputs, etc. devcards lets you look at all
the state of your widgets on the page + figwheel means you can see how CSS
changes will affect all the states of your widget at once.

Synchronicity between the two languages allows us to write .cljc files where
share functions and schemas can exist, so your backend and front end are
pointing to the same place for critical things that should be shared.

It's really really different, but it's really really great. If you're a
professional in the field, you owe it to yourself to just try it out and see
if it helps you save time and be more productive.

~~~
erichmond
All that said, it's not perfect and there are annoying things about it, so I'm
not painting it as a perfect language. And there are problems that it's
probably not well suited to solve.

I discovered clojure about 25 years into my programming career, and while it
introduced new "annoying things", it resolved most of the annoying things I
had dealt with over the past 25 years in most other languages.

------
grzm
(2013)

Discussion from a couple of years ago (97 comments):

[https://news.ycombinator.com/item?id=8074186](https://news.ycombinator.com/item?id=8074186)

------
juliangamble
> As the project matures bugs are inevitably found or new features are added,
> these correspond the occasional spikes in the activity. However, if the
> initial phase of the project can't be completed in a timely fashion then
> nothing else can happen.

> In my experience, if you can't get something interesting working in a few
> days the likelihood of actually finishing the project starts rapidly
> approaching zero.

> With Clojure you can get things done fast, fast enough that you get
> something working while the initial spark of excitement is still present. I
> would hazard to guess that this is the reason why Clojure has so many great
> libraries despite being a young language.

------
jgalt212
Python dev here who chooses his own tools. I want to move to Clojure, but
Clojure and the JVM just aren't that strong in machine learning and ML is my
current "growth" area.

Even with JVM based solutions, such as Stanford CoreNLP Python has more
support/interest than Clojure.

I am not here to pump up Python and knock Clojure, just to illustrate there
are areas that Clojure has a ton more wood to chop. And I do understand there
have been significant efforts made in this arena lately. e.g. Neanderthal

[http://neanderthal.uncomplicate.org/](http://neanderthal.uncomplicate.org/)

~~~
falcolas
Having worked with both Lisp and Python, I feel relatively comfortable saying
the only thing missing from Python is macros; and when it comes to readable
code, it's not a debilitating loss. Much of a macro's capability to create
DSLs can be replicated using the introspection and metaprogramming.

There are also some lisps that target the Python VM, so you could consider
using one of those.

~~~
cutler
Yes, Hy ([http://hylang.org](http://hylang.org)) is similar to Clojure and
very nice to work with. Sadly, they had to abandon their implementation of
__let __recently.

------
lloeki
> Some languages are simple but they're also verbose. You've probably heard
> people say that verbosity really doesn't matter. These people will go to
> great length to point out that all languages are Turing complete and that in
> certain languages you simply have to write a bit more code.

This argument I usually dismiss by suggesting moving to INTERCAL or Brainfuck.
Even syntax matters a lot more than people care to admit. The best language is
the one with which you can frictionlessly reason about and express a problem
without impediment from syntax, paradigms, concepts and boilerplate. Computer
languages just as much as natural ones are deeply tied to the way we think[0].

[0]:
[https://en.wikipedia.org/wiki/Linguistic_relativity#Programm...](https://en.wikipedia.org/wiki/Linguistic_relativity#Programming_languages)

~~~
yogthos
I agree, and that's one of many reasons I like Clojure so much. I find its
syntax maps very cleanly to the way I think. It's one of the most readable
languages I've worked with. It primarily has to do with Clojure syntax being
simple and consistent.

------
devmunchies
Is this the same author as this book or is there plagiarism going on:
[https://www.amazon.com/Web-Development-Clojure-Build-
Bulletp...](https://www.amazon.com/Web-Development-Clojure-Build-
Bulletproof/dp/1680500821)

Go down to the "From the Publisher" section and you'll see:

> _" But the practical question is how well the language maps to the problem
> to be solved. Does the language let you think in terms of your problem
> domain, or do you have to keep translating domain concepts in the constructs
> of the language? The best case is when you can use the language without
> thinking about it."_

~~~
handojin
Same author.

------
cutler
The sad fact of life is that large corporations often dictate the platform. If
you're a mobile app developer, for example, you're only native options are
Swift, Java and Kotlin unless you're prepared to settle for a less efficient
end product (Xamarin, Scala/Android, Clojure/Android).

~~~
city41
Job trends play a role too. I really like Clojure and would like to keep using
it. But it's less likely to help get me a job than say learning Python.

~~~
vemv
I also feel this pain. The reward is high though (salary, remote, colleagues)
so I remain motivated.

One also can help creating job market by

\- starting up

\- introducing Clojure at work

\- evangelizing it at local meetups (e.g. hijack a JS meetup, explaining cljs
goodness)

I've been thinking about the latter, as a consultant creating a 'need' for
your services would be quite an accomplishment.

------
maxpert
I have honestly tried many many times to read books/tutorials for getting
started in LISP. I know there are many LISP inspired languages and Clojure is
one of them. Where LISP throws me off is the excessive use of parenthesis, up-
to the point my mind can't keep track of them anymore and IMHO language uses
it's comprehension abilities. I am still struggling and pushing hard to learn
it; hopefully I can get over it and experience the most powerful language. Any
good starting projects/ideas I should try doing in LISP/Clojure etc. to help
me out?

~~~
didip
You just have to indent them the same way you'd indent curly braces.

The harder part about lisp is actually recursion. Surprisingly, there aren't a
lot of programmers who can follow recursion naturally.

(loop exists in lisp but recursion seems to be the common idiom)

~~~
ZenoArrow
>"The harder part about lisp is actually recursion. Surprisingly, there aren't
a lot of programmers who can follow recursion naturally."

All examples of recursion I've ever seen in Lisp follow a similar structure...

* First section checks if recursion is finished. If so, return final result (or final element of full result if returning a list).

* Second section performs an action or two on the inputs.

* Third section calls the function again with revised inputs.

In many ways it's just a do while loop with different syntax.

------
muxator
I have no lisp experience, but I want to ask to who knows more: isn't the use
of too many macros a potential hinder to maintainability? What happens to a
project when it becomes a mini-language in itself, with its conventions, it's
opinions, it's specific flavour? Does this help or discourage the onboarding
of new developers?

I know C is not a good example, bit at least in C projects, I was always wary
of "smart" developers inventing their own "smart" conventions and syntaxes

~~~
kazinator
Macro use scenarios have to be weighed against the alternative: writing _by
hand_ the logic that the machine would have generated from macro invocations.

------
thediff
I liked this quote.

"What matters to me in a language is whether I can use it without thinking
about it."

