On keeping software intentionally small.
Three years in, the codebase is half what it used to be. The product does more. The team is the same size. The on-call rotation hasn't fired at 3 AM in eleven months. None of that is an accident, but none of it is the result of any particular policy either. Mostly it's the result of saying no slowly, over and over, in small specific ways.
Things we said no to
- An ORM. We have queries in
sql/as.sqlfiles. They are not generated. We can read them. - A second language on the server. Everything is Go. Some of it is awkward Go. We have not regretted this.
- A message bus, twice. The first time we noticed an event loop would do. The second time we noticed a database transaction would do.
- Microservices. The thing is a single binary. It has a directory called
internal/with five packages. Anyone joining can read the whole thing in a day. - Kubernetes. Three machines, two regions, systemd. We sleep fine.
What we did instead
We wrote a CHANGES file by hand. We deleted code aggressively when we saw it not being used. We refused to add a flag where a default would do. We kept the test suite small enough that everyone runs it locally on every save.
None of that is original. Most of it is what every "boring tech" essay from the last decade says. The hard part is not the advice. The hard part is that the advice has to be applied a thousand times — once for every PR — and most of the time it costs you a little something and the cost is more visible than the benefit.
A small claim
The thing about software-that-isn't-growing is that it accumulates trust the way old buildings accumulate weight. The first six months, every change is a risk. By month thirty, every change is a vote of confidence. The thing knows itself. Touching it doesn't break it. New hires guess right about what to do because the system was designed to be guessed at right.
You can buy this. The currency is restraint. The price is mostly other people's enthusiasm.