Thinking in public
Essays on being a CTO, on AI in practice and on engineering leadership, plus the technical notes I wrote so I would not have to solve the same problem twice. RSS feed.
2026
mdread: a Markdown reader with 10% of the features, built for speed and a 4K screen
I wanted a Markdown reader with 10% of the features of every other reader and editor, as fast as possible, and using all of my 4K screen. So I built one in Rust.
A whole replay in a URL: how Flappycar's ghost links work without a backend server
How Flappycar sends a friend your entire run as a ghost to race, with no backend server: a fixed physics step, a seeded course, and every tap packed into a couple of hundred bytes of URL.
2025
The Gotcha Game That Drives Great Engineers Away
Most tech interviews are a game of gotcha that makes the interviewer feel clever and loses solid builders. The best interviewers are great conversationalists who listen.
How will we train junior developers in a world of generative AI?
Generative AI is delegation, not just abstraction. How do juniors build the judgement to use it well, and what should teams and employers change?
The Illusion of Democratized AI — And Why It Should Worry You
Training frontier models is structurally out of reach for all but a few hyperscalers. Why that concentration of compute is a strategic risk for everyone building on top.
Your real team as CTO
One of the biggest mistakes new CTOs make is thinking their team is still the tech team. Your real team is the executive team, and that changes how you spend your week.
2023
Easy async function execution in Python/Django using a queue and consumer Thread
Run API calls and tracking writes off the request thread in Django without Celery or django-q: a queue and a consumer thread are enough.
2021
How to work for an international software company from SA and maximise your earnings
A practical guide for South African developers on landing remote work with European companies, running as a sole proprietor, invoicing, forex and provisional tax.
2016
How to timeout a thread in Java / Limiting a threads execution time
Limit how long a piece of Java code may run using thread interruption and a timeout, and the catch that stops it working on arbitrary code.
How to communicate between your Chrome extension and your SPA web app
Two-way messaging between a Chrome extension and a single-page app using Chrome's external messaging API, with the background script, manifest and web app code.
2015
I get NoNodeAvailableException on long-running processes using SSL TransportClient with Found.no
A hosted Elasticsearch hostname resolves to several IPs. Add only the first to a TransportClient and long-running processes eventually fail with NoNodeAvailableException.
When I index something in Elasticsearch, why doesn't it show in my search straight after?
Elasticsearch is near-real-time: new documents appear after the next refresh. What that means and how to force it when you must.
Why does Apache Nutch sometimes get stuck using a single thread and crawling slowly?
Why an Apache Nutch crawl collapses to a single fetch queue, and the generate.max.count setting that keeps it spread across sites.
2014
Centralising Clojure/Java logging with Logback, LogStash, ElasticSearch, and Kibana
Shipping Clojure and Java logs from Logback through Logstash into Elasticsearch, and reading them in Kibana.
2013
Keybinding for emacs helm to recursively grep certain file extensions in your src directories
A short Emacs Lisp function that binds a key to a recursive Helm grep over your source directories, limited to the file extensions you care about.
2012
Deploying Datomic free on EC2 or any Ubuntu system
Installing Datomic Free on Ubuntu or EC2 with an Upstart script, a symlinked runtime for painless upgrades, and rdiff-backup for backups.
Integrating Logback with Clojure
Getting Logback working as the logging backend for a Clojure project.