Code review checklist
A practical Pragmatic Programmer checklist
Twenty questions that focus a review on the cost of the next change. This is an independent, practical checklist inspired by the principles in The Pragmatic Programmer; it is not the book’s checklist and reproduces no book text.
Use it in order. Start with the boundaries and the tests. Style disagreements can wait until the behavior and the design are understood.
The 20 checks
| Check | Question to ask | Common false positive |
|---|---|---|
| PP-DRY | Does each piece of knowledge have one authoritative home? | Similar code that represents different policies |
| PP-CONFIG | Are secrets, hosts, paths, and policy outside the code? | A local constant that clarifies a comparison |
| PP-MAGIC | Is every numeric threshold named and explained? | A protocol value fixed by an external contract |
| PP-ORTHO | Can one concern change without forcing edits in another? | Two modules that genuinely share a domain concept |
| PP-GLOBALS | Is mutable state owned by the smallest possible scope? | A process-wide client with a documented lifecycle |
| PP-TRAINWRECK | Avoid call chains that reach through three or more objects. | A fluent API or builder that returns its own type |
| PP-INHERIT | Would composition express this relationship better? | Framework base classes and exception hierarchies |
| PP-CONTRACTS | Does every public boundary validate inputs and fail loudly? | A boundary that intentionally returns a typed result |
| PP-RESOURCES | Is every file, lock, transaction, and connection closed on every path? | A resource transferred to a documented owner |
| PP-COINCIDENCE | Does the code rely on reliable behavior rather than an accident? | Float comparison with an explicit tolerance |
| PP-COMPLEXITY | Is each function small enough to hold in your head? | A parser or dispatcher with inherent branching |
| PP-NAMING | Do names use the domain vocabulary and state intent? | Short names with strong local convention, such as i in a loop |
| PP-COMMENTS | Do comments explain why, and is dead code deleted? | A comment that documents an external constraint |
| PP-BROKEN-WINDOWS | Is every skip, suppression, and TODO bounded and visible? | A skip that links to a tracked issue with an owner |
| PP-TESTS | Do tests pin down the behavior you intend to keep? | Generated tests that assert an observable contract |
| PP-TEST-HYGIENE | Are tests deterministic and independent of the network and clock? | An integration test with a local, controlled fixture |
| PP-AUTOMATION | Are tests, linting, and release steps scripted and repeatable? | A documented manual step that cannot be automated yet |
| PP-VCS | Is everything in version control, with secrets and large files ignored? | A generated lockfile or vendored dependency |
| PP-E2E | Is there one thin path that exercises the real architecture? | A library with no service boundary to exercise |
| PP-DOCS | Does the README explain purpose, setup, usage, and tests? | A repository whose docs live in a separate site |
How to run the checklist in a pull request
- Read the change description. Write down what behavior should be different when the change lands.
- Find the boundary. Identify the smallest public surface that crosses into the change.
- Check the failure path. Follow an invalid input and an infrastructure error. Do they fail loudly with context?
- Check ownership. Follow every acquired resource to a guaranteed release.
- Check the tests. Remove one behavior and confirm a test fails for the right reason.
- Check duplication. Ask which representation is authoritative before suggesting an extraction.
- Record dissent. If a finding is a false positive, write the reason next to the suppression.
Automate the repeatable part
A checklist works better when the mechanical questions are answered before the review starts. The pragmatic-audit CLI checks 20 of these concerns, reports file and line locations, and produces a review packet for a coding agent.
pip install pragmatic-audit
pragmatic-audit .
pragmatic-audit . --agent-packet
The scan is a hypothesis generator, not a grade. Less than a perfect signal is not proof of poor design, and a clean signal is not proof of correctness.
Where the checklist stops
No static tool can decide whether a boundary is in the right place, whether a domain concept is named well, or whether an abstraction has earned its keep. Those remain human decisions. The checklist is there to make them explicit, not to automate them away.