Bringing Clojure programming to Enterprise (2021)(blogit.michelin.io) |
Bringing Clojure programming to Enterprise (2021)(blogit.michelin.io) |
They seem to have a very good use case for Clojure adoption. The article mentions many of the affordances Clojure gives you for data oriented, information processing problems.
But one of the unsung heroes of Clojure is the namespaced keyword:
If you’re already working in a FP, data oriented style but in a language that doesn’t have them, I recommend you have a go with Clojure and explore them.
It’s such a simple construct that gives you a lot of leverage in terms of semantics, code organization, flexibility and validation.
Think of them as having characteristics of uuids, URLs, URNs etc. they stand on their own and have meaning across system boundaries.
It’s very nice and calming to have that in-built as an everyday construct.
Sounds intriguing, can you say more?
I think an illustrative example would be this repo:
https://github.com/cognitect-labs/anomalies
These are basically re-usable, namespaced keywords. You might decide to use them or something similar in your program/system and some people do. Pretty neat: Their semantics are documented in the readme and the little bit of code in the repo defines a spec here https://github.com/cognitect-labs/anomalies/blob/master/src/....
You can read it as: any map that has these keywords as defined in the spec is an "anomaly".
Specs are open, non-exclusive so you can add more stuff to your structure and they still conform. (Note that the double colon before the keywords just mean "the current namespace defined at the top".)
Note that you don't need to define a spec for namespaced keywords. It's just a utility that leverages them. By themselves they already say "I can be used in a global context".
---
These keywords can be used from anywhere and by themselves. You don't need to carry around their context for them to work or have meaning. To contrast: for example a JSON field in a nested context might only make sense in that specific nesting context. Clojure namespaces are by convention globally unique.
Some examples:
- `:my.domain.accounting/refnumber`
- `:my.domain.ui/color` defined as `(or :my.domain.ui/rgb :my.domain.ui/hsl)` etc.
- `:my.domain.person/name` defined as a string if at all
- `:my.domain.event/type`
The same author also publish a introductory article about datalog. Check it out!
Can you expand more on how the business rules are executed with the variable ? Maybe a simple example ? Clojure-newbie looking to learn more :)
when X then do Y
You can write them in Clojure like in the above example: [:rule [:when X] [:then Y]]
which is kind of self-explanatory. X and Y can be any valid predefined expressions, e.g. [:rule [:when [:< amount 100]] [:then [:send-email-to-boss]]]
If you had such a rule, you'd just parse that line as edn, substitute all symbols (check for injection attacks) and execute it.However, effectively clojure itself is most often the smallest representation:
(when (< amount 100) (send-email-to-boss))
It's just not that readable because it's missing the "then", but it would be valid clojure right away.In the end it's like a code snippet that non-developers can write without having to set up a compiler, run-time, syntax-checker
Only extension being I applied the momentum boost to bootstrapping a startup and escaped the enterprise world entirely (other than sales back to that world).
Good times, lots of programming. A++ would buy again.
So with Clojure you get ClojureScript and "shell" scripts too now!
I don't know if things have improved but back then everything felt either a WIP or obsolete. You wanna use lein to build but apparently that's ancient and you really should be using this other build tool that's not fully integrated with any editor other than emacs and hey while you are at it the Clojure team has released their own dependency management tool and you really should be using that instead. By the way who uses intellij when there is VS Code?
Clojure boasts about it's strong Java interop and ability to use the existing Java ecosystem but it has one of the worst intellij integrations, using a 3rd party plugin that is either broken or not working with your build tooling.
Oh did you say you wanna use Gradle or Maven to build your Clojure stuff? You could actually do it, funny guy.
The language is probably the most practical lisp out there, but it also brings all the artificial lisp superiority syndrome with it (and forces you into submitting the rest of your life to emacs in praise of lisp culture).
You think you'll pick it up quickly and be productive but juggling between learning all the build tooling, the language itself, editing lisp and integrating all those 1-man libraries that are scattered all over github, you end up losing weeks if not months on fixing boilerplate.
I would give it another go but now that I think about debugging a Clojure app in runtime and making sense of a reflection-based, dynamic language on top of JVM, I'm like naaah I already have enough stress-induced grey hairs...
Haskell gives me the pure functional kick that I want, and the rest I can deal with in Kotlin or even Java 11.
You have to export the code to make it callable, and I had to write some adapters on the Kotlin end. But very doable for integrating if you need to.
This code is quite specific, but you get the idea. Export symbols:
https://gitlab.com/crossref/rest_api/-/blob/main/src/cayenne...
Convert Clojure structures to Kotlin classes:
https://gitlab.com/crossref/manifold/-/blob/main/src/main/ko...
Mostly, people using Clojure want. to get away from Java.
I understand that, but Spring Boot already offers support for Koltin (yikes) and Groovy (double-yikes). Would supporting Clojure templates that use the underlying Java classes be difficult or cumbersome? Would it yield Clojure code that's not idiomatic?
I don't mind the underlying tooling that much, but I'd love to be able to use a more elegant language for the business logic.
I've added Clojure to several legacy Spring Boot apps, and the fact that it can be introduced as "just a library" made that portion a snap. If you're not trying to access resources related to Spring Boot's dependency injection, it's pretty straightforward to call into Clojure from Java. If you _do_ want access to DI resources, there's a small amount of code required to wire things up, though it took me a while to find out what that code was, mostly because it requires access to portions of Spring Boot that are not typically user-facing.
Since I had hooked Clojure up to the Spring apps, I also set things up so I could SSH onto application servers, then get a REPL via a socket server into the applications themselves. Being able to check and sometimes change the state of the application live at runtime was like a superpower. This proved extremely valuable, often for debugging errors in the Java portions of the code, but also for situations like final design tweaks live with a client in a development environment. Client asks to bump a font size or change a color or adjust a border or change some copy, then I make the change in my editor, send it over the socket REPL, tell the client to refresh, and repeat. When done, I would simply save, commit, and would be confident that it's what the client was after. The only downside is that I'm no longer at a shop that uses Clojure, and feedback loops for production debugging or letting clients see their decisions are measured in days or weeks when possible at all, not seconds or minutes.
I will admit that connecting to a running application is dangerous, but so is what many surgeons do, and we are certainly not going to ask them to turn in their scalpels. By being conscious of the "great power; great responsibility" bit, I was able to come out mishap-free.
On the other hand, when I had to create new projects where I thought Clojure would be a good fit, I just went all-in with the Clojure ecosystem rather than start with Spring Boot and add Clojure, and I found going all-in with Clojure to be incredibly productive. With that being said, I made the decisions with a decent understanding of both Spring Boot and Clojure, so my experience would likely vary from that of someone who is experienced with Spring Boot and knows nothing of Clojure.
It would do fine as part of a microservices architecture where some of the other services are Java/Spring. I've done exactly that in fact - wrote a few Clojure services to rip through and ingest some data as part of a system where we had Java/Spring and Python services mixed in.
If you're looking for a Java alternative in a "Spring Boot" shop, Kotlin has excellent Spring support and is definitely more pleasant to use than Java.
https://survey.stackoverflow.co/2022/#section-top-paying-tec...
I do python now :(
That sounded to me as if someone said: "I had gigs working as a crane operator, the problem is that working as a bricklayer pays better..."
Not only your statement is wrong, typically Clojure devs get paid more, but you're also missing the fact that these aren't comparable trades, on many facets.
On the contrary, Clojure was not focused on satisfying business managers, but on satisfying programmers. It's a good thing that it
also
suits business managament, but that's not its purpose.
- Very consistent, easy to keep the whole language in your head
- Stable, core rarely changes ("accretive only" mindset).
- REPL
- Focus on a handful of data structures which will solve 95% of the problems you face, rather than a deluge of complicated abstractions.
- Excellent concurrency primitives
- Access to Java libraries if a Clojure equivalent doesn't exist
- Macros
The only blemish for me was horrifically bad error messages.. other than that it's near perfect.Is that not all programming languages. Practically have identical syntax for the problem they are solving. The thing which differs is “standard” libraries, which is not part of the language but a side effect of.
But I think it's just general hackernews language waves. Someone posts something, it does well, other people get interested, find things post them and onwards.
When I started learning LISP+Clojure (yea ok purist Clojure might not be a perfect LISP or deserving of the name). There were a lot more Clojure tutorials and help out there than there was for CL (Common Lisp).
I usually start my new language journey by watching lots of Youtube tutorials, it gives you a broad-overview of landscape, before I dig into the code.
The other opinion why it's getting trendy again might be that, "the modern coding landscape" is not much "fun":S
Learning JavaScript(the modern guide), js-frameworks, Rust (yea it's good, but not fun).
Clojure is really fun :) Once you are used to an "interactive workflow" like evaluating and testing a function right then and there it's hard to go back to coding function in a file and running the whole program to test.
And I've said it in a few comments yesterday as well, anyone starting out with Clojure just tell yourself "It's Maps All The Way Down".
HN commenters love using anecdata. So please allow me to use one and speculate on this phenomenon. So we have a product. Three devs wrote the initial prototype. Then over time, they hired five more. For three years we've organically grown our codebase, adding more and more integrations. The business expanded and grew enormously. We had to deal with a lot of pain, trying to grapple with enormous amounts of data and constantly changing requirements. In addition to tons of back-end services, we also had to build three different web apps. The company had to hire two additional PMs and two more designers. But we've managed to hold the fort with the small team as we were. Occasionally, the question about hiring more devs would come up, and we interviewed people. A person one day left (for some fabulous offer) and we had to quickly hire a replacement. I no longer work there and they hired only two more after I left.
I mean, I can keep going with the story, but I think you get the gist of it. Clojure allows building enormously big operations with a handful of developers. I just can't imagine building and maintaining all that in other stacks. And as it turns out, even when we needed to add new product features, we didn't have to hire a new team for that. And the business was not restricted by the pace of our development. We continued adding new features and kept supporting the existing ones.
This is a very subjective example case, of course. But it makes me want to ask: if we didn't have to hire more developers, and I don't think I ever heard of any company massively trying to expand their Clojure teams, how would then Clojure grow? Is creating new Clojure-based startups the only answer?
Meanwhile, the OP is quietly using Cursive to get his work done. It’s used in the screenshots.
(Disclaimer, I develop Cursive)
You can model a lot of problems similarly to clojure. you get immutable structures, agents and a very freestyle ecosystem for getting things done while havign enough opinions laid down to be able to get started pretty quickly
[1] https://lfe.io/
I giggled at this. Regularly, and in this thread, whenever some DSL req or LISP is mentioned you get these holier than thou comments about how LISP is the best thing since sliced tomatoes.. similarly with diehard vim/emacs users.
"I tried looking at Clojure code once, around 2015, and I wish I went blind..."
They can't live knowing that many people enjoy writing Clojure. This dystopian world makes them feel really sad. "These schmucks don't even know how miserable their days are. I need to tell them that they are so damn wrong, and maybe I can heal their heresy and fallacious excitement..."
People get excited about Clojure not because it has a cool logo or because of Rich Hickey's terrific hairstyle. There are many good, objective reasons why they like it and prefer it to other tools. Because of those objective reasons, Clojure is used in big corporations and small startups.
Usually, there's nothing wrong with excitement about a good tool you like. Almost always, everything is wrong with hating a tool and hating people who like it.
Very interesting, as something along these lines is a direction I've been meaning to extend Polymorphic Identifiers, both to have partial trailing paths and also to have bundles of paths that can be treated a bit like a data structure, but without actually being one.
Honestly this is probably part of the reason Clojure jobs can pay less.
Not very accurate use at all, the whole sector has actually more a social science than a hard sciences bend. Information is a very culturally defined concept and the silicon tech and the true white coat engineers designing and making chips a very small fraction of what happens (or gets discussed).
This is probably title inflation that makes people feel better. The same dynamic that created "Data Science" to mean data cleaning, and AI to mean statistical fitting. But in Rome like the Romans :-)
I started a company that deals primarily with "cyber-physical systems" use cases in-part because I ceased to find anything remotely resembling "software for its own sake" to be compelling anymore (in an existential sense).
Also, if you do happen to work in solar farm tech, I'd love to chat. nathan@auxon.io
- First couple of screenfuls worth of HN Algolia search stories by date covers 7 months of scala, vs 3 months of Cloure stories - score 1 for cloure
- on Lobsters, 2 pages of Clojure is 9 months, for Scala 3 years - score 1 for clojure
- in StackOverflow dev survey, Scala respondent count is ~50% higher than Clojure (~1800 vs ~1200) - though Clojure is "loved" significantly more. Score 1 for Scala.
I'll admit it seems more of a draw than I thought and you could reasonably weight the SO case a bit more than the first 2...
But most shops using Java would be resistant to adopting a whole new language, especially an audacious lispy language.
So Clojure worked really hard on having good interop support for Java, which meant you could adopt it incrementally into an existing JVM codebase; you don't have to do a ground-up rewrite (scary to cost-cutting stakeholders)
It also meant they didn't have to bootstrap a fresh, immature library ecosystem from scratch (also scary to stakeholders)
They took a very practical approach that acknowledged the existing landscape and introduced idealism into it, instead of trying to create a whole new, blessed island that nobody would ever visit outside of hobby projects. Which is the same thing other successful new languages have done- Kotlin (also with Java), Rust (with C/C++), Zig (with C), TypeScript (with JavaScript).
I'm not sure further reference is needed, it just feels really obvious that this was the strategy. Of course Clojure can and has grown beyond just that use-case, but you need to get a foothold first.
I know it's anecdotal evidence but I'm doing Java right now because I couldn't find a Clojure job that pays nearly the same (and I already used Clojure for 5 years in production environment).
- functions
- classes
- list comprehensions
- generators
- inheritance
- operators
- string interpolation (a handful of syntaxes)
- module system hard to wrap your head around
- async (I think async is a workaround for getting more done with one thread because of the GIL). Pointless on machines with increasing number of cores. Just get multithreading right (and I want to learn Clojure's model - focusing on immutability) and you will not need async. Python can barely share memory across threads. I'm not sure you can get by without serialization.
Clojure is so much nicer to work with and this really resonates with me; I'm always still having to check language docs for C++ stuff but only very rarely for Clojure. Being able to keep almost all of it in my head is a huge benefit as I don't have to break my "flow" nearly as much.