4 ms·
I loved clojure until working with it for a few years, with some of the famous best teams in Europe and America, including Cognitect people, who ill leave unnam
by jeofken 5y ago
I loved clojure until working with it for a few years, with some of the famous best teams in Europe and America, including Cognitect people, who ill leave unnamed here.
I fell out of love when I realised what the language is - a mutable, imperative, blocking IO by default language with lambdas and zero guarantees at compile time. Effects happen at any time, as it is an imperative language. Just like JS with a better syntax but with blocking IO and Java threads.
Backends, when more than a handful coders program, turn to runtime checking all the time with spec or schema, and because it’s always up to you to make things async, things often end up depending on a handful of blocking calls. It’s not impossible to write good big programs in clojure, but when working with a group it does not tend to end up that way. Changing a program from sync to async with zero help from the compiler is a task that ends up requiring a lot of time, and negotiation, when it could’ve been the default.
In imperative languages, where you have no control over what effects run, programmers often turn to frameworks to square their program. In teams of >20ppl using clojure, it instead tends to become siloed, where a few people “own” a part of the code, and others must request changes there. It’s not a law of nature, but a pattern I’ve seen emerging in my experience working with clojure teams, including the very famous ones. Time spent negotiating and in these meetings is time wasted.
I should make sure to thank Clojure for getting me into lisp and emacs though, as well as Hickeys enlightening talks.
- cies 5y agoI really like Clojure and I'm glad it is around, but I'll prefer something with strong types any day. From the article I see a lot f reasons why: > "Don't break things!" is part of the culture. If you cannot have compile time guarantees on correctness, the discipline to not break things becomes a key feature. On the other hand, if you have strong correctness guarantees, you may more easily incur some breakage (and thus actually fix things). > Some discipline required [...] with great freedom comes great responsibility. There's always some discipline required, but without a type system discipline become more important. > you often need to find specific places where a function or a piece of data is referenced [which is hard in Clojure] because there are no links established via a type system. Yups. IDEs also like types to build their features on. > Documentation becomes more important I dont like documentation as a fix. Docs should tell me why some code is there, not what it does or how to use it (that is preferably obvious). Again: I like the language a lot. I also like Ruby a lot. But when a new project with serious complexity requires me to pick language I go with something that has: no implicit nulls, strong type safety, sum types, exhaustivity checks.
- joppy 5y agoIf you constantly work on the same code base day-in, day-out, breakage through the language or libraries is much less of an issue. You can keep up with current developments in the language and/or libraries, and update as necessary. Incremental changes are not a big deal, since you’re always around when they happen. If you tend to write code once, and come back to it months or years later, breakage is a huge issue - why is the code that was working perfectly well in 2019 broken today? Why do I have to now fix 4 dependencies in order to do what I actually wanted to do (make some small change). This is the reason that I tend to write all my own code in TypeScript projects, but for my Clojure/ClojureScript projects I am much more happy to pull in the occasional library. I would say that the “don’t break things” culture is less about static vs dynamic types, and more about the style of software being written and the maintenance expectations.
- cies 5y agoDont break things merely exaggerated as a requirement in dynamic typed langs.
- jeofken 5y agoIn real life projects, you end up doing type checking at runtime, meaning you also need a test for the code path
- comma_at 5y ago> If you cannot have compile time guarantees on correctness, the discipline to not break things becomes a key feature. On the other hand, if you have strong correctness guarantees, you may more easily incur some breakage (and thus actually fix things). Yes, and the result of that is cabal hell. Types aren't there to help you break your API. Once the API is out and it has users it is rude to break them. The linux kernel is a prime example how far can you get if you don't break your users.
- Kototama 5y agoWhat is mutable by default in Clojure? Nothing. You need to explicitly declare mutable variables with a special notation. Are you talking about the underlying VM? Yes, the Java API are mutable, not surprise here, it's not Haskell. Imperative? What is imperative by default in Clojure? Nothing. It's one of the least imperative Lisp, favoring functional constructs all over the place unlike Common Lisp or even Scheme. Blocking IO. Ok. So you want JavaScript? You have async i/o lib for Clojure and the primitive of the language to create threads are relatively good (relative because the limitations come from the Java VM). Zero guarantees at compile time. Almost true. It' s a dynamic language and does not pretend to be something else. It has pros and cons. Like modelling a domain is very simple since you almost always reuse the same datastructure and having ubiquious immutable datastructures build a solid foundation for an ecosystem of libraries.
- jeofken 5y ago> What is mutable by default in Clojure? Nothing. All data in Clojure inherits from java.lang.Object. I get what you’re saying, but in real life commercial projects, especially when you use libraries and Java classes, the code ends up with a lot of mutable things. You can never know if any function you call does mutate something without keeping all definitions in your head, and with 20+ people on the project, this is a challenge. Programmers of languages less sexy use frameworks to manage state and effects, but not in FP, which clojurians think they do. > Imperative? What is imperative by default in Clojure? Nothing. Please note that I’m not praising Common Lisp or Racket either - the same criticisms apply to them, except they ship with type systems. In Clojure IO is usually done by calling a function that does some (blocking) effect and returns something. That is programming in imperative style. In practice effectful functions find their way into programs, and taints everything referring to it. For this reason, clojure programs written by teams tend not to be as FP. > Blocking IO. Ok. So you want JavaScript? I for sure prefer to write a backend where no teammates ever introduce blocking calls. I once worked on a webpage which took minutes to render, because of blocking calls on the back end. It was a mess, after having been worked on for years by around 70 coders, including consultants for the biggest names in Clojurespace. > Zero guarantees at compile time. Almost true. Except for syntax errors. These things turned me off: imperative and blocking IO and effects and no square framework to contain it, combined with zero compile time checks. It results in teams making bespoke solutions that other teams in the company (or even consultants from the famous players in the Clojure space) solving their code needs by meeting with the authors and asking for changes, having a ton of testing to make sure it does not fail in rare code paths, and having one guy on every team religiously adding specs in order to not go mad.
- cutler 5y agoSo what is your preferred alternative/language/framework?
- jeofken 5y agoTypeScript+immutable is like typed clojure without S-expressions but with async io, so that is nice. Haven’t found a way to get eval-expr-at-point for js though. This is my choice for writing back ends today, but I also do Clojure jobs. I program compilers nowadays, and do so in OCaml, which is blocking IO, mutable data, and no sexpr, but the type system makes changing code easy. For the domain of compilers, there isn’t much IO anyways.
- pllbnk 5y agoI don't completely agree with all of the points but I am really glad that there are sensible critics of Clojure who don't position it as a perfect language. I have been working exclusively with Clojure for over 2 years now and I came from mostly C# background and I still want to pull my hair out every time I have to fix a bug which wouldn't have happened in a language with a good compiler. Same goes for asynchronous programming, which I think is generally lagging behind by many years in JVM world. Another issue I have is the lack of choice in quality third party libraries. A lot of them are created as wrappers over Java libraries and then abandoned and those that aren't usually lack in documentation and depth.