Andrej Karpathy has a useful framing for what shifted. We moved from handwritten code fed to a compiler to context fed to a much more general interpreter. The context window is the program and the AI is the interpreter. The interpreter is new. The cost of producing plausible programs collapsed because the new interpreter is vastly more general than a compiler. But if the program is now a prompt…
Agents don’t feel pain. Humans do. This insight, pointed out by Mario Zechner , turns out to be quite profound. Pain in a codebase is a signal. It’s a feeling that senior developers have spent decades calibrating to say “no, we don’t need that”. It’s the thing that triggers a large refactor even though it will not add any new features to the next release. Pain…
A curated list of things I’ve built or written that live outside the regular blog post stream. Developer tools mu — A small, opinionated control plane for running a crew of AI coding agents in parallel. One tmux session, a typed task DAG, isolated VCS workspaces per agent, and an audit log — deliberately built to get out of the model’s way. vecgrep — Semantic grep: like ripgrep, but…
The all-or-nothing stance that dominates AI debates is not helpful. Neither of the extreme positions “we don’t use AI here” and “we let Claude YOLO all our code” is productive. Both avoid having to think about the actual problem: how to use this powerful new tool without breaking the codebase with hundreds of invested man-years? Turns out the answer is obvious: start…
Simon Willison’s collection of Agentic Engineering Patterns includes an excellent post called “Hoard things you know how to do”. The short version is that you should collect examples of how to solve problems, in code preferably, so you can show your AI agent later. One line in particular is worth pulling out: “The key idea here is that coding agents mean we only ever need…
Code is not scarce anymore. We are already living in the world of too much plausible code. That does change our job as developers. However, the job was never just typing anyway. Good developers always brought other things to the table and those things matter more than ever. Judgment matters. Debugging matters. Taste matters. Systems thinking matters. Tradeoff analysis matters. Being able to…
In practical terms the big thing that changed is this: plausible code is now basically free. Getting from a vague thought to something that looks like software is dramatically easier than it was. That does not mean building good software is suddenly easy. But it does change what actually matters. A weird consequence is that the explanation of what you actually want starts to matter more. If code…
In many software companies the percentage of AI generated code is steadily increasing. This accelerating code churn is driven by human-in-the-loop AI agents but also fully automated AI cleanups and codemods. Many developers feel more productive and their number of landed changes has gone up. The shipped code seems to work ok, and if not, the AI agent can often root cause and fix bugs quickly.…
AI tooling is not impacting the software industry in a uniform way. The YC startup bubble gets most of the attention and that distorts the picture. Move fast and break things is simply not viable in big parts of the industry. Take heavily regulated industries like finance. It’s easy to mischaracterize these companies as slow-moving or even lazy, when in reality they’re solving a harder…
If you have spent some time with the recent slate of AI agents (post Opus 4.5) you probably went through roughly the same mental journey as the rest of us: This thing is incredibly powerful, I can’t believe it managed to fix that bug / implement that feature / create this tool that I’ve been meaning to write for years Quickly followed by: We (software developers) are all cooked If you…
Take yourself back to when you got your first computer and started writing code. That sense of wonder when “Hello World” appeared on your screen. That dizzying feeling that you could make this strange machine do whatever you told it to. Turns out that tapping into that old feeling is really helpful again. Experiencing that sense of wonder while messing with all these new AI tools and…
Some of the readers of my Beyond Clojure blog series have asked about my opinion on clojure.spec, and if it solves Clojure’s ’type problem’. Implying whether its presence makes me look more favorably on Clojure. Here are some of my thoughts.
This is a post in the Beyond Clojure blog series, in which a Clojure developer looks at typed languages for web app development. In this episode we look at front-end development in the language Elm. Front end development targeting web browsers is a ghetto, everybody seems to agree. The core tools at our disposal are the amalgamation of ideas and accidents thrown together without much overall…
This is a post in the Beyond Clojure blog series, in which a Clojure developer looks at typed languages for web app development. This is by no means a complete survey of the Haskell web development landscape, rather a random collection of thoughts. If you are interested in typed functional languages one stands taller than the rest. It’s impossible not to get sucked into the Haskell vortex,…
Here we are, after five years of learning and later doing Clojure full time, I’ve come to the point where I am seriously looking around for alternatives. I’ve gotten very comfortable working in Clojure, and it has and will continue to serve me very well. But getting comfortable has a flip-side, you stop caring.
By reading the title of this post, you might think this entry is about using some clever Emacs skills to find bugs in old software. But no, it’s actually about hunting down bugs in Emacs itself (which incidentally happens to be very old software).
I’ve been quite vocal about my opinions on development environments and automating the creation of them on this blog and elsewhere . Boiling it down to the two points I feel most strongly about: Always develop in a production-like environment Automate the creation of these environments
It’s been a couple of months since I’ve stopped using Cider for Clojure development in Emacs. I find a simple ‘inferior lisp’ setup faster and more reliable. For a good summary of why one would consider not using Cider, see Luke VanderHart’s excellent summary .
Recently, I gave a talk at the Clojure eXchange 2014 titled ‘Developing Clojure in the Cloud’. I described a way of creating and using (Clojure) development environments inside VMs. I’ve been developing like this for the last year (spanning 2 projects).
Tradition demands that I write down some subjective thoughts on how my old friend F# is doing. So here we go again (for the 4th year running). All I can really say is this: wow, what a year.
I’ve been hacking Clojure for many years now, and I’ve been happy to rekindle my love for Emacs. The Clojure/Emacs toolchain has come a long way during this time: swank-clojure, nREPL, nrepl.el, and now Cider. The feature list is ever-growing, and every time you look, there are some new awesome shortcuts that will ‘make your day’.
The Clojure Cookbook is part of the O’Reilly cookbook series. I’d describe this format as a ‘curated wiki in print’. The wiki analogy is especially true for this volume since its contents were contributed by some 60 different developers. It’s packed with small, bite-sized recipes for solving common problems in Clojure. This is useful for developers across the entire…
All Clojure developers swear by their REPL; it’s one of the most powerful tools in our arsenal. Coming from traditional edit/compile/launch languages, it is also a great productivity boost. The Clojure community takes non-AOT (ahead of time compilation) to the extreme. By default, we ship Clojure source code in our development and production jars and thus leave compilation to the very last…
You can’t do anything even remotely blocking inside go-blocks. This is because all the core.async go blocks share a single thread pool, with a very limited number of threads (go blocks are supposed to be CPU bound). So if you have hundreds/thousands of go blocks running concurrently, just having a few (a handful really) block – all go blocks will stop! For a more in-depth explanation…
One particularly annoying difference between core.async and Go is that you can’t wrap function calls with the go macro. This is due to implementation details of core.async, which can only see the body ‘inside’ the macro and not the functions it may call. This is obviously not a problem if the called function doesn’t interact with any channels, but if it does, then you might…
Dealing with exceptions in go blocks/threads is different from normal Clojure core. This gotcha is very common when moving your code into core.async go blocks – all your exceptions are gone! Since the body of a go block is run on a thread pool, there’s not much we can do with an exception, thus core.async will just eat them and close the channel. That’s what happened in the…
For the third year running, here’s my annual (and extremely subjective) review of the state of the F# language, its community and other loosely connected things. How would I sum up the noises coming from F# the last year? Pretty darn awesome. A lot of what’s been happening was on my wish-list outlined in last year’s post . What are the highlights?
tl;dr I present a new Simulant example project , testing a simple web API. All programs are simulation tested, at least once. — Stu Halloway Simulation testing is an interesting field that has a lot going for it. While most website/API developers write many tests at the unit level (an old Rails habit), testing and understanding a whole system is often not done. Most systems we build nowadays…
Stuart Sierra has done a great job with clojure.tools.namespace and the reloaded Leiningen template. If you haven’t heard about this before, please have a look at c.t.n’s readme and watch this presentation . I have retrofitted this pattern into two rather large Clojure projects (20,000 and 5,000 lines) with several modules, and here are some of my findings. Removing global state The…
I’ve been using various Go examples and tutorials to take a deeper look into core.async . The CSP pattern is very interesting and powerful; it’s a good move for Clojure to “throw in” with Go and push this style of programming. core.async works at the s-expression level, where some other JVM solutions ( Kilim , Pulsar ) do the same at the byte-code level. The main benefit of…
Some time ago I wrote about Asynchronous workflows in Clojure . With the recent release and excitement of core.async , I thought it a good time to revisit that post. While there are already some good examples and comparison-with- go posts out there, I’d like to focus on an area often misunderstood, namely async frameworks and blocking APIs (most commonly blocking IO). It’s important to…
I am proud to announce a new Scala project called “Frins.” Frins is a practical unit-of-measure calculator DSL for Scala. Key features: Tracks units of measure through all calculations, allowing you to mix units of measure transparently Comes with a huge database of units and conversion factors Inspired by the Frink project Full source code is available on GitHub . To whet your…
In this post, I present some of my experiences writing a Scheme interpreter in Scala (as an external DSL) and compare it with my recent similar experiences in Clojure and F#. Overall, the Scala solution is very similar to the F# one . Not very surprising, since the problem lends itself well to case classes / discriminated union types and pattern matching. One difference is more type declarations…
Functional programming is great; higher-order functions, closures, immutable data-structures, lazy sequences etc. Most languages comes with a REPL (or ‘interactive’ prompt), where you can play with these features at your leisure. Dynamically typed languages are a bit more convenient in the REPL, but not by as much as you might think. Also, F# type providers closes the gap even further.…
This epic journey (yeah right) began at university with discovering the mighty SICP , still the best book on programming I’ve read (and let’s face it, the best I will ever read). After that profound experience, I kept an eye on the Lisp/FP world and wrote some toys in Scheme , ELisp , and OCaml every now and then. One thing that dawned on me was that none of these languages had much…
I recently switched to the Samsung ARM Chromebook for all my laptop needs. The pitch is quite appealing: £200, dual-core ARM Cortex-A15s, good keyboard, totally fanless (CPU is passively cooled), good battery life, and 1kg weight. The one downside is its quite limited RAM size, just 2GB. But with a decent swap file, I’m running multiple JVMs (with Datomic, Elasticsearch, CLJS compiler, etc.)…
TL;DR: Pipejine - a lightweight Clojure library for multi-threaded producer/consumer pipelines supporting arbitrary DAG topologies. Recently, a colleague and I faced a problem where we needed to optimize the total running time of a complicated calculation. This calculation involved several asynchronous steps getting data from other systems (like Elasticsearch and other home-grown services), along…
Let’s say you have a big legacy C++ app. Then you’re undoubtedly covered by Greenspun’s tenth rule . Let’s also say that your home-grown, buggy, and slow DSL/scripting language has been pushed to its limit and cannot be tweaked any further. What do you do? How can you replace it? As you might expect, this is quite a common problem, and embedding scripting languages into a…
It’s been a year since I last wrote about F# and Mono - what’s happened since then? F# 3.0 has recently been released, bundled with the new all-grey , ALL-CAPS Visual Studio 2012. The biggest new feature is type providers , bringing some of the benefits of dynamic languages into the type-safe world. Innovations like type providers deserve more industry attention. I really hope these…
I’ve written about Datalog and Datomic recently. To conclude, here’s another post comparing execution speed with the contrib.datalog library by Jeffrey Straszheim. Clojure 1.4-ready source can be found here . The example I’m using in my benchmark is a simple join between two relations. In Datomic/Datalog, it would look like this: ( q ' [ :find ?first ?height :in $a $b :where [$a…
Mr. David Nolen recently published core.logic 0.8.alpha2, with added cKanren (c for constraints) support. To celebrate this glorious event, I’m writing up some core.logic/cKanren stuff I’ve been looking at recently. Enter the Queens If you’ve followed this blog, you’ve perhaps seen my previous posts on solving N-Queens in core.logic ( part 1 and part 2 ). How will this look…
Here I present a couple of examples of the functional design pattern “untying the recursive knot.” I’ve found this useful on several occasions, for instance, when breaking apart mutually recursive functions. This material was inspired by Jon Harrop’s excellent Visual F# for Technical Computing . First, let’s look at a simple factorial implementation using direct…
This is a follow-up to my previous post on datalog-equivalent queries in core.logic. Here I present an alternate way to do the unification and join inside core.logic (without having to use clojure.set/join). It uses the relationships/facts API in core.logic, described here . First, let’s consider this Datomic query: ( q ' [ :find ?first ?height :in [[?last ?first ?email]] [[?email ?height]]]…