Audit a Codebase You've Never Seen
The final test of a craft book is whether you can spot the problem in code nobody warned you about.
The idea
Chapter 17 is not really a chapter. It is a field guide: every smell and heuristic Martin collected, filed under Comments, Environment, Functions, General, Names and Tests. Read cold it looks like a wall of codes. But you have spent eleven modules doing almost all of it by hand; this chapter just hands you the index.
A smell is a hint, not a verdict. Duplication does not mean every repeated line is a crime, it means repetition is where you should look, because it usually marks a missing abstraction. The catalog trains a reflex: this code makes me uneasy, and I can now say why in one precise phrase. Naming the smell is half the fix, because each name points at a cure you already practiced — duplication means extract, feature envy means move the method to the data, a boolean parameter means split the function.
Precision is the skill being tested. There is a real difference between "this function is kinda gross" and "this switch is polymorphism-shaped, and that boolean argument is selecting between two functions welded together." The first is a vibe. The second is a diagnosis with a treatment plan, and it is what separates a useful review from a drive-by LGTM.
So do this capstone on a codebase you have never opened. Eleven modules on one repo means you know where its bodies are buried; real review never works like that. Pick something unfamiliar, audit it, clean it while the tests stay green, and then re-run your Module 1 stopwatch on the dirty copy and the clean one. The book's opening claim was that mess is a speed problem. You get to end the track holding your own measurement of it.
The bench — 4 exercises
The smell census
Audit an unfamiliar working codebase file by file and record every smell as a named, located, evidenced finding — turning vague unease into review-grade diagnosis.
- Pick a small unfamiliar repo you can run: a mid-sized open-source CLI, an old project of your own you haven't touched in a year, or a teammate's side project.
- Open Ch. 17's catalog beside you and create FINDINGS.md with one row per finding: file:line, catalog code, one-line evidence.
- Sweep the whole repo once for names and functions, then sweep again specifically for the families you skipped.
- Tally your findings per family (C, E, F, G, N, T) and note which families came up empty.
hint
Almost everyone finds function and name smells and walks straight past the test smells and comment smells. Re-sweep the test files on purpose.
hint
If you can't name the code, describe the evidence first — the code usually falls out of a precise sentence.
hint
Refactoring Guru's smell catalog is a fast lookup when a code won't come to mind.
DONE WHEN
· FINDINGS.md holds 20+ rows, each with a file, a line and a catalog code
· At least four of the six catalog families are represented
· Every row's evidence line names the specific code, not a general complaint
The full clean
Fix every confirmed finding using the techniques from all eleven prior modules, in small always-green steps, so that one repo satisfies every dimension at once.
- Lock behavior first: run the existing tests, and write characterization tests for anything untested you plan to touch.
- Work in order — names, then functions, then structure (classes and boundaries), then tests — committing after each green step.
- After each pass, re-run your own earlier checks: naming, function length and nesting, comment density, dot-hops, return null, boundary imports, duplication.
- When two fixes fight each other, back up one commit and cut at a different seam.
hint
Fixes interact: extracting a function can create a naming problem, moving a method can create a Demeter problem. That interaction is the whole capstone.
hint
Step size matters more than order — if a commit is scary, it was too big.
DONE WHEN
· Tests green at every commit, with observable behavior unchanged end to end
· At least eight small commits between the census and the finish, no big-bang rewrite
· Every finding in FINDINGS.md is marked fixed or explicitly declined with a reason
The checklist you keep
Compress your census into a personal review checklist in your own words, ordered by your own blind spots — the one artifact meant to outlive the track.
- List every smell you missed or nearly missed on the first sweep.
- Turn each into a trigger question you'd ask in a review, like "does any name promise something the code doesn't do?"
- Attach the catalog code and the specific file that taught it to you.
- Order the list by how often you missed it, and keep it to 10-15 items.
hint
Nobody reviews with sixty entries in their head; working reviewers carry a short list shaped by their own misses.
hint
Scored high with few misses? Mine your hesitations instead — the ones you almost didn't flag.
DONE WHEN
· CHECKLIST.md has 10-15 items, each phrased as a question you'd actually ask
· Each item cites a catalog code and a real file from your audit
· The list spans at least four catalog families
The victory lap
Re-run the Module 1 scavenger hunt against the dirty copy and your cleaned copy, and measure the clean-code advantage in cold minutes on your own work.
- Keep a pristine copy of the original repo untouched before you start cleaning.
- Write five "where does X happen?" questions and time yourself answering them against the dirty copy.
- Write five equivalent-but-different questions and time yourself against the cleaned repo.
- Write the three numbers side by side — Module 1 baseline, dirty, clean — and one sentence on what surprised you.
hint
Do the dirty run before the census if you can; you will never be that cold on this repo again.
hint
Use different questions for the clean run, or you're timing your memory instead of the code.
DONE WHEN
· Two timed runs recorded with five answered questions each
· The dirty copy is provably unmodified compared to the version you cleaned
· A written comparison of the three times exists, whatever the numbers say
Go deeper (after the bench)
Read Clean Code Ch. 17 (pp. 285-314) as a reference, not a memory test: skim the full catalog before the census and keep it open while auditing, because nobody memorizes G1 through G36. For one free companion, Martin Fowler's "CodeSmell" bliki entry gives the framing this whole module leans on — a smell is a surface indication, sniffable in seconds, that invites a deeper look rather than demanding a fix.