What requirements don't you have?
Short summary
Sean Goedecke argues that strong system design comes from deliberately dropping requirements like strict consistency or instant delivery, using examples from Unicorn, S3, StatsD, and SQLite. He also warns that coding agents tend to pile on unnecessary requirements that make code needlessly complex.
- Systems like Unicorn, S3, StatsD, and SQLite gain speed, simplicity, or scalability by giving up guarantees such as shared state, atomic multi-key updates, delivery of every packet, or concurrent writes.
- Deciding which requirements to relax needs both technical and business input, and trust gaps between engineers and product managers often block that tradeoff.
- Solo developers and startups can make these tradeoffs more easily because one person holds both the technical and business context.
- LLM coding agents tend to invent edge-case requirements (extra mutexes, TOCTOU checks, consistency guards), so reviewers need to strip them out or the codebase becomes unmanageable.
Full summary
The core argument is that good system design depends as much on the requirements you choose to drop as on the ones you keep. Sean Goedecke points to real systems that got simpler and faster by giving something up. Unicorn, a preforking Ruby web server, skips handling slow clients, so it can queue requests directly on Unix sockets and leave the problem to nginx or HAProxy in front. S3 gives up atomic multi-key updates, which lets it store data at the blob level and avoid cross-partition coordination. StatsD sends metrics over UDP, accepting that some data will be lost in exchange for much lower network overhead. SQLite drops concurrent writes to fit in a single file, and Cursor accepts high tail latency to make its distributed git backend easier to scale.
The hard part, he argues, is that deciding what to relax needs both technical and business judgment. An engineer has to know how stale data can get and what that does to performance, and a product manager has to decide whether users will tolerate it. The two often distrust each other's incentives and can't easily check each other's work, so neither gives ground and the design stalls. He suggests this is why solo developers and small startups can outbuild large companies: one person holds both the technical and business calls and can make tradeoffs a committee never would.
He then turns to LLM coding agents, which he says make the problem worse. Models trained on verifiable rewards chase hypothetical edge cases. They add mutexes, extra checks mid-request, and synchronization between cache partitions, and a four-line change can balloon into a thousand lines. He reports that about half the large AI-generated diffs he reviews contain an invented requirement like this. His practical advice is to state tolerance for staleness explicitly in prompts, and to scan Go code for unnecessary locks and indirection first. Left unchecked, these added requirements, which he calls "epicycles," accumulate until the system can't scale.