Esp. if there is a very large code base and if the team is also doing some level of test-driven development, it is not practical and also does not make sense to do review of entire code-base. In such a case, how do we decide which parts of code to review and whether it is effective at all? This question is also related to 527259.
The parts you're working on now.
Also, the parts with the highest bug frequency (which should be some of the parts you're working on now).
You can use a code metrics tool and run it against the code base and find the most complex pieces of your project that have been worked on most recently.
I generally check the contracts of the various classes and methods. Do the methods make sense, are the pre and post conditions well defined,etc. And I check if there are any obvious code smells (http://c2.com/xp/CodeSmell.html). And if TDD is being practiced, it is good to review the tests first, it will give an idea of how the code is working and also if all the conditions are being tested.
I would focus on those areas that are important to the business objectives first, then those areas that are performance sensitive. For example, if your application is crunching data, review the algorithms doing the data reduction for correctness.
- Code that is used very often in code.
- Business critical code.
Edit With "Code that is used very often" I mean Code that is used often in code. not necessarily code that is used often by the user. There is a big difference since code that is used often is a target for change. Now I'm not saying that code should not be reused. What I'm trying to say is that when code is beeing reused. It deserves more attention and is therefore good to review.
Someone should review every single line of code that changes. If there's too much code in a single change to review, then you're changing too much, and you should consider breaking down the change into a series of smaller changes.
Not everyone needs to review every single change, but every single change should be reviewed by someone. No one writes perfect code.
I always start with the parts that are "ugly" in the sense that there's either little commentary, poor variable name choices like xx1 or such, or any place that decides it doesn't want to use encapsulation. Those almost always strike me as places that need to be reviewed. After that, I agree with the "most complex" comment from above.
You should code review the areas of code that have changed in the current development iteration/relate to the specific dev case.
e.g. the way it works for me, in an environment where we use Fogbugz: - a fogbugz case is worked on by a developer - the developer does the code changes, checks in to subversion and the files changed get linked in to the fogbogz case - developer assigns the case for code review - code reviewer looks at the files changed for that case/the changes made (listed via the "Checkins" list associated with the case) and checks that the changes made make sense/are correct. - if all OK, code reviewer marks the case as resolved/completed, else assigns back to the developer with comments
One motivation in code review is to find bugs. Another is to expose more developers to parts of your code base they don't normally see. This helps educate junior coders. It also helps to assure that you don't have big problems when a developer leaves - because they're the only person that knew how something worked.
So:
Review the parts of the application that are scary. Especially the parts that you would hesitate to work on, or tell a junior not to work on.
Old programs often have areas written by developers who no longer work at the company. Often this stuff gets really crufty because newer developers won't take the time to understand it before making changes. Review that.
Review all code that is only worked on by one person.
Review anything really complicated.
If the team is using TDD, one code metric you can use is code coverage: a class with low test coverage is a solid candidate for review.
A tool like NDepend can help you also visualize both the complexity of various pieces of your codebase, as well as which pieces depend on which.