The Broken Wall
Traditional software wisdom, reinterpreted for the age of agentic coding.
The wall was never the code.
It was the prerequisite.
Software wisdom grew up behind a wall of prerequisite — you had to know 12-factor before you could build production software, understand module design before your code would last. Claude doesn't remove the wisdom. It removes the entrance exam. Below are eight gates. They've always been open.
Trunk-based development
One codebase. Many deployments. One branch, always deployable.
Main is always production-ready. Three environments serve distinct roles — dev is where Claude builds, QA is where you validate, prod is what's live. The branch maps this chain from left to right.
A long-lived branch is a symptom. The change was too big or the scope too wide. Keep branches small enough that merging them is routine.
Work trunk-based. Keep this change small and deployable. Open a PR when done — don't hold the branch.The twelve factors
Config in the environment. Logs are streams. Processes share nothing.
The twelve-factor manifesto — 12factor.net — is the rulebook for software that survives production at scale. You don't need all twelve. Start with the ones Claude breaks most often if you don't ask.
I · Codebase — One repo, one app, many deploys. Claude works in your repo. If you're asking it to coordinate a single feature across multiple repos, the boundary was drawn wrong — that's a distributed system, not one app.
III · Config — Never hardcode credentials, database URLs, or feature flags. Anything that changes between environments belongs in environment variables. Claude will write API_KEY = 'sk-...' if you let it — tell it not to.
V · Build, Release, Run — Keep the stages separate. Build turns code into an artifact. Release combines that artifact with config. Run executes it. Claude works at build time — it writes code. Config is injected at release, not hardcoded. Nothing changes at runtime.
Review this codebase against the 12-factor app principles. List what's missing or violated, ordered by severity.Favor the data
The object hid its state. The data had nothing to hide.
There should only be one way to do each thing. Not because it's elegant — because when there are two ways, Claude will use both, and the codebase drifts. Pick one shape for your data and hold it. The pipeline enforces this: data in, transform, data out, no detours.
In practice: not a dict here, a class there, and a JSON blob in the API layer — pick one and use it everywhere. Not validation scattered across five methods — one function, one place. Same concept, same name, always. Claude reads the whole codebase before it writes a line. Give it one consistent thing to read.
Rewrite this to be data-oriented. Functions that take data in and return data out. No hidden state. There should only be one way to do each thing.Deep modules
The door was small. Behind it, the world.
John Ousterhout's principle: the best modules have narrow interfaces hiding deep implementations. Claude tends toward wide interfaces — many small functions, many exports. Push back. One entry point that does the work is worth ten that divide it. The simpler the surface, the more powerful what's behind it.
Reduce the public surface of this module. Hide the complexity behind one or two entry points.Orthogonal features
Turning the wheel should not ring the bell.
Features that don't touch each other. Add logging without changing business logic. Add authentication without rewriting routing. The test: can you describe the new feature without mentioning existing code? If yes, it's orthogonal. Ask Claude to wire new things in at the boundaries only.
Build this feature so it doesn't modify existing code. Wire it in at the boundaries only.The unknown reader
Every variable named for the stranger who would never arrive.
Code was written for readability because someone unfamiliar would eventually inherit it — the new hire, the on-call engineer at 2am. That constraint shaped everything: verbose names, exhaustive comments, no clever patterns. Claude reads fluently at any complexity level. The stranger no longer struggles.
What changes: comments that explain what the code does matter less — Claude can read it. Comments that explain why — the constraint, the workaround, the non-obvious decision — matter more than ever. Readability for humans during review and debugging still counts. But the hierarchy shifts.
Remove comments that describe what the code does. Add a comment only where it explains a non-obvious decision, constraint, or workaround.Test first
How do you know it works?
The wall here was cost: tests took time, time was scarce, and the discipline slipped. Now Claude writes tests as fast as the code. The only question is whether you ask — and whether you ask before, not after. The test is the spec. Writing it first forces clarity about what done actually looks like.
Write the tests first. Don't write any implementation until I've seen and approved the tests.The table
One function. Many truths. The table holds them all.
Table-driven testing: a slice of cases, each a row — input, expected output, description. One test function runs them all. Easy to add a case, impossible to miss one. Once you've seen the pattern you can't unsee it. Ask for it by default on anything with more than two cases.
Use table-driven tests. Each case is a row: input, expected output, and a description. One test function runs all rows.