There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult. - C.A.R. Hoare
This quote is a poetic reminder for us programmers. It’s much easier to write complex than simple code. The big ball of mud is a common sight in most non-trivial projects.
Embrace Replaceability Over Perfectionism
Let’s face it: most code is temporary. Requirements shift, priorities pivot, and yesterday’s brilliant solution becomes tomorrow’s tech debt. Instead of obsessing over future-proofing, focus on writing code that’s easy to replace.
Complexity is inevitable, but entanglement isn’t. Rewriting a small, isolated module is far simpler than untangling a spaghetti mess. As Joel Spolsky warned though, rewriting everything is a trap—but replacing parts? That’s survival.
Maintainable code is easy to replace
The only thing you would achieve if you try to take care of all future possibilities is to make things unnecessarily complex. And you would more often than not, build wrong abstractions or do premature optimizations.
Good code isn’t timeless—it’s disposable. If you can’t delete it without a week of debugging, it’s holding you hostage. If you can replace it in a day, you can extend it in a day. This also cultivates a culture of building quick prototypes. So many projects are never released because they are never finished, there is always that one more feature which might be needed and should be taken care of.
How?
- Isolate complexity - Keep modules small, focused, and loosely coupled. A tiny, clear API surface means fewer surprises when swapping parts.
- Test the Boundaries - Tests aren’t just for correctness—they’re guardrails for future changes. So when the time does come to replace, you’re more confident.
- Single responsibility principle - A function/library/service should do one thing, well.
- YAGNI - You aren’t gonna need it. In the words of Ron Jeffries - “Always implement things when you actually need them, never when you just foresee that you need them”. Build for today, not hypothetical tomorrows.
- Document the “Why” - A two-line comment explaining why a hack exists saves future-you hours of head-scratching.
Related
- The Art of Destroying Software - Greg Young. Some quotes from the video -
- This is the unix philosophy, this is the Erlang philosophy, this is microservices, this is SOA(Service oriented architecture), this is actors.
- You know the most about your project at the end after you’ve done everything, not at the beginning while planning.
- The problem is most people are picking up these ideas and they are never understanding the fact that the goal is to delete your code.