Boundaries before features
The fastest way to make a small codebase feel large is to let features leak into each other. One module reaches into another's data, a controller starts knowing about the database, and six months later every change touches five files.
So before I write features, I draw boundaries.
What a boundary is
A boundary is a line you agree not to cross casually. On one side lives the domain — the rules that are true regardless of framework or database. On the other side live the details: HTTP, SQL, the UI. The domain depends on nothing; the details depend on the domain.
Why first, not later
You can refactor toward boundaries afterward, but it's expensive — by then the leaks are load-bearing. Drawing the line first is almost free: it's a decision about where code is allowed to live, made before there's any code to move.
This is the same instinct as keeping decisions reversible. A boundary is a place where you can swap one side without disturbing the other — the database, the delivery mechanism, even the framework. The feature doesn't notice.
It's not about predicting the future. It's about making the present cheap to change.
Related notes
Tests as living contracts
A good test suite isn't a safety net you tolerate — it's the executable specification of what your system promises, including the properties that must always hold.
Make decisions reversible
You can't reliably predict the right call. So optimize for cheap mistakes: prefer decisions you can walk back over ones you have to get right the first time.