5.1 KiB
| source | date | tags | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| hyperthrive_dev | 2026-03-13 |
|
99 Bottles OOP — Full Software Design Process Map
A complete map of the software design lifecycle described in 99 Bottles of OOP by Sandi Metz and Katrina Owen. Documented during a session exploring how to better encode OO principles into AI coding conventions.
Overview
The process is an infinite loop with four distinct phases: initial development, a waiting period, a refactoring loop triggered by new requirements, and implementation. The key insight is that refactoring and feature addition are deliberately separated.
Phase 1: Initial Development (Shameless Green)
Goal: get to working, understandable, thoroughly tested code as fast as possible. Do NOT invent requirements or speculate about the future.
- Sketch a high-level public API for the problem
- Write the first test targeting the simplest, most thoroughly understood piece of that API
- Red → Green (write only enough simple code to pass)
- Write the next test proving existing code is incomplete
- Write the simplest, most concrete code to pass — tolerate duplication
- Repeat horizontally until all variations are handled
- Stop. You have reached Shameless Green: easy to understand, fully tested, fulfills current requirements
Shameless Green optimizes for understandability, not changeability. If the code never changes, you stop here.
Phase 2: The Waiting Period
Do nothing proactively. Wait for a new requirement. Two voluntary exceptions:
- Exception A (Purify Tests): Clarify test names, remove echoes of implementation details, ensure every class has its own unit test
- Exception B (Aesthetic Improvements): Fix Law of Demeter violations, remove hard-coded class names, push object creation to the edges
Do NOT build abstractions speculatively. Save time and money.
Phase 3: The Refactoring Loop (Open/Closed Principle)
Triggered when a new requirement arrives. Separate refactoring from feature addition.
Decision gate:
- Is the code "open" to the new requirement? (Can you implement it by adding code, not modifying existing code?)
- YES → go to Phase 4
- NO → continue
- Do you know how to make it open?
- YES → refactor → return to step 1
- NO → continue
- Identify the best-understood code smell and remove it using a mechanical recipe:
- Need to unearth an abstraction → Flocking Rules
- Conditionals supplying behavior → Replace Conditional with Polymorphism
- Need to choose which polymorphic class to use → Factory
- Objects tightly coupled → Dependency Inversion (push object creation to edges, inject dependencies)
- Enforce contracts: check LSP (objects return trustworthy types) and LoD (no chaining collaborator messages)
- Return to step 1
Phase 4: Implementation
Code is open. Make the change — usually as simple as creating a new polymorphic class and registering it in the factory. Then loop back to Phase 2.
Code Smells and Mechanical Recipes
Switch Statement / Conditionals supplying behavior → Replace Conditional with Polymorphism (or State/Strategy)
Primitive Obsession → Extract Class (give the primitive a domain object)
Duplicated Code → Extract to a single method; apply Flocking Rules to find the abstraction
Large Class → Extract Class (divide responsibilities)
Data Clump → Extract Class or consolidating method
Law of Demeter Violation (chained sends: a.b.c) → Delegation / message forwarding, or redesign from the sender's point of view
LSP Violation (returns unexpected types) → Perform type conversion inside the method
Temporary Variable (used only once) → Inline Temp
Blank Line within a method → SRP violation; separate responsibilities
The Flocking Rules (Unearthing Abstractions)
Apply mechanically when you don't understand the abstraction yet:
- Select the things that are most alike
- Find the smallest difference between them
- Make the simplest change that removes that difference
Apply in four microscopic steps: (a) parse the new code, (b) parse and execute it, (c) parse, execute, and use its result, (d) delete unused code. Make one line change at a time. Run tests after every change. Undo immediately on failure.
Replace Conditional with Polymorphism (Recipe)
- Create a subclass for the value you switch on
- Copy one switching method into the subclass; keep only the true branch
- Create a factory if none exists; register the subclass
- In the superclass, remove everything but the false branch
- Repeat for all switching methods
- Iterate until a subclass exists for every switched value
The Ultimate Goal
Build applications out of trustworthy, loosely-coupled, polymorphic objects that can survive an unknown future. The programming aesthetic: fall in love with polymorphism.
See Also
- AI Coding Conventions Organization — External Research Synthesis — how practitioners encode process and principles into AI context
- OO Principles Plugin Concept — Design Recommendations — how to build an AI plugin based on this lifecycle