top | item 43155224

(no title)

hlship | 1 year ago

I've been working in Clojure now for about 12 years. Maybe 12+ years of Java prior to that.

I've created some great apps, and great libraries (in both Clojure and Java).

I often describe Clojure as "the least worst programming language", which is an off-handed complement, but I think accurate. Things you don't like can generally be fixed (at least locally) using macros and libraries. The core is strong, a good basis for building things ... and as described all over this thread, stable.

As you master your tools, you gain a level of speed and precision in your work that I have not found elsewhere. The REPL-oriented workflow is a central value proposition in Clojure, and many features (and a few limitations) of the language exist to properly support it.

Working in Clojure feels like I'm working "with" my code, molding it like clay. My prior experiences in Java and Objective-C were so much slower, with long code-compile-test-debug cycles that are compressed down to instantaneous responses in the running REPL.

discuss

order

nogridbag|1 year ago

I gave Clojure a shot some years ago and even wrote an important tool used daily by all employees at our company in Clojure. The problem for me was maintenance. If I had to make any change to that code, I had to dive into the REPL just to understand it. Whereas with something like Java, even if something is poorly written and not documented, I can get at least a minimum understanding of the code just looking at the types.

I've been working on a large modern Java application lately and have never really felt the need for a REPL workflow even after having been exposed to it in Clojure. I tend to structure my Java code so it can be easily unit-testable and then just run the suite of unit tests (several thousand) in a few seconds as needed.

lucyjojo|1 year ago

maintained a few clojure code bases at my old company for 10+ years

i find core.spec did wonders for that problem.

also, i have a tendency to write a lot of in-code documentation, whichever language i use. so it probably helps too.

incangold|1 year ago

Built a significant system in Clojure (from several smaller systems). Same experience.

I wish Hickey had built gradual typing in to the language.

I still love Clojure anyway.

nathan_compton|1 year ago

What about core.typed. I find gradual type systems to be hard to work with for some reason.

xigoi|1 year ago

> Things you don't like can generally be fixed (at least locally) using macros and libraries.

What macro do I use to make it not run on the JVM? :)

erichocean|1 year ago

That's one of it's best features!

But it runs on other things—Microsoft's CLR, Dart's runtime, JavaScript's runtime, Erlang's runtime, and with Jank, on top of LLVM.

rootnod3|1 year ago

Haven't worked much in Clojure, but I have the same experience with Common Lisp. The malleability and live image workflow is just very pleasant to work with.

erichocean|1 year ago

Clojure is like that, but because data structures are default immutable, and all of the standard library (and the vast majority of 3rd party libraries) are also default immutable, the stress level is much lower.

You can still get mutability and I do this on every project. But it's a very small percentage of the code, less that 1%, and also well-defined.

Something like FlowStorm [0] isn't really practical in anything but Clojure, and things like Clerk [1] are easy and very natural.

[0] https://www.flow-storm.org/ [1] https://clerk.vision/

eddd-ddde|1 year ago

How does the REPL approach scale in very large codebases? I.e. code that talks to multiple services, complex configurations, etc..

huahaiy|1 year ago

Scales very well.

Immutable data pairs great with REPL.

Because data are immutable, you don't need to care about where that data come from and where it will go. Just focus on what you need to do with that data at the point you work.

Everything is localized due to immutability.

m1n1|1 year ago

I worked with a 60K LOC thing* that talked to multiple services and had complex configuration. Ran fine on my laptop pointed at the company's dev env.

The REPL let me test my changes while inside the thing as it ran. No problems. Someone wrote a nice *recording* debugger too which helped immensely -- no more "oops, I'm past the interesting part and have to start over"

* in prod we usually give it a small number of large instances

thom|1 year ago

I use Integrant to make systems out of components that are tied together at runtime. I have the option of running real versions or mock versions in tests or the REPL, with config drawn from the environment or config files or parameters. I can boot or reboot any combination of components at will. It’s fairly easy to divide and conquer this way.

ludston|1 year ago

Even better than in small ones, because you don't need to spend 60 seconds building and restarting the application after changing one line: You simply redefine a single function at runtime and them can test the effect immediately.

gavmor|1 year ago

I played with Clojure just a bit in 2014 because I wanted to write GUIs in Om, and this gave me a seriously warped habit of calling React.el('div',...) for a while. Sorry not sorry.

I'm used to using TDD for fast feedback as I'm molding my code. Do you miss unit testing? Or, do you find that the REPL in no way obviates unit testing?

And, do you miss static typing?

huahaiy|1 year ago

REPL code is copy/pasted straight into tests. So really, REPL is for helping write tests.

BTW, when Clojurians talk about REPL, it's not about that separate window where you type and run the code as in other language such as python. They are talking about an invisible REPL running behind the scene, to which they send code within their editors, and the results show up in the editors too.

There's no need to "miss static typing" in Clojure. If I need static typing, I just write deprotocol and deftype in Clojure, as many Clojure libraries do.

eigenhombre|1 year ago

Not the OP but:

One can develop with TDD in Clojure quite smoothly depending on choice of tooling; with CIDER in Emacs there are keyboard shortcuts to run tests for the current namespace or the entire project, so feedback can be very fast (if your tests are fast). I've also used (some time ago) test runners that stay running and re-test when a file is saved.

In fact, it can be nice to do one's explorations in the REPL and then reify one's discoveries as tests.

Regarding types: I will say that working on larger Clojure (and Python) projects with somewhat junior teams made me more curious about type systems. Clojure's immutable collections and the core abstractions they are built around are great, but it can take some skill and discipline to keep track of exactly what kind of data is flowing through any particular part of your program. But, there is some support for à la carte strictness in the language via Spec, Malli, structured types, etc.

perrygeo|1 year ago

I picked up Clojure recently after a 10 year hiatus. My early complaints were around tooling - a Lisp-specific IDE felt all but required to get the benefits of the REPL and structural editing. And leiningen, god how I despise that tool.

With clojure-lsp, deps.edn, and more REPL tooling (conjure in neovim in my case), the situation is better now. I find myself reaching for Clojure for almost everything these days - from scripting to data crunching to quick web apps to database work. Clojure is an amazing tool once you grok it - closest thing to a super-power we can get.

> working "with" my code, molding it like clay

This the best description. Clojure feels very fun/interactive but simultaneously feels rock solid for production work. There is no gap between "notebook" and "prod". Zero compromises. Most other languages pick one or the other (Python - interactive but plagued by runtime errors, Rust - rock solid but clunky to iterate and experiment)

pjmlp|1 year ago

Not the same thing, but having something like JRebel can get quite close, and even if jshell isn't the best example of REPL, it isn't that bad either.

Byamarro|1 year ago

Maybe I miss what REPL really is, but...

If REPL is the main value proposition, how is it better from average JavaScript development? Dev tools allow you to basically interactively work with your code.

daslu|1 year ago

One important detail is that in Lisps like Clojure, printed values can usually be read back as code. So, the REPL is really a read-eval-print-LOOP.

Another detail is that the whole culture of the language, oriented towards immutable data, makes it very easy to evaluate almost any sub-expression in your code, which makes the whole code introspectable in a very playful and dynamic way.

cutler|1 year ago

It's totally different. The R in REPL retains its original reference to the Lisp READer which is special when your code is structured as an AST as in all Lisps. Only in Lisps can you select the left paren of a deeply nested function and hit Eval. Other language REPLs are really just shells by comparison.

cess11|1 year ago

You can keep a JVM running in the background with your project loaded and send stuff there from your IDE/editor.

I don't think this is possible with JavaScript.

barrenko|1 year ago

"...not as clumsy or random as AI, an elegant weapon from a more civilized age."