most read
Software Engineering
Why We Killed Our End-to-End Test Suite Sep 24
Software Engineering
The value of canonicity Oct 30
Culture & Values
The Spark Of Our Foundation: a letter from our founders Dec 9
Careers
We bring together great minds from diverse backgrounds who enable discussion and debate and enhance problem-solving.
Learn more about our careers



During his talk at Clojure South, Alex Miller, Principal Software Engineer at Nubank, addressed a problem that lies at the heart of every developer’s daily work: the painful ways we often handle data. Our industry is rife with fragile formats, objects laden with boilerplate code like getters and setters, and the ever-present complexities of mutable state that demand layer upon layer of protection. This friction isn’t just a technical debt; it’s a tax on our creativity and our joy.
Clojure offers a powerful alternative to this paradigm. It places simple, immutable data and pure functions at the very core of its philosophy. It’s a fundamentally different way of thinking about software rather than just a different syntax. By embracing this model, we can build cleaner, more mathematical, and incredibly powerful mental models. This approach, as Alex demonstrated, leads to systems that are not only more robust but also more joyful to create.
The journey to this simpler, more powerful way of programming begins by rethinking a word we use every day: “value.”
Back to basics: what truly is a “value”?
While programming involves manipulating various entities, Clojure’s power stems from a rigorous definition of ‘values.’ This distinction is far from a semantic triviality; it is the core design principle that gives the language its characteristic elegance. In this context, a value represents a specific category of data, defined by immutable properties that change how we reason about state.
According to Alex, for something to be considered a true value, it must possess four key characteristics:
This definition clarifies what is not a value. Things like network sockets, file handles, streams, and mutable objects fail this test.
They are processes or resources, not facts. A subtle but important distinction exists here: a file path can be treated as a value, as it is an immutable, precise description. A file handle, however, representing a live connection to a changing resource, cannot.
Embracing immutability for all values, including collections, has profound consequences that simplify system design immensely:
This design is not without its costs; it is a conscious engineering choice made for immense benefits.
This powerful philosophy isn’t just for single numbers or strings; in Clojure, it extends to the very collections that structure our data.
The bedrock: simplicity in four core collections
If Clojure South had a silent protagonist, it was the humble map. This is no accident. Clojure deliberately rejects a sprawling ecosystem of collection types in favor of a small, powerful bedrock of four core structures. This strategic choice to favor a minimal set of data structures fosters immense reusability and clarity.
Clojure is built on four primary collection types, each serving a distinct structural purpose:
What makes these collections so powerful is not just that they are immutable, but that they are all accessible through a single, universal vocabulary of functions. In many object-oriented languages, “every class invents a new language.” To get a user’s name, you call user.getFirstName(); for an order’s total, order.getTotal(). This is a major source of friction; developers must constantly context-switch, learning a new mini-protocol for every object they encounter.
Clojure rejects this bespoke complexity. Instead, it provides a unified set of functions—get, keys, vals, seq, count—that work on all data. This common vocabulary dramatically reduces cognitive overhead. As Alex Miller noted, once you
The same tools work everywhere, making data feel close, transparent, and easy to reshape.
This common language for manipulating data is the key that unlocks Clojure’s central, and remarkably simple, algorithm for solving problems.
The core algorithm for programming
At the very heart of the talk, Alex presented the key slide—a simple, two-step algorithm that encapsulates the entire Clojure development philosophy. It is an idea so powerful that it can fundamentally reshape how one approaches building software.
This two-step model of “data in, data out” is profoundly effective for several reasons:
This might sound elegant in theory, but its true power becomes clear when applied to real-world problems.
From to-do lists to music: data in action
To demonstrate the core algorithm in practice, Alex walked through a series of diverse examples, showing how any domain can be modeled as data and manipulated with functions.
A simple to-do list
A to-do item is not an object with methods; it is simply a map containing keys like :task, :errand, and :duration. Miller’s advice here is a cornerstone of pragmatic Clojure design:
From this foundation, a common pattern emerges: write a small function to handle a single item, then another to handle the collection. The task of transforming to-do items into HTML follows this perfectly, with one function converting a single map into a Hiccup data structure, and a second mapping that function over a collection. This emphasis on small, single-purpose functions is pervasive. As Miller observed, “it’s not uncommon to look at a closure codebase and see that… the average size of a function is five lines.”
Conway’s game of life
The infinite grid of Conway’s Game of Life is elegantly represented not with a massive, two-dimensional array of zeros and ones, but with a sparse representation: a simple set containing the [x, y] coordinates of “live” cells. This data modeling choice is incredibly powerful. The entire game logic becomes a pipeline of pure functions that takes one set of coordinates as input and produces the next set as output, implementing the game’s rules with mathematical clarity.
Graphics and music as data
The pattern extends even to creative domains. A circle on a screen can be represented as a map with :x, :y, :radius, and :color keys. Similarly, a musical note can be a map with :pitch, :octave, and :duration. By modeling these entities as data, Alex Miller was able to build a mini-synth on stage, using a sequence of maps to play the iconic five-note theme from “Close Encounters of the Third Kind.”
In every case, the solution was found not by designing complex class hierarchies, but by first asking, “What is the simplest data structure that can represent this problem?”, and then applying simple, composable functions to transform it.
While this model covers the vast majority of programming tasks, Clojure also provides a principled approach for the rare moments when values truly need to change over time.
Managing change: a principled approach to state
Inevitably, some parts of an application must change. A user’s session, a database connection, a UI component’s state—these all require managing change over time. For these scenarios, Clojure provides a clear answer that avoids the chaos of unmanaged mutability. The goal is to create a “stable logical identity that’s going to have different immutable values over time.”
Clojure offers a small set of stateful constructs for this purpose, primarily atoms, refs, and agents. Instead of directly mutating the value they hold, you provide them with a pure function that computes the next state from the current one. This design means developers don’t perform manual locking; reads are always available without coordination, and writes are managed safely by the Clojure runtime.
What’s most telling is how this plays out in practice. When Clojure was created, its Software Transactional Memory (STM) system, built around refs, was seen as a flagship feature. Yet, over years of production use, a surprising truth emerged. As Miller noted, developers discovered that they “can get by with an amazingly little amount of state in your system.” The disciplined, data-first approach naturally leads to architectures where the vast majority of the code is pure and stateless, reinforcing the core philosophy of the language.
Conclusion: building on rock, not on sand
The core message of Alex’s talk is a call for a return to simplicity. The philosophy is clear: build systems on a foundation of immutable values and pure functions, and manage state only when absolutely necessary. This approach yields programs that are easier to understand, grow, and maintain.
Miller concluded with a powerful metaphor that perfectly captures the difference between this approach and more conventional, mutable-state-heavy paradigms. Following this philosophy is like “building on bedrock instead of building on sand.”
The stability and clarity that come from this foundation are not just technical achievements; they are the source of genuine professional joy. It allows developers to focus on solving problems rather than fighting with the accidental complexity of their tools. The standing ovation Alex received was not just for a well-delivered talk, but for articulating a philosophy that brings the joy back into the craft of programming.
Check our job opportunities