
Why I like Clojure - tosh
http://sulami.github.io/posts/why-i-like-clojure/
======
vnorilo
My favorite thing about Clojure:

You compose libraries, instead of totally buy into framework A or B. Some
people prefer the opposite.

However, Composition _works_ in Clojure because everyone is using the staples:
functions, maps and seqs. Pretty much everything in the language can work as
one (or all!) of them.

While I also like static types, this is my argument for a well designed
dynanic language like Clojure or its Lisp relatives: stuff just snaps together
like magic lego bricks.

~~~
Kalium
Composing libraries instead of buying into a framework is a wonderful thing.
It allows a developer to use just the parts they want, integrate them with
just what the developer needs, and get on with whatever they're doing. It's a
beautiful idea, and it can enable amazing levels of productivity.

With that said, might it also be possible that there could be some drawbacks?
Having worked in and with Clojure, I found the ecosystem incredibly immature.
It's somewhere beyond arrogant - reckless comes to mind - for most engineers
to do all their own plumbing for a web service. The odds that they'll manage
to design someone easily long-term maintainable are slim. The chances of
authorization, authentication, potential SQL injection, and a thousand other
security things being handled well is effectively none - the Clojure ecosystem
often seems wildly ignorant of such things. The core philosophy of just
composing the libraries you need with Ring means that anything you don't
actively think of will be likely entirely neglected. This is a dangerous way
to ship code that will be facing the real internet. Clojure requires you to
fit absolutely every aspect of everything you're doing into your head and be
handled by you, because nothing is going to do it for you. The lovely magical
LEGO feeling is, sadly, a lie.

This stands in stark contrast to the level of consideration around maintenance
and security that has gone into a modern, mature framework. Or a modern
language where SAST is an option.

Doing low-level stuff feels _absolutely amazing_! The sense of control, of
having your hands in the guts and the ability to do what you need without
wasting time on bullshit magic, is heady and glorious. It's just perhaps worth
considering that that magic can sometimes be incredibly valuable, well worth
the tradeoff against the feeling of freedom.

~~~
Scarbutt
Really though, Clojure web apps are at the php-no-framework level security
days, not joking.

The most used HTML templater(hiccup) doesn't do any secure output escaping,
bad password/session management, auth*, sql injection, bad encryption methods,
its all there.

~~~
didibus
Hiccup has functionality to perform escaping with `h`. It doesn't do it by
default though, for performance reasons and nesting of Hiccup in Hiccup.
Normally, you'd just want to sanitize right before returning your response.

Doing it that way you can also perform more selective sanitation if needed.

Hiccup2 does sanitation by default, still in beta though.

The common SQL lib is java.jdbc or next.jdbc and they use prepared statements
by default. Can you explain more where you see common risks for SQL
injections?

I'm not sure what you mean by bad password and session management? Normally,
the common lib people use is ring-defaults [https://github.com/ring-
clojure/ring-defaults](https://github.com/ring-clojure/ring-defaults) what
about these do you feel are insufficient? Maybe do a pull request about it.

Auth and encryption I agree, but the untold reason is that people just use
Java bountycastle and Apache Shiro or other for that. Buddy is the most
popular Clojure one
[https://github.com/funcool/buddy](https://github.com/funcool/buddy) , but
honestly, for that stuff, you want something super battle tested, that means
popular, and Clojure as a whole isn't popular enough for that, so really just
pull in a Java lib done, it works flawlessly within Clojure.

~~~
Kalium
> Hiccup has functionality to perform escaping with `h`. It doesn't do it by
> default though, for performance reasons and nesting of Hiccup in Hiccup.
> Normally, you'd just want to sanitize right before returning your response.

One of the things that Rails' templates gets completely right is that it knows
when something is nested and when it's going to be returned immediately. It is
thus able to do its automatic escaping right before returning a response and
not before.

At this point in history, I think this is the baseline behavior all templating
systems should meet. Requiring users to remember to manually escape every
output every time is begging for exploitation. Such a design error only
strengthens the case that hiccup is not appropriate for serious use at this
time.

~~~
didibus
It seems Rails used to default to not escaping as well, but in Rails 3 they
switched to escape by default. And from what I'm reading, nested helpers do
suffer from the over escaping, and in fact they warn not to blindly html_safe
them. But I admit, I can't find very new guides on latest versions, are you
saying ERB now tracks nesting and only escape once at the end?

That's actually what hiccup2 does as well by the way. I admit, it is a nicer
behavior, and I'm not sure why hiccup2 hasn't gained more traction since it
released, but you are free to use it, it's part of the normal hiccup release,
just require hiccup2 instead of hiccup.

But hiccup is not the only popular Clojure HTML templating lib. Selmer,
Clostache and Stencil which are much more ERB or Django like, both HTML escape
by default.

------
peatmoss
I love the language. I’ve never found a language where I found the learning
curve so shallow for being able to do so much.

That said, I do find myself pining for the ability to easily compile a static
executable (maybe with a small embedded runtime). Some time ago there was an
attempt to port Clojure to Gambit Scheme, but that appears to have fizzled.

More recently, I’ve seen Ferret, which compiles a subset of Clojure down to
C++. Also Joker, which is a Clojure-ish interpreter in Go.

Then there’s GraalVM, which I don’t trust, because it’s Oracle.

I feel like the relative lack of traction for non-Java / non-Javascript
implementations is part of the brilliance and sadness of Clojure. Namely, the
JVM is a rocket ship and a boat anchor.

Racket (modulo the uncertainty cast by the Racket2 discussions) and Gerbil
Scheme both have a pretty good “distribute an executable” story while trying
to introduce some creature comforts beyond plain Scheme. I suppose my ideal,
would be something a little more like Clojure in terms of language, and a
little more like Scheme in terms of deployment options.

~~~
pmoriarty
Why not Chicken Scheme? It compiles down to C.

~~~
peatmoss
Oh, definitely Chicken as well. The library story with Chicken is also pretty
decent.

------
synthc
What I like most about Clojure is the interactivity: I can quickly test and
iterate on ideas in my editor connected to a REPL. To me, this is the main
advantage of Clojure.

Clojure's focus on the REPL, immutability and simple datastructures make it
possible to inspect data and redefine functions in running systems.

In other languages I spend a lot of time making small edits, setting
breakpoints, starting the debugger, waiting for the program to start, etc,
where in Clojure I can just redefine and inspect stuff immediately, allowing
very short feedback loops when programming.

A lot of Clojure tooling emphasizes short feedback loops: component with it's
reload function to restart systems, figwheel/shadowclj with live reload of
browser apps, which is a huge productivity boost.

Once I got used to the quick feedback loops that Clojure provides, all the
other languages feel bulky and slow to develop in.

------
marmaduke
> homoiconicity, meaning code can be represented as a data structure inside
> the same language

> generating strings and passing them into eval like for example in Python

Python has become a pinata for language enthusiasts? Python lets you pin a
decorator on a function, get the AST (a data structure AFAIK), manipulate it
in a sane fashion in Python, compile it, return the result. No string munching
eval require

I'm all for Lisp but this just isn't convincing

~~~
pritambaral
> get the AST (a data structure AFAIK), manipulate it in a sane fashion in
> Python, compile it, return the result. No string munching eval require

I use both Lisps and Python, and especially after learning to use Lisps I've
wanted to do this in Python, so I looked for the ability to do what you
describe here.

While it is technically possible to do this (like most things) in Python, it
is quite the effort and nowhere near ergonomic. Among all the cases where I
could really use this, I found it worth the effort to instead:

1\. Manipulate & generate code statically (from ASTs), as a build-time / dev-
time step, using redbaron etc.; or

2\. Just use a Lisp (specifically, Hy).

Both methods involved writing quite a lot of code. In the former: to load,
parse, match, and transform ASTs; in the latter: to port existing code (the
code I originally wanted to manipulate) from Python to Hy.

\----

The reason for all this is plainly the fact that Lisps are designed for this,
while Python is not. Before learning Lisp, I used to wonder what could be so
different in the language itself that could possibly make it that much easier.
Now I use a Lisp-in-Python in production precisely because of this.

~~~
marmaduke
This is true, but I wanted to correct factual errors in the article.

If you or your team are Lisp users then Hy or Clojure would be good choices,
but if you are just trying to create a transformation for existing Python
codebases, the decorator approach is a good shoehorn.

On the other hand, you can also interpret the difficulty of AST transforms as
a signal from the language designers (had van Rossum really never heard of
Lisp?) that they hurt readability and their use should require a little
ceremony.

~~~
pritambaral
I'm sorry, but I don't agree at all.

> if you are just trying to create a transformation for existing Python
> codebases, the decorator approach is a good shoehorn.

For transformations that need to modify the code, decorators are insufficient.
Decorators have their value, and I have built good interfaces using
decorators, which would have been rather difficult without them, but all of
that was because decorators help _wrap_, not _transform_ code.

When I had a need to transform code, I looked for the right tool, and the
takeaways of my searches are mentioned in my original comment.

> you can also interpret the difficulty of AST transforms as a signal from the
> language designers (had van Rossum really never heard of Lisp?) that they
> hurt readability and their use should require a little ceremony.

Nobody's claiming Guido had never heard of Lisp, or any non-lispy-language
designer for that matter. Language designers make languages for varied
reasons. Guido's reasons actually happen to be documented, and the only reason
Python isn't homoiconic is because Guido didn't have a need for it, not
because he explicitly wanted AST transforms to "require a little ceremony".

In fact, Python AST transforms do not merely "require a little ceremony". They
are actually quite cumbersome. The standard library actually provides no help
at all in transforms, making it necessary for libraries like Rope, RedBaron,
and Astor to be written.

------
Kalium
I love the _idea_ of Clojure.

I find the ecosystem immature and full of ideas about "libraries, not
frameworks" that leave developers incredibly vulnerable to their own ignorance
and second-order ignorance. The number of developers I know - or even know of
- that can be trusted to develop a useful and secure web application from the
ground up with this kind of tooling approaches zero.

Clojure is a cool language. I can only hope the ecosystem soon matures enough
to make it one that's suitable for serious use.

~~~
dmix
Which libraries are people expected to plug together the security parts? I'm
not pushing for clojure but a lot of other languages and frameworks are taking
this approach too including Node and Go.

Wouldn't the security stuff be a part of the individual packages? Ie
authentication package handles sessions and tokens, an http server/middleware
with built in csp and ssl, orm, the data stuff handling serialization and data
parsing?

Technically rails is composed of a bunch of smaller gems with a similar
responsibility tree although without the centralized CVE distribution and
pressure that creates.

When I used Clojure it was always mini frameworks which created a base set of
important packages with a pluggable middleware system on top and flexible data
back ends.

The individual packages need to have domain experts for their particular
attack surfaces and exposures.

If anything its about a lack of eyes or community size on the various wholes,
rather than expecting the end user to do the individual hardening or plumbing.

~~~
Kalium
You're right. Many things can be handled by packages, abstracting them away
from the developer.

Of course, that's assuming the developer thinks far enough ahead to remember
that they need authentication, decide how they want to handle it, figure out
what they want for a CSP, and so on. Other things cannot be so readily
handled. Authorization, for example, isn't a concern that can be bundled into
a pre-fab function. It's something application-specific that has to be re-
evaluated with every single web request and is going to be subject to unique
business requirements.

Frameworks tend to handle these issues by setting out a set of conventions to
adhere to, within which many of these concerns are handled for you to the
extent possible. It's far from perfect, but it does a lot to reduce the
chances of someone forgetting (for example) that forms need anti-CSRF tokens
because their form-generation function doesn't do it for them or automatically
work with the form-accepting and validating functions.

Or, to use example I've seen, the logging package's ignorance of what might be
sensitive in the strings its been handed turns into secrets being sent to the
centralized logging system and exposed to far more people than they should be.
The developer didn't think about what might be in what they were logging, the
package assumed that the developer _did_ , and the result could have been
avoided by a more integrated whole.

A culture of libraries instead of frameworks can mean that each project may
have to make all the decisions a framework does all over again. Is everyone
going to get it right every time?

~~~
bcrosby95
> The developer didn't think about what might be in what they were logging,
> the package assumed that the developer did, and the result could have been
> avoided by a more integrated whole

Umm, is there any all in one web framework that protects against this to any
level of guarantee?

~~~
Kalium
It's been my experience that Rails logging can and will do things like censor
password fields when passed objects.

So, yes, it is possible for logging (and serialization) systems to defend
against this kind of thing.

~~~
bcrosby95
In my experience these password logging events tend to be at a lower level
than object serialization. They're usually at the raw request level.

------
dominotw
> While the primary platform is the JVM, superbly uncool but stable and
> relatively performant

My impression was that java has the reputation of being "uncool" but JVM is
highly regarded as modern marvel.

I am wrong about this ?

~~~
eternalban
IT Java is uncool, but then IT is uncool even if written in Clojure (though
the psychological aspect of using a "cool" language will likely dampen the
existential pain of writing yet another book keeping CRUD app since now you
are using s-expressions!)

In my experience, people who say silly things about Java -- the technology,
which certainly includes the Java Language Semantics, and JVM -- actually do
not know what you can do with Java (the language).

So yes, you Lisp nerds have you homoiconic 'mash' of syntax and thus AST
manipulation, and we have first class Class Loaders and Byte Code Engineering
and the sky is the limit there. Magic.

But the sad reality of programmers' lives is the disconnect between the
required cognitive capabilities of workers and the actual (domain) task at
hand.

tldr;/ its your job that is uncool not the tech.

~~~
0x445442
> But the sad reality of programmers' lives is the disconnect between the
> required cognitive capabilities of workers and the actual (domain) task at
> hand.

Yeah, I just don't understand the less lines of code argument. This is not the
limiting factor in software development, it's just not. The limiting factor is
having enough information for the immediate Use Case and enough business
domain knowledge to come up with a solution that delivers value to the
business. The time spent on delivering that value dwarfs the time it takes to
write some extra code. Let's look at Uncle Bob's example in the linked
article...

(println (take 25 (map #(* % %) (range))))

While fancy, that code is very Perlish and I think we all know the common
criticisms of Perl. Also, fancy doesn't pay.

What I've found to have a much larger negative impact on a project than the
language is overly complicated architectures. To the extent Clojure can help
with that I'm all for it. But from what I've seen, Java 8 with some clear
conventions and constraining source code to the implementation of the Function
interface can get you a lot of the same benefits.

------
rrosen326
Clojure Help:

This is super apropos since I am JUST learning Clojure via the Clojure Koans.

Any tips from clojurists on getting the repl (and readline) working fluently?
I'm using Leiningen but it's not responding as I'd expect. I would think this
would all set up more effortlessly.

Tips on getting a new Clojure setup working would be appreciated.

~~~
mping
I recommend emacs, try braveclojure.com - it's a pain to set up properly but
well worth it.

~~~
iLemming
As an avid Emacsen, I would usually recommend Clojure-mode and CIDER _only_ if
you are already familiar with Emacs. Learning both - Clojure and Emacs can be
really frustrating and may potentially become a "deal-breaking" impediment.
Almost every [popular] editor/IDE today supports Clojure (not many mainstream
langs can proudly say so)

------
mruts
One (stupid?) thing that annoys me about closure is that native clojure
libraries use snake case while java libraries use camel case. You could
obviously write a new defn macro to take of all this and make it consistent,
but it might have just been a better decision to just make everything camel
case, in in Lisp-like fashion.

Also I find Clojure a little dogmatic in regards to mutation, more so than
even Scheme. I find Racket to be better designed and more elegant, though
currently the performance isn’t as good.

~~~
keymone
Clojure being dogmatic is the reason I love it.

~~~
dkersten
Agreed. While I don’t always agree with its dogma, without it I don’t think
I’d still be using Clojure, yet here I am ten years after first learning it.
Clojure is great _because_ it takes a strong stance on how certain things
should be done.

~~~
keymone
yep. also, i think learning how clojure's dogmas synergize with each other is
the determining factor in whether one is a clojurist for life or not.

------
BlueTemplar
> While OO seems to be out, and FP the new hotness

Funny that. While I prefer FP, and did since I've learned Python, my teachers
are really hot about OO, even pushing us to use it in Python projects.

(Looking at projects from previous years, they mostly seemed to use Java. Then
also because of browser integration and obviously because of the OO <-> UML
<-> Project links ?)

~~~
nafeydev
Is there any reason to believe FP is the "new hotness". Each year in the Stack
overflow language trends report the FP languages are barely making an impact.

~~~
flixic
FP languages are not that big. FP architecture and practices are very popular.
React, Immutability and more have become mainstream.

A recent example is SwiftUI. While Swift is not a FP language, SwiftUI (FP UI
framework) and Combine (a FP toolkit) is being pushed by Apple as the future
UI architecture for all its OSes.

------
nautilus12
Need someone to explain why I should use clojure over scala because typelevel
seems pretty well developed

~~~
serpix
Clojure: live repl into running code

Scala:

Clojure: Explore the problem you are facing with quick prototyping in the repl
and see the blind spots, the unknowns, the shape of data received from flaky
integrations. Mold and shape your functions as the problem becomes clearer.

Scala: Best it can do is write unit tests and the debugger to look at what
exactly is happening, devise a bunch of classes to handle them, rinse repeat
and of course wait hours for recompiles. Refactor when new unknowns surface
and curse at the fucking compiler not knowing what type it should be
inferring.

Clojure programmers are done before Scala has a test environment up.

~~~
justinhj
I'm sure you're happy with Clojure and I'm not going to try and convince you
Scala is better but you have some misconceptions.

Firstly Scala does have a couple of REPL's, the best being Ammonite which is
mentioned below. It can be embedded in code to provide a live repl just as
your Clojure program. I often work in Scala in a similar way to I work in
Clojure; creating and testing new types and functions in the repl before
moving them back to a source file.

The way you build programs sounds quite horrible, but I know people do it that
way and it works well enough. Your complaints about long compile times are
largely irrelevant. Incremental compilation means it's usually 2-3 seconds at
the most before I can test a change. We don't build programs as a bunch of
classes by the way, that would be OOP. Scala is more commonly written in a
functional and/or streaming/reactive stle. Also I'm glad you brought up
refactoring. It's a breeze in Scala because of the strong type system. Poorly
defined data can be expressed just well in Scala with types as it can in your
blob of maps of maps, and it's much easier to work with.

Finally you may finish your program first; it appears to do the thing you want
but you can't really be sure. There will be more runtime errors such as NPE's
and type errors because you don't have mechanisms to remove them from
possibility. I'd much rather maintain and evolve a Scala program.

~~~
the2bears
> Scala is more commonly written in a functional and/or streaming/reactive
> stle.

This is the exact opposite of my experience. All the Scala I've seen "in the
wild" is basically Java with a slightly different syntax. All OO, with the odd
high-level function thrown in to prove something I guess.

------
swyx
as i was talking to a friend about clojure i came up with an analogy i cant
shake: clojure is what happens when you just make your programmer directly
write an AST. a bit reductionist, but anyone care to debate this?

~~~
_hardwaregeek
Isn't that the point of lisp and homoiconicity in general? That you're writing
an AST that you can also treat as a data structure?

~~~
swyx
ok so... why is writing an AST more ergonomic than having some syntax?

~~~
_hardwaregeek
It’s really not. That’s part of the problem with lisp. But you can treat your
code as a data structure which offers a lot of benefits. For instance, it’s
basically impossible to offer control flow as a library in normal languages.
That is, if you wanted to implement an unless statement like in Ruby, you’d
have to use thunks or some other form of lazy evaluation. Macros allow you to
just transform the unless statement into an if statement quite easily by just
operating on the AST. Of course, you can do this without homoiconicity but
it’s a lot less ergonomic.

Also part of the reason Babel exists is to take the place of a macro system.
Instead of transpiling array spread into a function polyfill, macros would
just output the pollyfill into the AST. What’s nice about this is that since
it’s userland, people can test drive new features. Rust did that for
async/await. And the pattern matching proposal in JS is based off a SweetJS
macro.

(Obviously not all language features can be implemented as macros but you get
my point, right)

~~~
swyx
i think so. thanks for the explainer!

------
amelius
I tried to learn (get to know) Clojure by writing a library for cacheing
(memoizing) function calls. I thought it would be a simple exercise, but it
turned out to be not so easy at all, with lots of special cases.

~~~
dmix
That seems like an unusual first project. Any reason you chose it? Were you
more interested in the language semantics?

~~~
amelius
It was because (1) a project I was thinking of would lean heavily on memoized
calls, and (2) it would allow me to learn about less basic features like
introspection and (3) to quickly see how cleanly the language was designed to
not be disappointed later on.

~~~
yayitswei
You could check out Clojure's built-in memoize
([https://clojuredocs.org/clojure.core/memoize](https://clojuredocs.org/clojure.core/memoize))

------
ngcc_hk
It is a good language. Python is easier for quick code.

~~~
iLemming
I disagree. It's the matter of familiarity. Clojure is extremely productive
and the best PL I have tried (out of many) to quickly build prototypes.

Whenever I have a requirement to solve a problem in a different language (e.g.
interview challenge, etc.) I would still do it first in Clojure and then
convert it to whatever language is required. Yes, I have to do the same work
twice, but even then - I am still faster doing it that way.

------
dev_dull
> _Clojure is explicitly designed as a hosted language, which I think was a
> very good move._

I’m not personally a fan of a VM such as JVM. Sure you get some easy benefits,
but now you have two things that need tuning. Two things that need periodic
updating.

Personally the total encapsulation of first-class static linking (such as
Golang) is my preferred future. It must be first class and baked into the
language in its design.

~~~
iLemming
You're missing the point. Because Clojure is hosted you basically can share
code between JVM and Javascript. It is extremely nice when you actually can do
that. Even in NodeJS, essentially running on different implementations of the
same platform - that is hard. As it turns out - not so hard in Clojure.

Now, imagine also having access to thousand of libraries written for JVM and
Nodejs and Browsers? There are attempts to port Clojure to other ecosystems,
making it possible to use them there. What if someday you can write Clojure
code that can be shared between say Rust runtime, NodeJS and a browser?
Wouldn't be that cool?

------
itwy
Clojure/Lisp is super nice until you have a bunch of transformations to make
then you've to keep everything in mind without having a named reference in
front of you (unless you omit the threading operators and abuse the let
statement). It becomes exhausting after a while and makes you question if you
are working for the machine or the machine is working for you.

Yes, it's more succinct and elegant but is it worth it?

~~~
vemv
You are absolutely free to decompose computations into more `defn`s, `let`
statements, or threading operators. Or mix and match those.

~~~
itwy
You are 100% right but I am not writing all the code. My job is mostly
maintaining other developers' code. And turns out, languages can have great
effect on making not-so-good developer write reasonably good code (Go, for
example).

~~~
kccqzy
One thing I've come to realize is that it is not enough to write code that's
merely compilable. That's a low bar. A team needs a consistent style and that
has to be enforced automatically. Automatic formatting is a good first step
but that's also not enough. Say you don't want too many nested s-expressions.
Then write a tool to reject code that has too many of them. Run the tool
together with the compiler. Prevent merging if the tool complains unless a
special exception is noted.

Tooling is important.

