I found one of the perceived weaknesses of Clojure (in this article), it being dynamically typed, is a tradeoff rather than a pure negative. But it applies that tradeoff differently than dynamic languages I know otherwise and that difference is qualitative: It enables a truly interactive way of development that keeps your mind in the code, while it is running. This is why people get addicted to Lisp, Smalltalk and similar languages.<p>> To understand a program you must become both the machine and the program.<p>- Epigrams in Programming, Alan Perlis<p>Two of the big advantages of (gradually-) typed languages are communication (documentation) and robustness. These can be gained back with clojure spec and other fantastic libraries like schema and malli. What you get here goes way beyond what a strict, static type systems gets you, such as arbitrary predicate validation, freely composable schemas, automated instrumentation and property testing. You simply do not have that in a static world. These are old ideas and I think one of the most notable ones would be Eiffel with it's Design by Contract method, where you communicate pre-/post-conditions and invariants clearly. It speaks to the power of Clojure (and Lisp in general) that those are just libraries, not external tools or compiler extensions.
One thing I don't like about all articles on clojure is that basically all of them say: ah, it's just like lisp with lists `(an (example of) (a list))` with vectors `[1 2 3]` thrown in. So easy!<p>But then you get to Clojure proper, and you run into additional syntax that either convention or functions/macros that look like additional syntax.<p>Ok, granted, -> and ->> are easy to reason about (though they look like additional syntax).<p>But then there's entirely ungooglable ^ that I see in code from time to time. Or the convention (?) that call methods on Java code (?) with a `.-`<p>Or atoms defined with @ and dereferenced with *<p>Or the { :key value } structure<p>There's way more syntax (or things that can be perceived as syntax, especially to beginners) in Clojure than the articles pretend there is.<p><pre><code> (defn ^:export db_with [db entities]
(d/db-with db (entities->clj entities)))
(defn entity-db
"Returns a db that entity was created from."
[^Entity entity]
{:pre [(de/entity? entity)]}
(.-db entity))
(defn ^:after-load ^:export refresh []
(let [mount (js/document.querySelector ".mount")
comp (if (editor.debug/debug?)
(editor.debug/ui editor)
(do
(when (nil? @*post)
(reset! *post (-> (.getAttribute mount "data") (edn/read-string))))
(editor *post)))]
(rum/mount comp mount)))</code></pre>
> An incoming HTTP request? it is a plain Clojure dictionary.<p>I learned to code in Python. Loved it. Dynamically typed dicts up the wazoo!<p>Then I learned why I prefer actual types. Because then when I read code, I don't have to read the code that populates the dicts to understand what fields exist.
Walmart Labs was a step in this direction.. but we need some big companies to standardize around Clojure to jumpstart the ecosystem of knowledge, libraries, talent, etc. I’ve spoken to engineering hiring managers at fairly big companies and they’re not willing to shift to a niche language based only on technical merits but without a strong ecosystem.<p>If we don’t get some big companies to take on this roll the language is going nowhere.<p>I’m saying this because I’m a huge fan of Clojure (as a syntax and language, not crazy about the runtime characteristics) and I hope I get the opportunity to use it.
I started working professionally with Clojure earlier this year and this article rings true. I think the article leaves out a fourth downside to running on the JVM: cryptic stack traces. Clojure will often throw Java errors when you do something wrong in Clojure. It's a bit of a pain to reason about what part of your Clojure code this Java error relates to, especially when just starting out.
Another good report about what Clojure does well is this article by metabase: <a href="https://medium.com/@metabase/why-we-picked-clojure-448bf759dc83" rel="nofollow">https://medium.com/@metabase/why-we-picked-clojure-448bf759d...</a><p>I have had the pleasure of contributing to their code since we used their product at a previous company I worked at, and I must say I am sold on Clojure. Definitely a great language to have in your toolbox.
> We tried VisualVM but since Clojure memory consists mostly of primitives (Strings, Integers etc) it was very hard to understand which data of the application is being accumulated and why.<p>You should try deeper profiling tools like JFR+JMC (<a href="http://jdk.java.net/jmc/8/" rel="nofollow">http://jdk.java.net/jmc/8/</a>) and MAT (<a href="https://www.eclipse.org/mat/" rel="nofollow">https://www.eclipse.org/mat/</a>).
I tried to use Clojure but what put me of was that simple mistakes like missing argument or wrongly closed bracket didn't alert me until I tried running the program and then gave me just some java stack spat out by jvm running Clojure compiler on my program.<p>It didn't feel like a first class experience.
Being able to keep track of what data was where is the initial bump I had as well when learning Clojure. Unlike the author, I personally got used to it, and generally don't struggle with it anymore, but part of that is learning good habits on your code base where you make judicious use of names, doc-string, destructuring and have a well defined data model using records or Spec or Schema, etc.<p>The other one is just getting good at the REPL and inspecting the implementation for functions to quickly see what keys and all they make use of.<p>Something the article didn't really cover either is that it's not really the lack of static type checking that's the real culprit, its the data-oriented style of programming that is. If you modeled your data with generic data-structures even in Haskell, Java, C# or any other statically typed language, you'd have the same issue.<p>If Clojure used abstract data-types (ADTs) like is often the case in statically typed languages, things would already be simpler.<p><pre><code> (defrecord Name [first middle last])
(defn greet
[{:keys [first middle last]
:as name}]
(assert (instance? Name name))
(println "Hello" first middle last))
(greet (->Name "John" "Bobby" "Doe"))
</code></pre>
This is how other languages work, all "entities" are created as ADTs, it has pros/cons off course, which is why Clojure tend to favour the data-oriented approach where you'd just do:<p><pre><code> (defn greet
[{:keys [first middle last]
:as name}]
(println "Hello" first middle last))
</code></pre>
But as you see, this makes it harder to know what a Name is and what's possibly available on it.
Great article, love Clojure, unfortunately couldn't find any work with it when I tried, I managed to flop in the only interview I got :(
Still, I miss it sometimes when I'm writing C#.
Great article, love Clojure. Was trying to figure out what Nanit does. Might want to consider putting a link to the Nanit homepage on your engineering page. When just typed in nanit.com and saw the baby monitor tech, I thought maybe I went to the wrong place, until I saw the logos matched. Anyway, good read, but please put a link to your home page on your engineering site, or, put a 1 liner in the opening of your blog giving context to what your company does.
> Pure functions make code design easier: In fact, there’s very little design to be done when your codebase consists mostly of pure functions.<p>Ummm... I am a little bit fearful about your codebase.<p>If you don't see the need for designing your FP system it probably mostly means it is being designed ad hoc rather than explicitly.<p>If you are trying to compare to OOP system done right, you will notice that this includes a lot of work in identifying domain model of your problem, discovering names for various things your application operates on, and so on. Just because you elect to not do all of this doesn't mean the problem vanishes, it most likely is just shifted to some form of technical debt.<p>> Clojure is a dynamic language which has its advantages but not once I stumbled upon a function that received a dictionary argument and I found myself spending a lot of time to find out what keys it holds.<p>Dynamic typing is a tradeoff which you have to be very keenly aware of if you want to design a non-trivial system in a dynamically typed language.<p>It is not a problem with Clojure, it is just a property of all dynamically-typed languages.
> ... and the question regarding choosing Clojure as our main programming language rose over and over again<p>If I find myself having to repeat myself justifying a certain decision time and time again, it's an indicator that the decision needs to be revised to be something which is a more intuitive fit for the organization.