Recent forays into developer productivity
I've written before about my posture around LLMs being mostly summarizable as design your systems and abstractions to accommodate an infinite number of junior engineers.
One of the nice things about this framing is that it sidesteps the trap of fake work that benefits LLMs and theoretical marginal productivity at the expense of actual productivity. Instead, it lets you fall into a different trap—one that I have tried so hard to avoid for the past few years—which is over-investment in developer productivity and tooling.
Here's the catch, though: this shape of work is largely toilsome and uninteresting and low-risk, making it particularly well-suited for LLMs to take initial exploratory steps. And so I ended up with a pretty nice feedback loop where, with an order of magnitude less effort on my part than would have otherwise been the case, Buttondown developer productivity has increased pretty dramatically over the past three months.
It is tricky to truly measure developer productivity. But there are at least a number of quantitative measures that are hard to argue with: fast builds, lints, and deploys are unambiguously better than slow ones.
That's where I've spent the majority of my robot-assisted efforts. None of these are even particularly clever or novel, and I list them out not in hopes that you'll be impressed but purely as a catalog of things that you should throw a bit of time at, just in case you haven't already:
| Change | Savings | Notes |
|---|---|---|
| Parallelize backend linting | ~14s warm, ~10s cold | 52% reduction warm |
| Parallelize frontend linting | ~48s | 73% reduction |
| Speed up marketing preview builds | ~2 min | Skip Sentry source maps and prerendering |
| Speed up docs Vercel builds | ~2.5 min | Skip static page generation on previews |
| Speed up file generation | ~60s | Lightweight CSS builds, skip unchanged icons |
| Speed up codebase fixtures | ~390ms | os.walk instead of glob.glob (~12x faster) |
| Speed up slow tests | ~30s | Targeted optimizations across test files |
| Use pre-sent emails in comment fixtures | ~10s | Avoids redundant email sending during test setup |
| Migrate to inline-snapshot-django | ~5s | Faster SQL fingerprinting in perf snapshots |
| DRY up test suites | ~15s | Parametrize + deduplicate (e.g. mailgun tests: 448 → 263 lines) |
| Decouple asset build from Heroku deploy | ~2 min | Run asset build in parallel with test suite |
None of these required any particular genius or even creativity. They were all, individually, the kind of thing where a sufficiently motivated (and distracted) engineer would say "yeah, I know exactly how to fix this, it's just not worth the time."
In sum: Buttondown's end-to-end CI now takes around seven minutes to run, down from ~twenty this time last year —
| Step | Duration | What |
|---|---|---|
| 1 | ~2 min | Linting + building + testing in parallel (backend suite is the long pole) |
| 2 | ~90s | Deploying to the demo app and healthchecking |
| 3 | ~90s | Deploying to the production app and healthchecking |
| 4 | ~90s | Deploying to the constellation of other things (docs, marketing site, admin, etc.) and healthchecking |