SecondBrain/2026-03-13-99-bottles-oop-f...

108 lines
5.1 KiB
Markdown

---
source: "hyperthrive_dev"
date: "2026-03-13"
tags: [research, oo-principles, 99-bottles, tdd, software-design, process, shameless-green, open-closed, refactoring]
---
# 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.
1. Sketch a high-level public API for the problem
2. Write the first test targeting the simplest, most thoroughly understood piece of that API
3. Red → Green (write only enough simple code to pass)
4. Write the next test proving existing code is incomplete
5. Write the simplest, most concrete code to pass — tolerate duplication
6. Repeat horizontally until all variations are handled
7. 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:**
1. 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
2. Do you know how to make it open?
- YES → refactor → return to step 1
- NO → continue
3. 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)
4. Enforce contracts: check LSP (objects return trustworthy types) and LoD (no chaining collaborator messages)
5. 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:
1. Select the things that are most alike
2. Find the smallest difference between them
3. 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)
1. Create a subclass for the value you switch on
2. Copy one switching method into the subclass; keep only the true branch
3. Create a factory if none exists; register the subclass
4. In the superclass, remove everything but the false branch
5. Repeat for all switching methods
6. 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