Code reviews can be a common practice for many developers: another engineer, often more experienced with the language, library, or code base being used, meets with the author-developer to read through their work, ask questions, and provide suggestions for improvement.
This process can be a positive experiment for many, but often, it can be challenging to be on the receiving end of a review. These can descend into demands for needless uniformity of style ("no! it's super-important to align your code just so") or they can create uncomfortable or harmful power dynamics between peers about whose style or ideas are "better." At their very worst, code reviews can merely provide cover for biased viewpoints or microaggressions directed toward developers who may have less power in organizations.
While we recognize that not all parts of this practice are always helpful, we do encourage a lot of code reviews for our students here at Rithm. We think that, especially for newer developers in a class, these can provide useful feedback and lessons that can be difficult to get from lectures or books, and can also be hard to notice just from reading other code.
Possible Benefits
Some areas we think code reviews can help learners:
Common Language Idioms
In most programming languages, there are small patterns or idioms that are often used to solve problems. Typically, these can be one of a set of possible ways to write the code, but where one case is so widely used that other developers may be confused by a different approach.
For example, in JavaScript, if you had an array of prices, and wanted to create an array with those prices that incorporated a 9.5% sales tax, you could write this like this:
let taxedPrices = []; for (let i = 0; i < untaxedPrices.length; i++) { taxedPrices.push(untaxedPrices[i] * 1.095); }
This is a straightforward solution, but it's not the idiomatic approach a lot of modern JavaScript developers would use. Instead, many would now do this with the .map
function of arrays and an arrow function, like so:
let taxedPrices = untaxedPrices.map(price => price * 1.095);
While this example is a simple one, and might be obvious to developers who use .map
and function expressions often, for newer developers, it can be difficult to recognize where new language features are commonly-used, and to recognize those places where their developer peers are most likely to use things like conventional variable names, useful standard library methods, or common functional idioms.
Recognizing Unexpected Edges or Bugs
One of the most challenges things for developers, both newer and more experienced, is debugging their own code: both because code can be very complex, but also because we often create bugs via our own blind spots in thinking through a problem. If you're tasked to write code to deal with information about companies, and you envision that all companies have a least 1 employee, you may easily write code like this:
if (company.numEmployees) { // do something with this company } else { // looks like we don't have a "numEmployees" property on this object, // since we got undefined... }
However, that else
condition would be triggered not just if the numEmployees
property were undefined
— it would also be triggered if there were zero employees. This might be a very legitimate case (some community nonprofits have only board members, for example, and no paid staff).
The bugs that come from assumptions like these are tricky because, even with careful re-reading, we often read our code optimistically with our assumptions in mind. In many ways, it's similar to the challenges many have try to proofread our own writing: we tend to read our own work differently than others, and can more easily miss grammatical, spelling, or phrasing errors.
Good code reviews can help you clarify what your assumptions were: is the data always required? What can of unexpected input might be received? Clarifying these kinds of things can help you write better code and better tests.
Getting Feedback on the Understandability Of Code
It's often difficult for developers to know how well others will be able to understand their own works: six months later, will that variable called infoObject
help the next maintainer? Are the functions broken down in ways that are likely to confuse readers?
This is another area where it's difficult to do our own judging—since we chose those names, we're able to substitute in our heads a clear understanding for its purpose, and may not notice the challenge of a vague name like data
or a misleading name, like price
when it actually represents an array of prices.
In a good code review, you can leave with an understanding of where you might refactor names or approaches to help other readers.
Double-Checking Documentation
Quality, professional code is documented. However, even with the best intentions, this documentation can be vague or outdated unless it is carefully checked.
This is another area where it can be hard to judge your own work: comments in code can often omit uncommon cases (what should this function do if it's passed in different data than expected, for example?) It also easy for the phrasing of comments or docstrings to be difficult to parse.
In a good code review, the reviewer can read your documentation first, to see if from this, the can understand the purpose and approach of that part of your code. Then, they can compare the actual functionality to that, and can often more easily recognize gaps between the comments and the code.
Tips for Good Reviews
To help get the most out of a code review for a new developer, make sure you share an understanding of what both parties want: is this a required sign-off before new code enters a real code base? Is this an instructor reading student code primarily to help give them advice? Does the code-author want tips on how to best express themselves, or are they primarily interested in ensuring their fundamental approach is promising?
It's often helpful to understand that code reviews can be a fluid mix of bugs, ideas, and opinions. It can be frustrating to get two different reviews and hear that you should solve your problem one way, and then hear from another that you shouldn't. Framing this as a learning opportunity can be useful: "Jessica really suggested I break this into smaller functions, and I know we often talk about testing, so let me ask her if this could help me write tests better, whereas Jade thought I should merge this into one big component—she and I have been talking about performance, so let me ask her questions about the tradeoffs that could introduce." Sometimes this can turn the annoying experience of contradictory advice into twice the learning points.
Hopefully, this can give you some ideas on why you might want to seek our plenty of code reviews, especially as you're first working with a new language or library. We hope you benefit from the ideas they can bring forth!