Originally published on opensource.com.
As a Project Team Lead for OpenStack Quality Assurance, code review was my daily work. Not occasionally. Daily. Dozens of patches a week, across a large codebase, from contributors ranging from first-timers to decade-long veterans. After doing that long enough, you develop a mental checklist. This is mine.
What I want to make clear upfront: you don't need to be a language expert or a project veteran to give a valuable review. Code review is about bringing a fresh pair of eyes and a new perspective. The voting system in open source projects lets you express an opinion without requiring absolute authority; disagreement between reviewers isn't failure, it's how good code gets made. The only bad review is no review.
The 10 steps
1. Understand the change
Start with the commit message. What problem does this code solve and why does it matter? If that context is missing or unclear, ask for it before going further. Reviewing code without understanding its purpose is how you miss the important issues and fixate on the trivial ones.
2. Consider alternative approaches
Before diving into the details, ask yourself: how would I have solved this? If your answer is meaningfully different, raise it, not as a rejection but as a question. Sometimes the author considered your approach and rejected it for a good reason. Sometimes they didn't think of it. Either way, the conversation is useful.
3. Run the code
Execute it. With and without the change. If running the full project isn't feasible, isolate the function and test it with simulated data. Reading code and running code are different activities that catch different problems. Don't skip the latter just because the former was fine.
4. Assess potential breakage
Think through edge cases. Will this work across all supported configurations? Are new dependencies compatible with older environments? Does the change introduce any security surface? Will command-line options behave correctly everywhere they're used? This is the step where experience with the project pays dividends: you know where the bodies are buried.
5. Evaluate code style and effectiveness
Check whether the solution follows the project's documented style and conventions. Most mature projects have a style guide (OpenStack has HACKING.rst, for example). Consistency with the existing codebase matters. A patch that solves the problem but looks like it belongs to a different project creates maintenance debt.
6. Verify there are no unused variables or imports
Every new import and every new variable should serve a purpose. This is easy to miss, especially in larger patches where something gets added early and then superseded later. Linting tools like flake8 catch most of these for Python, but don't rely on automation alone: a linter won't tell you that an import is used but shouldn't be.
7. Check for duplicate functionality
Before approving a new function, check whether similar logic already exists elsewhere in the project. Duplication is one of the most persistent sources of technical debt. If the author didn't know the existing utility was there, telling them is a genuine contribution, not a criticism.
8. Require unit tests
New functions and changes to logic should come with tests. This is a reasonable expectation to hold consistently. If a patch adds meaningful behaviour without a test, ask for one. The answer to "how do we know this works?" shouldn't be "we read the code and it looks right."
9. Verify refactoring completeness
When code is refactored (a function renamed, a parameter removed, a pattern changed), every occurrence in the codebase needs to be updated. Use grep or your search tool of choice. A refactor that's half-applied is worse than no refactor: it leaves the codebase in an inconsistent state that will quietly break things.
10. Check whether documentation needs updating
If the change affects user-facing behaviour (new options, changed defaults, removed functionality), the documentation should reflect that. This is the step most commonly skipped, and the one that causes the most confusion for users six months later.
A note on how to give feedback
Technical correctness is only part of what makes a review useful. How you communicate the feedback matters too. Ask questions rather than making pronouncements. Explain your reasoning rather than just pointing to a problem. When you're not certain something is wrong, say so: "I'm not sure about this, but have you considered..." is a perfectly good review comment.
The goal of a review isn't to find fault. It's to make the code better and help the author improve. Those are related but different things. A review that catches every technical problem but leaves the author feeling beaten up has failed at the second one. In a community that runs on volunteer effort, that matters.
