Chapter 9
Writing Code
The craft, bridged to where the Lab proves it. Consistency over isolated correctness.
On this page
The craft of implementation.
The craft
Writing code is a craft. Like any craft, it has techniques that can be learned, practiced, and refined.
None of the techniques here are mine. Metz, Beck, Fowler, Freeman and Pryce worked them out over decades, and the footnotes point at the sources. This chapter used to restate them; the Reloading Lab now demonstrates them on a real system, which teaches better than a recap. What stays here is the shortest bridge from each landmark to the place that proves it, plus the one discipline I hold that the sources do not state: consistency over isolated correctness.
The landmarks, and where they are proven
Test-driven development. Write the failing test, make it pass with the simplest thing, clean up while green.[1] Outside-in, the acceptance test pins behavior while unit tests drive design.[2] Watch it done rather than described: Drive the Body Plan With Tests builds the Lab's suite this way, including the two ways green lies and the map of what each test can and cannot prove.
Small objects with small surfaces. Metz's rules (classes under 100 lines, methods under 5, four parameters, one object per controller) are forcing functions toward objects that have one job.[3] The Lab's readiness gate is the rules made flesh: one public message, assess, returning one value object, and Readiness Is Derived, Not Declared shows what that small surface buys when the rule has to change. Break the rules when you must; say so, and say why.
Simple design. Beck's four rules in priority order: passes the tests, reveals intention, no duplication, fewest elements.[4] The order matters; working-but-unclear beats clear-but-broken, then gets clarified.
The smells. Long methods, feature envy, shotgun surgery, primitive obsession: Fowler's catalog names them all.[5] Most of them are one question in this book's vocabulary: can you still draw it?
Refactoring
Changing code structure without changing behavior. Beck's line: "Make the change easy, then make the easy change." The first part is often harder.
I watched the whole principle play out in the garage, in two moves. Lawn-and-garden storage needed to relocate, so I made space beside the freezer and moved the shelf, bringing related equipment closer together. That was the change made easy. Then Norma saw the new arrangement and regrouped the components that get used together. That was the easy change, and it was not mine. I cannot tell you whether she had seen that optimization all along and the old layout made it too expensive to bother with, or whether the move is what made it visible. Either way, the first change did not have to be the final optimization. It changed the system enough that the next improvement became cheap and obvious for someone else. The next yard-work cycle needed nothing from that shelf, but neither of us lost track of where anything now lived. Whether the new arrangement actually retrieves better is still open; it has not been exercised by real use yet.
The software version is the same move: restructure so the change you actually want becomes small, then make it. And notice what the garage adds to Beck's line. The person who makes the easy change does not have to be the person who made the change easy.
The discipline:
- Small, incremental steps
- Run tests after each change
- Keep the code working at all times
- Never be more than a few minutes from green
And two boundaries: don't refactor without tests (that's just changing code and hoping), and don't polish code you will never touch again.
Consistency over isolated correctness
I learned this rule from a teammate whose code reviews I still hear in my head, and it has held everywhere I have tested it since: two ways to do something, one "better" and one existing, is worse than one consistent way. Every new pattern adds cognitive load for every future reader, and a locally cleaner pattern can make the whole codebase harder to understand. (The Body Plan tells the case: prettier diagram names that would have forked a second style beside four consistent commands.)
Before you write, discover how the codebase already solves problems like yours, and match it, even when your way is better in isolation. A new pattern creates a migration obligation. If nobody will own migrating the old pattern to the new one, the local improvement is a net loss: the repo now teaches two ways, and the next engineer has to guess which one is load-bearing.
The related disciplines, all pulling the same direction:
- Refactor everywhere first, or not at all. If the existing pattern is truly a problem, fix it across the codebase in its own change, then build on the new pattern consistently.
- Duplication beats the wrong abstraction.[6] It is far easier to recover from repeated code than from a bad abstraction everything depends on.
- Wait for the third case before extracting.[7] Two similar things are a coincidence; three are a pattern worth naming.
The limit: consistency is not a reason to preserve a harmful pattern forever. Security and correctness flaws justify deviation. The distinction is whether the inconsistency is intentional, bounded, and being carried toward convergence, or just this month's better idea sitting next to last month's.
Small, shippable increments
The standard I hold: every commit deployable, every push safe.
Trunk-based development. Work on main. No long-lived branches. Integrate constantly.
Why this works:
- Small changes are easier to review
- Small changes are easier to debug
- Small changes are easier to revert
- Integration pain is distributed, not deferred
The discipline:
- Commit often. Multiple times per day.
- Each commit is a complete thought. It works.
- If a feature isn't done, use feature flags.
- Never check in broken code. If the tests don't pass, don't push.
The goal
Code that works. Code you can change. Code others can read.
Not clever code. Not impressive code. Not code that demonstrates your skills.
Working, changeable, readable code. That's the craft.
Write the test first. Make it pass. Clean it up. Keep the code working. Keep it consistent. This is the craft of implementation.
Kent Beck formalized TDD in Test Driven Development: By Example (2002). The Red-Green-Refactor cycle is the heartbeat of the practice. ↩︎
Steve Freeman and Nat Pryce, Growing Object-Oriented Software, Guided by Tests (2009). The outside-in, "London School" approach that designs object conversations through tests. ↩︎
Sandi Metz, Practical Object-Oriented Design in Ruby (2012, 2018), and the 2013 Baruco talk that introduced the rules. ↩︎
Kent Beck, Extreme Programming Explained (1999). ↩︎
Martin Fowler, Refactoring (1999, 2nd ed. 2018). ↩︎
Sandi Metz, "The Wrong Abstraction" (2016): "duplication is far cheaper than the wrong abstraction." ↩︎
The Rule of Three, recorded by Martin Fowler in Refactoring (1999), who credits Don Roberts. ↩︎