21 ms·
Six years of professional Clojure development
- tigroferoce 5y agoI also had the privilege to work with clojure for a couple of years on a large project. That was wonderful. Hands down the best language/framework/approach to development I’ve ever had. I still find crazy that it’s not one of the main programming language out there.
- rychco 5y agoUnfortunately, despite consistently hearing about how enjoyable Clojure is, I think many people are turned off by the JVM. This is probably also the problem with Scala, which is apparently also enjoyable to use.
- cyberscientist 5y agoWhy is the JVM a turn off?
- atraac 5y agoI don't think JVM is what turns people off. It's a different paradigm. Every FP language is basically a niche these days even though you can hear great things about most of them(Elixir? Elm? Clojure? F#?). It's just that FP is not popular/common enough for these languages to be popularized like some other OO languages.
- theonething 5y agoElixir seems to be pretty popular here on HN these days.
- joelbluminator 5y agoHN is not a good representation of the programming world at all.
- disgruntledphd2 5y agoIt does tell you what legacy code bases you'll be maintaining in ten years though ;)
- pjmlp 5y agoJVM and .NET are the top runtimes with best in game GC implementatios, JIT compilers, JIT code cache, and monitoring tools for production code. In fact plenty of them, given that there are multiple implementation to choose from. Meanwhile other languages keep playing catchup and having to rewrite extensions in C.
- yakubin 5y agoYour comment prompted me to google for those tools once more. One that I did not know about before is Eclipse Memory Analyzer. The screenshots[1] look promising, especially "Path to GC Roots". I didn't know that was possible. Is there something comparable for .NET? [1]: <https://www.eclipse.org/mat/about/screenshots.php https://www.eclipse.org/mat/about/screenshots.php> EDIT: A bit more googling and I found <https://memprofiler.com/ https://memprofiler.com/> for .NET which seems to have a similar feature, called "Instance Graph".
- pjmlp 5y agoEclipse Memory Analyzer is quite good, but something like Java Flight Recorder is much more capable. On the .NET side of the fence, you can have a look into this nice article although a bit old, https://mattwarren.org/2018/08/21/Monitoring-and-Observability-in-the-.NET-Runtime/ https://mattwarren.org/2018/08/21/Monitoring-and-Observabili... and "ETW - Monitor Anything, Anytime, Anywhere" https://www.youtube.com/watch?v=ZNdpLM4uIpw https://www.youtube.com/watch?v=ZNdpLM4uIpw
- thomastjeffery 5y agoThe runtimes themselves may be great, but the tooling is bloated and uncomfortable. Every time I use Clojure, I am reminded how much I hate using Java. The error messages alone are enough to turn me away. So is having to set up a whole Leiningen project just to get started. A Clojure without Java would be very attractive to me.
- pjmlp 5y agoThere is nothing else that gets close to the world promised to us by Xerox PARC. Don't blame Java for the issues that are Clojure's fault. The only Lisps that can match such tooling are Allegro and LispWorks.
- 331c8c71 5y agoScala can be enjoyable but can be a major pain as well. Look no further than the de-facto standard build tool (sbt).
- serpix 5y agoas both a Scala and Clojure polyglot I would pick Clojure over Scala every single time, the Clojure REPL development style alone puts Scala behind. Scala and SBT is a nightmare, I don't want to touch it ever again. With Clojure you are done before Intellij has even rebuilt your indexes /s.
- snotrockets 5y agoThe JVM is best in class, and has great ecosystem (with some noteable omissions). Scala is a different beast: modern Java negates the need for a lot of it, and the community tolerance and support for bigots and abusers justifiably distances many.
- dkersten 5y agoThe JVM is a blessing and a curse. I believe it was a very good decision and that Clojure wouldn't have become as useful or popular as it is without it, because it provided immediate and quick access to a huge ecosystem, allowing it to be productive and useful right away. But its also hindering further adoption and may be part of what caused a bit of a decline in interest, which for an already niche language, doesn't help. Many people are turned off the JVM. I personally don't mind it and I love Clojure, but even I have been wondering whether I should port some services to something else because I've had to use larger cloud instances for them simply due to memory requirements... Maybe I can run them on node with Clojurescript instead, I'll have to investigate that, but I think I'll lose out on a ton of libraries that I use that rely on the JVM. Hmm.
- stanislavb 5y agoAccording to LibHunt's popularity index, it's the 28th most popular language https://www.libhunt.com/index#clojure https://www.libhunt.com/index#clojure (ahead of Elixir that is 40th). It is less than 50th position on Tiobe's index https://www.tiobe.com/tiobe-index/ https://www.tiobe.com/tiobe-index/ (which is a bit more reputable than LibHunt's)
- iainctduncan 5y agoYeah but does any programmer actually believe these indices? I have yet to see one with a prelude where they defined "popular" in a way that would make anyone with a passing knowledge of stats happy.
- lukashrb 5y agoNice article. Sadly a lot of people won't even try clojure since it is dynamic typed. I see their point but nevertheless clojure does something really well here. As the author obserserves designing around some core data structures results in high code reuse. A library like spec is also way better in encoding business requirements than all the mainstream language typesystems e.g. a number in business context has mostly constraints like a particular range etc. I really looking forward to see someone come up with a static type system inspired by clojure's approach.
- joelbluminator 5y agoI don't think it's about it's dynamicism but more about it being functional. Plenty of super popular dynamic languages out there. I think that's also what keeps elixir from becoming something more mainstream, most people come from OOP and are used to thinking about programming that way.
- capableweb 5y agoBoth of you miss the most obvious difference between Clojure and all mainstream languages: it's a lisp. I've had so many programmers look at code I write and proclaim: "wow that looks impossible because of the parenthesis" and that would never touch anything like it because it seems so different. Some people do take the time to learn how it works, but many just have a knee-jerk reaction to it and then forget about the language itself.
- joelbluminator 5y agoCan you blame them though? Look at Python/Ruby where even non developers can sometimes understand the code and then look at some crazy Haskell/Lisp expression.
- capableweb 5y agoYes, I do blame them for this because if you spend 10 minutes, any programmer can learn "some crazy lisp expressions" because they are not that crazy. This knee-jerk reaction you're having is exactly the ones I'm talking about :)
- simongray 5y ago> *Reusability*: Here's where Clojure really shines. Because most functions are pure and operate on few common data structures (mostly maps, vectors and sets) it is very easy to write reusable code. We created many internal libraries just by separating the candidate functions into their own namespaces within the regular project source tree. To finally establish the library we move the code from the project repo into a new Git repo and include the resulting library Jar in the project.clj as dependency. Thus, we have a very lean process that results in production-quality resusable assets. This is very true. Data-orientation really helps with reuse and library composibility. The ability to reference git repos in the deps.edn file further supports this process. I don't particularly like the ergonomics of the Clojure CLI, though, but having this feature is pretty great. I use it all the time.
- YuukiRey 5y agoClojure is the most enjoyable language I've ever used and I love the interactive development. I haven't written code in any other language that even comes close. Unfortunately I am too lazy and careless to use Clojure in any serious capacity though. I really need a Haskell or Rust compiler to remind me of all my silly mistakes. I can't be trusted to get to the same level of confidence through unit tests or linting or spec or malli. I actually tried using Clojure for a little web project (~3k LoC in both Haskell and Clojure) and any refactor that included maps that were passed around in many different routes (think authorization, logging, DB) ended up with me chasing down rather weird type errors. Basically the equivalent of can't call X on undefined in JS. In Haskell I spent at least the same amount of time trying to make various monads play nicely together. Think using IO, Maybe, Either, etc. in the same route handler without having your code be indented ever further to the right. But the difference is that once I've invested that time I'm very confident in my code, whereas in Clojure there's always this lingering sense of impending doom because surely there's some code path that I haven't thought about.
- draklor40 5y agoI wrote Clojure for 4 years. I understand your pain points. Dynamic types are an impediment beyond a certain code size.
- praptak 5y agoMy experience with dynamic types comes from developing in Python. The projects I've seen were pretty healthy until a large enough part of the original team went away. Once enough people had to figure out their way by experimenting, the projects got messy. I'm not saying this doesn't happen in Java or Go but the static typing enables easier code exploration. That makes code bases more readable to newcomers.
- kaliszad 5y agoThat might be true but good variable names and some terse but to the point comments are much more helpful in my experience.
- jeofken 5y agoI 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.
- smackeyacky 5y agoLost me at "the promise of purity". Nobody wants to deal with high priests, just get the job done!
- capableweb 5y agoThat's... exactly the point of that section. You should continue reading the part right after the section title you mentioned.
- smackeyacky 5y agoWell, no not really. They started with the conclusion that being a clojure geek is cool and then try to post justify it. Good programming practice isn't a language feature its a programmer feature.
- comma_at 5y ago> Good programming practice isn't a language feature its a programmer feature. I'll enjoy reading your production-grade brainfuck code. A language's built-ins and idioms greatly influence what you say and how you say it. If your mother tongue doesn't have words to describe any emotions you'll have a hard time explaining them. You're talking only about the other side of the coin. Yes, people can write terrible clojure code, you need to be a good programmer to write good code. But please consider rewriting this bash one-liner in pure C (or assembly) grep FOO */* | wc -l Having a language to express your domain concisely is essential in reducing code complexity, time-to-market, bugs etc.
- smackeyacky 5y agoDo you really think referencing brainfuck, a deliberately difficult language, is the right way to get your point across?
- capableweb 5y ago> > > Good programming practice isn't a language feature its a programmer feature. > > I'll enjoy reading your production-grade brainfuck code. > Do you really think referencing brainfuck, a deliberately difficult language, is the right way to get your point across? I'm gonna assume you're not deliberately missing the point here and the confusion is genuine. You were initially indirectly saying that "it doesn't matter what language you use, how the program ends up is 100% to the developer" The other person made a joke/insight about that, since you think so, you should be able to write a program ready for production in Brainfuck, since your point was that the language doesn't matter. Obviously, anything but Brainfuck would make it easier to both write and understand, therefore your point seems to not be 100% true, at least always. The main point is not about Brainfuck, it's just an example. The point is about that the programming language _does_ matter, as well as the skill of the developer.
- igarcia 5y agoVery nice post! I wonder why the article date is in the future (10th May 2021)? :P
- borishn 5y agoI wonder if the company's success is not because Clojure is a marvelous language for building systems, but because Clojure is a marvelous people filter?
- truth_seeker 5y agoWhy is everyone making a big deal out of dynamic nature of Clojure as the main factor to not consider it in enterprise project ? As if no dynamic language has ever succeeded in creating enterprise application which runs 24X7 !!! If you don't like maps use clojure records If you don't want free floating initiation or ambiguous variables and arguments to function in code, use type hints. Type hints may not be exact alternative but are good enough help in reading the code and especially compiling the code to native graal image or just providing enough information to JIT for optimization. Use spec for generative testing and more detailed documentation. Irrespective of the language you use, tests are much important than types. Types help but they are not commandments. Multithreading capabilities in clojure through standard library primitives exposed to achieve it are much better and safer than java. For most of us, cost of immutable data structure is pretty reasonable. But if you think it's not the case, clojure provides mutable alternatives. Use components like library to large code in depedancy inversion oriented style, if thats what you like. Personally I prefered dynamic dispatch through multimethods when I used to work in clojure 4 years back. You can always get the library to do your job in the clojure ecosystem. If you don't find it, clojure provides easy integration with java libraries and you might be able to build a wrapper around it in couple of days if it is complex, in minutes otherwise. To compare Clojure with languages like Haskell and its features, Rust and its features is utterly naive. Instead development team must strive for what actually is needed for job. Flexibility and discipline provided by language compiler and library eco system will always strike some kind of trade-off. Clojure is good trade-off for most applications including mission critical soft realtime application category.
- galangalalgol 5y agoThe soft real-time interests me. Are there ways to avoid garbage as with java to minimize GC driven latency.
- truth_seeker 5y agoIt's very much possible, now more than ever. New JDKs provide more efficient version of garbage collector like epsilon for example. CMS can also do the job if you know few tricks. You don't have to be a big nerd to understand them. Documentation is pretty helpful. In my application I was able to get latency for http/rest services less than 15ms which also hit database more than once. Ofcourse it's very subjective to the business use case and networking infrastructure. YMMV If you really want me to pin point the issue, as far as GC on JVM heap is concerned only major difference with other language implementation was that I had to use around 1GB of extra RAM. All i am saying is that, start with idiomatic clojure. If that's not performant enough for you use case, start optimizing the code.
- clartaq 5y agoI've used Clojure for going on 10 years now and it has been one of the most enjoyable programming languages I've ever used. But I've gone back to Scheme for a few ridiculous reasons. 1. TCO. Using `recur` in Clojure just breaks my thought process. 2. Difficulty in getting down to the metal when needed. Using JNI is painful. In Scheme, when needed, the FFI usually handles plain old C. Much easier in my opinion. 3. Community. Rich is a really smart guy and has made great contributions, but he doesn't suffer fools lightly and I am a fool. Great for a scientist, not so much for a "benevelent dictator for life" of a programming language. 4. Pragmatism over correctness. There was a long running conflict about some set operations that did not return correct results. To my mind, there is no argument against correctness. 5. Slow startup. Not always a problem except when it is. 6. ClojureScript. Could be my unfamiliarity with ClojureScript/JavaScript, but I find I have to revert to JavaScript too often to get something done. And if I can't just use ClojureScript, why use ClojureScript? Like any Lisp, Scheme is easier to read than Python, Java, JavaScript, Haskell, PHP, Perl, Fortran, Forth, APL, etc. Pascal is pretty good in this regard though. Clojure might actually be better in my opinion. Why not Common Lisp? It's pretty good and at least as powerful. The warts annoy me though. So I will continue using Scheme while looking into Janet https://github.com/janet-lang/janet https://github.com/janet-lang/janet. Janet has most of the things I like about Scheme _and_ Clojure. More experience will tell. I just miss the way maps are handled in Clojure.
- iainctduncan 5y agoCurious, because I'm also doing Scheme now, and Clojure was my gateway drug, which Scheme are you using and for what sort of problem? I'm using s7, but that's because my use case is very much oriented to s7's non-typical feature set (it's computer music), but Janet looks really nice too. (Many similarities to both Clojure and s7 actually).
- clartaq 5y agoMostly Chez. Racket is remarkable too -- I have never felt that I was stretching its capabilities. Enjoying Janet, trying to get over Clojure habits where the two differ. Most of my career has been involved in medical diagnostic, data analysis, and desktop applications. Hobby projects include text processing, editors, outliners, wikis, and knowledge management.
- blunte 5y agoI really enjoy the language and even the look of it, and I have tried several times to use it. For "simple" scripts or server processes that you might call from cron, it was fine. But for web development, it was always so hard to get up and running - get everything configured and then know how to do things - that I always gave up. The Clojure community really values choosing libraries and tools and seems to echew Rails-like approaches. That's good if you know what you're doing, but it makes the cost of entry really high. And for better or worse, Ruby is a pretty nice language and Rails is pretty easy to get rolling with... so it's very difficult to justify the effort of switching. I want to... I really do. But at this point, unless I work for a shop like TFA, it will just never happen for me.
- claytn 5y agoI agree. I love using the language for smaller things, but since I don't use it at my day job it's really hard to get well acquainted with the common tooling/libraries. When I try starting a new project I always end up spending hours just getting my environment in a good state.
- afry1 5y agoI've had some difficulty getting a "basic" web server up and running too. Composing libraries together is a great way to build software, but when you're starting from such a low level with a new language where that kind of development style is the norm, it's a steep initial learning curve. Have you looked into Luminus? I haven't tried it yet, but it's supposed to be a Rails-like starter kit for web apps: https://luminusweb.com/ https://luminusweb.com/
- blunte 5y agoI actually did build something basic following the book Web Development With Clojure (https://github.com/jumarko/web-development-with-clojure https://github.com/jumarko/web-development-with-clojure), but honestly the way the code snippets were presented in the book were sometimes difficult to use if trying to follow along and build it yourself. I think you could probably get code from different chapters from their git repo, but then you're not doing it yourself - you are instead trying to read diffs to understand what's new and figure out why it has been changed. My experience has been that there is no complete guide, tutorial, or example that is kept current and provides every detail such that you can follow it and learn. I'm sure with enough concerted effort, one obviously can learn it... but there will be some trial and error and some guesswork. Normally that's fine, but it slows the process compared to other tech stacks and their guides. The Clojure community is nice and helpful, but they're all busy doing real work (rather than teaching). Even the book I mentioned is not yet complete and has been in progress for over two years I think.
- clusterhacks 5y agoFinding staff is an interesting negative of Clojure to mention. I searched for a Clojure job off-and-on for several years in the 2012-2018 timeframe. I had attended the very first Clojure/conj in 2010 and had development projects in production very soon after that - so I had some Clojure specific experience and was otherwise a reasonable candidate. My opinion was that there were far fewer opportunities than the inner core of the Clojure dev world admitted. This opinion seems very much not shared or mentioned by others. I also think that Clojure opportunities seem more limited now than a few years ago - Clojure seems to have become one of those programming languages listed on job descriptions but Clojure isn't actually part of the job. Never getting an offer from a Clojure-oriented job was kind of weird to me at the time because I did get lots of interviews outside of the Clojure world and pretty regular job offers from those. I never figured out why I couldn't catch an offer from a Clojure dev org.
- thebouv 5y agoIf I want to learn a new technology, that's been out a while, I make sure to look for jobs for it first. Just a gut check on how many opportunities are out there for it. This doesn't work for something brand new of course, but I still do a cursory look through job sites to see what I can see. Like for instance on Dice.com right now there are 60 jobs available. If I were interested in Clojure today and saw that, I probably wouldn't bother because I know Clojure is mature but there's not a market for it apparently. Again, this isn't meticulous or scientific at all, just a gut check with a few searches. Then again, Rust only has 13 jobs listed soooooo.....
- emidln 5y agoI posted a couple years ago about my experience finding Clojure jobs in 2018. https://news.ycombinator.com/item?id=20075132 https://news.ycombinator.com/item?id=20075132 I still have about 10 recruiters a week mail me about jobs relating to Clojure (either Clojure roles directly, or someone looking for a "functional" developer for another fringe language). It's unclear how many of these are the same handful of companies cycling recruiters (or with open reqs). At least in Chicago, it seems pretty straight-forward to get a job hacking Clojure if you have prior Clojure experience. The other alternative is bringing Clojure to an org. You solve problems and a lot of orgs honestly don't care about the details, particularly if you're in a silo or one of the only devs. This is harder to do in an established org that already has templates for specific things, unless that org is big into containers or microservices already. I've never been hired for a full-time job as a Clojure developer (although I've had offers), but I've put Clojure into production across three organizations.
- rcgorton 5y agoWhat about the required size of the Clojure VM? Source code size is only part of the picture. That is, if it takes 1Gb of interpreter/JIT to run 1K of Clojure, vs 1Mb of C code, Clojure is a BAD idea.
- agumonkey 5y agoAnybody here mixed code base between clojure and another language to have a concise / dynamic layer with some 'classic' statically typed modules underneath ? kotlin/java comes to mind due to JVM but maybe others.
- clartaq 5y agoJava and Clojure are probably pretty common. I sometimes use the Clojure numeric stack and Java (JavaFX) for the GUI portion of a program.
- metasoarous 5y agoThis is a great article, and I think does a great job of surveying the landscape as it stands. Particularly great to hear reports of ease in hiring and training, which doesn't surprise me, but is nice to be able to cite when risk-averse tech leads express concern about staffing and team-scaling. I find it somewhat funny that a lot of the critiques here are about purity or types. I really see it as Clojure's core strength that it's both pragmatic and approachable. I'm a math/alegbra nerd, so I love languages like Haskell & OCaml, but they're much more austere for the uninitiated, and have had their own troubles growing. From my experience, the approach of Clojure spec is really nice because it gives you more flexibility/freedom/support in both thinking at a high level about the design of your system (in spec code) before you actually write the (implementation) code itself, while also not requiring it, and letting you add after the fact. You also get a lot for it: generative testing, destructuring, documentation, etc. That having been said, I'm surprised that more of the pro-type folks here don't seem to be familiar with the [typed clojure](https://github.com/clojure/core.typed https://github.com/clojure/core.typed) project, which adds optional typing, along the lines of Racket's contract system. To me, it's one of the great testaments to the power of Lisp that you can fairly easily implement types on top of the core language. My one beef with this article is that scripting with Clojure is now not only possible, but a joy, thanks to GraalVM and [babashka](https://github.com/babashka/babashka https://github.com/babashka/babashka)! This has made a HUGE difference in the surface area of problems to which I'm able to apply Clojure.