Our toolkit

A list of what we work with. These pages are usually about keyboards and colour schemes; this one is mostly about the boring end, because the boring end is what decides whether a system is still pleasant to work on in year six.

Languages we reach for

Java is the bulk of it, and has been for twenty-odd years — mostly Spring, mostly systems that have to be right rather than novel. Rust for tools: fast start-up matters enormously for something you run fifty times a day, and a terminal UI that takes two seconds to appear is one you stop using. TypeScript where the browser is involved, and Swift where Apple platforms are.

Not a religious position. The languages follow from what the thing has to do.

The tools we wrote

Three of them, each because the thing we wanted did not exist:

  • ebman A k9s-style terminal UI for AWS Elastic Beanstalk. The console is several clicks away from every answer you actually want; this is one keystroke away from most of them.
  • pgman The same idea pointed at Postgres, with a particular interest in turning Hibernate's logging back into SQL you can run.
  • candor Capability maps and CI gates for code — what a function can actually reach, and a build that fails when something crosses a boundary you declared. Increasingly useful now that a lot of code arrives written by something else.

Building and running

AWS, and all of it described in Terraform rather than clicked into existence. If the infrastructure is not in version control then nobody knows what it is, including the person who built it.

PostgreSQL for anything that matters. Docker for the things that need to be identical on a laptop and a build agent. Continuous integration on Bitbucket Pipelines and GitHub Actions, depending on where the repository lives.

This site runs on S3 and CloudFront, is built with Eleventy, and has no runtime dependencies at all. There is a longer note about that.

Checking the work

The unglamorous part, and the part that decides whether any of the above holds up.

Tests, obviously, but more usefully: things that attack the tests. We break our own code on purpose and check that something fails — a wrong number, a flipped comparison, a dead link — because a suite that only ever runs against working code tells you nothing about whether it would notice a fault. It is the cheapest way we know to find out whether the safety net has a hole in it, and it has found several.

The same instinct applies to infrastructure: a plan across every configuration, read-only, on a schedule, so that drift between what is deployed and what is written down is something we find rather than something we discover.

AI, since everyone asks

We use coding agents daily and they are genuinely good, which is exactly why candor exists. The problem is not that the code is bad; it is that there is a lot of it and no one person read all of it. So the interesting question stops being "is this correct" and becomes "what can this now reach that it could not reach before" — which is a question a machine can answer deterministically, and a reviewer cannot answer by eye.

Nothing here is written by a model and published unread. The words are ours.

If you want any of this pointed at a system of yours, get in touch.

Have a big idea to build, a problem to solve, or a system that’s overdue an upgrade?

Get in touch