September 4, 2026

Writing a Minecraft server in Clojure: it was fun (via)

This is a cool example of the kind of problem that Clojure makes so much simpler to solve. Having a coherent model of time and not sharing mutable state makes parallel computing so much easier, because you’re not trying to coordinate multiple mutators contending for a shared resource. If you just don’t share the resource and let the language level primitives handle serializing operations for you, you can stop worrying about entire classes of bugs and just focus on your problems.

The ideas parallel servers reinvent by hand - immutable snapshot, pure read phase, changes as data - are the language's defaults. If writing from many threads is difficult, then don't write: all game logic is pure functions (fn [world events]) that read the snapshot in parallel and return changes as deltas, merged in one place. The merge preserves order, so the parallel run is bit identical to the sequential one, and no mechanic cares how many cores it runs on.

I think it’s so cool when people experience the benefits of Clojure’s paradigm in real projects. It’s often a tough sell at first but it really is amazing how far you can get with pure functions operating on immutable data. My favourite way to fix bugs is to just make them impossible by default, which often means rethinking the way your program models the world and time. It can be a bit trippy at first but it pays off.

link#clojure#concurrency#functional-programming#immutability#software-development

January 29, 2026

Spec-ulation

I've been thinking about versioning (for work) lately and I'm reminded of Rich Hickey's take on it from his Spec-ulation talk. The gist of it is that it’s more useful to think in terms of breakages and accretions as opposed to the more vague notion of “versions”. He (perhaps controversially) suggests that breaking changes should just be considered new things, the concept of having a new “version” of something that is not compatible with the old one is incoherent if you think about it.

link#change-management#clojure#spec#versioning

January 16, 2025

core.async.flow (via)

Rich Hickey just pushed a new namespace to the core.async library that looks really interesting. The accompanying rationale explains what it's all about in simpler terms than the code, but it feels like a big step forward in making core.async more intuitive to use. Channels are a super useful abstraction, but as the rationale explains, they are still a relatively low-level construct that require expertise and good architectural decisions to use well. This new namespace provides some more abstractions on top of channels that handle, among other things, "all channel I/O, thread lifecycle and coordination with the flow graph". This seems very powerful.

These are very high-level abstractions over an entire system, but I often wonder if this is just the inevitable direction in which software is headed. As we come to understand software systems better and better, and as the tools for generating implementations of solutions to known problems become better and better, it seems like this shift toward ever higher-level abstractions is the natural outcome.

It reminds me a bit of what Hyperfiddle is doing with electric Clojure, abstracting over the entire network, not just the "front" or "back" end of a web app. It's a totally different domain, but similar in that it feels like an impossibly high level to develop at, yet it appears to work very well. I'm excited to out both of these.

link#clojure#core-async#rich-hickey