My team uses a code review checklist to prevent stupid mistakes from causing us problems and wasting time. In this post, I want to share the reasons we decided to implement a code review checklist, what's on our checklist, how we created, use, and improve our checklist, and how it's improved our effectiveness.
When we looked at the flow of stories across our sprint board, we immediately zeroed in on our review process as our bottleneck. More often than not, stories ended up in our "reopened" status (failed code review) than our "done" status. And when we tracked why our stories failed code review, we found all kinds of reasons related to the quality of the code itself. But we were surprised to find just how often we made a stupid mistake. Examples include forgetting to run the unit tests or missing a requirement. In fact, "stupid mistakes" caused of the vast majority of our failed code reviews.
But we'd also occasionally end up with a defect in production when we missed a step or performed an ineffective code review. It's really embarrassing to tell your boss that you took down the website because you messed up something simple.
I had read The Checklist Manifesto: How to Get Things Right (Atul Gawande) a few years ago and immediately recognized that this would be an excellent opportunity to use a checklist.
Checklists are great way to ensure you cover all the steps in a complicated task, like a code review. Instead of having to remember what to look for and review the code, you can just review the code and trust the checklist to ensure you cover all the important points. As long as you actually use your code review checklist (and the checklist is well-constructed), you should catch the vast majority of stupid mistakes.
Our code review checklist has evolved over time. Here's what my personal version looks like right now.
Code Review Checklist:
- scope - story is high priority, small, minimize creep, no stray changes, off-task changes added to backlog
- works correctly - specification is correct and complete, implementation follows specification, testing plan created, unit tests created and/or updated, master merged into branch, all changes tested, edge cases covered, cannot find a way to break code, cannot find any ways these changes break some other part of the system, all tasks 'done', ZERO KNOWN DEFECTS
- defensiveness - all inputs to public methods validated, fails loudly if used incorrectly, all return codes checked, security
- easy to read and understand - appropriate abstraction and problem decomposition, minimum interface exposed, information hiding, command-query principle, good naming, meaningful documentation and comments, fully refactored (use judgement with existing code)
- style and layout - all inspections pass, code formatter run, no smelly code styling, line length, styling consistent with project guidelines
- final considerations - YOU FULLY UNDERSTAND THE CODE AND THE IMPACT OF THE CHANGES YOU HAVE MADE AND IT... is unbreakable, is actually done, will pass code review, would make you proud to present your changes to other programmers in public, is easy to review, correct branch, no stray code, schema changes documented, master merged into branch, unit tests pass, manual testing plan complete and executed, all changes committed and pushed, pull request created and reviewed, Jira updated
My team's official checklist doesn't include step 6. That's my own personal reminder of things that I find important to check at the very end of the code review.
Some people might say that our checklist contains way too much detail. That's probably a valid complaint. However, this is the checklist our team developed and it works for us.
We created our checklist by looking the steps in our code review process and the problems we were having getting pull requests to pass review. Then we gathered all those details into an initial code review checklist. We organized and refined our initial checklist over several weeks.
Once we were happy with our code review checklist we converted it into a Google form. We also included some additional fields for data that we wanted to capture about our code reviews such as:
- the name of the author and reviewer
- how long the code review took
- the outcome (pass/fail)
These fields are important because they give us the feedback we need to monitor the success of our code review improvement program.
The author of a pull request does a self-review on his code using the code review checklist. He corrects any issues he catches and then releases his pull request for review.
The reviewer uses the Google form version of the checklist to guide the review and capture a summary of the outcome. We typically complete the Google form in under two minutes. We attach specific and detailed feedback for the author about the code itself in BitBucket.
The Google form stores the results of our codes review in a Google spreadsheet. We look at the data every two weeks as part of our retrospective meeting where we evaluate the effectiveness of our code review process and see how it's changing over time.
We've found self-review to be just as important as the peer review. It's surprising how many issues you catch when you step back from the details and subject your code to a checklist. Our checklist is especially good at catching things we forget to do. For example everyone occasionally forgets to implement a requirement. Without a checklist to remind us, we find it hard to see what's missing from a pull request.
Our code review checklist is a living document. We review it periodically and add or remove issues as necessary. We also encourage programmers to keep their own version of the code review checklist. Personalized checklists contain reminders that are important only to the person who wrote them (like section 6 is for me - see above).
We couldn't be happier with the results of our code review checklist. We've made a serious dent in the number of code reviews that fail for stupid reasons. Every failed code review costs us a serious amount of time. And code reviews that fail for stupid reasons--like a missed requirement--are an extremely preventable form of waste. Furthermore, we conduct our code reviews more quickly and the process is more consistent because we use a checklist. We've significantly increased our effectiveness.
We also use our code review checklist to identify automation opportunities. When we first started doing code reviews we had lots of issues with code formatting, styling, naming, method complexity, etc.. We quickly realized that these issues were costing us lots of time and that they would be worth standardizing/automating. So we configured a code formatting tool and various static analyzers. They run automatically right in our IDE. Automating those steps gave us a huge boost in effectiveness--really outstanding.
These days our checklist is showing us the high cost of our manual testing procedures. So we're putting more effort into testing automation in cases where we think there's a healthy ROI.
There are tons of resources for programmers who want to start using checklists. But I'll just mention a few here:
- book: The Checklist Manifesto: How to Get Things Right (Atul Gawande)
- article by Atul Gawande: The checklist
- book: Code Complete (Steve McConnell) contains many checklists for various software engineering activities
- article: Why You Need a Checklist: Practical Takeaways from The Checklist Manifesto
- article: 11 proven practices for more effective, efficient peer code review
Checklists are a proven way to increase the effectiveness of your code reviews. It took us maybe a dozen hours to get our initial version of our code review checklist up and running. And that tiny investments pays us dividends every day.
Do you use a code review checklist? Share your thoughts in the comments.