At Sturdy Statistics, our mission has always been to make sense of complex data — whether it comes from genomes or text. Our core technology began as something unusual: a genomic model adapted to work with text. The heart of our company is a probabilistic generative model implemented in C17, built around a DSL for constructing Bayesian DAG networks using the Pitman–Yor process. We use it for NLP, but the model’s origins in population genetics make it equally applicable to genomic problems such as single-cell RNA sequencing or tracking clonal evolution.
But you can’t build a company around a CLI. (Or at least, we couldn’t — and we tried.)
That required building an entire ecosystem around it — everything from data ingestion to user-facing tools:
- Wrappers to run our models, serialize them, and integrate them into end-to-end pipelines
- Tools for data ingestion, pre-processing, analysis, and visualization
- An API for developers
- Integrations with curated data sources such as product reviews, news articles, academic papers, Hacker News comments
- A web platform for managing accounts, data, and API keys, and for no-code analysis
When we started, Python seemed like the obvious choice. It had the best NLP ecosystem, spaCy looked perfect for pre-processing, Flask was a simple, battle-tested way to serve APIs, and Dash helped us prototype dashboards quickly. We knew Python inside and out — and we chose it reluctantly but pragmatically.
As our prototype evolved into a platform, though, we hit the predictable walls:
- Dependency resolution hell: version conflicts and breaking changes that turned simple updates into day-long debugging sessions
- Performance bottlenecks in surprising places
- The GIL — Python’s Global Interpreter Lock — which makes true parallelism nearly impossible
We built workarounds: shelling out to parallelize, and offloading heavy lifting to C programs or DuckDB (which is astonishingly capable — especially when you’re desperate). Eventually, the cost of those workarounds exceeded their benefit.
We decided it was time to start fresh and we surprised ourselves by choosing a language neither of us knew, or had ever used before: Clojure.
Why Clojure?
Clojure gave us:
- Real concurrency — threads, futures, and async channels — without the GIL
- Predictable, fast performance — with far fewer surprises than Python
- Rock-solid stability — the JVM’s garbage collector and threading model make it ideal for long-running, 24/7 systems
- REPL-driven development — hot-reloading, tiny feedback loops, and real “live coding”
- Zero dependency drama (so far) — we have yet to hit a single conflict
That last point feels cultural as much as technical. Clojure libraries rarely introduce breaking changes. The ecosystem values stability and composability. Python, in contrast, rewards shipping fast — sometimes at the cost of compatibility.
We expected these improvements. What we didn’t expect was how much better our code would become. Writing pure functions and working with immutable data nudged us toward patterns that were simpler, clearer, and more reliable. The codebase feels smaller, more transparent, and easier to reason about — even though neither of us knew a word of Clojure when we began the rewrite.
The Human Side
There’s also a more personal angle. Around the time we began the rewrite, my first child was born. I found myself working at odd hours — fifteen minutes here, three minutes there, sometimes a quiet stretch from 2 a.m. to 4 a.m. Our Python codebase was very well written, but under that kind of schedule, I couldn’t easily “re-enter” it. It was too stateful, too sprawling, and too dependent on remembering context.
Clojure was different. Knowing that everything is a pure function meant I could open a single file, change one small piece, and be confident it wouldn’t ripple through the rest of the system. The language made the project fit the rhythm (or chaos) of my life. I could still contribute meaningfully, even in short bursts.
Another benefit: I work in Emacs, and tools like paredit, ido, dabbrev-expand, and key-chord-mode — plus a custom keymap — let me code one-handed while holding my baby. For reasons I can’t quite explain, I’ve never found a particularly comfortable way to work with Python… the whitespace delimiters don’t gel with my incremental, interactive development style.

To be clear, we could have built similar habits in Python — but we never did. In Clojure, they came naturally.
Continuous Improvement
The rewrite isn’t finished; we’re taking it one component at a time. But already, the experience has reshaped how we think about our system. We’ve become faster, our infrastructure has become more predictable, and our mental load is lighter.
For a startup building probabilistic models of complex systems with a small team, reliability and simplicity help a great deal.
In rewriting our system, we discovered that language choice shapes not only how software runs, but how teams think and work.
If you’re a small company hitting the scaling limits of your Python stack — and you’re willing to learn something new — we’d encourage you to give Clojure a try. You might find, as we did, that it helps you build not just better systems, but better flexibility when building them.