Cracking the code review (Part 4): Conflict management

(This is the fourth part in a series about working effectively to pass code review quickly and without missed defects.)

Photo by bert sz on Unsplash

In the last post, I discussed how proactively involving your reviewers in your design and implementation process would get your reviews approved faster. The biggest risk of proactivity, though, is that one or more reviewers might disagree with you.

If we don’t manage arguments properly, things will come to a head at review time when your reviewer is free to let loose all their criticisms yet again. Then you’ll reply in kind, and so on.

Time spent going back and forth in a code review is wasted time.

Continue reading “Cracking the code review (Part 4): Conflict management”

Cracking the code review (Part 3): Be proactive

(This is the third part in a series about working effectively to pass code review quickly and without missed defects.)

Image courtesy of Reddit user andyjerbear

In the first two parts of this series, we discussed why code reviews needed to be small, and failing that, how we could make them seem small by managing extraneous cognitive load. There is a third way to make reviews go faster, and that’s by proactively ensuring your reviewers know a bit about what you’re working on before they review it (managing germane cognitive load).

Continue reading “Cracking the code review (Part 3): Be proactive”

Cracking the code review (Part 2): Make them seem small

(This is the second part in a series about working effectively to pass code review quickly and without missed defects.)

Image source: Wikimedia

In part one, we showed that, all other factors considered, the shorter the code review, the better. It may seem intuitive that this is the case. After all, barring some entry into a code obfuscation competition, even the worst written code can still be understood if it’s short.

But you’ve probably also seen code that was easy to understand despite it being many lines long.

Examples of this phenomenon include: a class rename that spans 100 files; a host of new Factory classes; addressing all instances of a specific compiler warning; or new functionality in a system that you originally authored.

These things seem small even though they aren’t actually. So, how do we really quantify "small"?

Continue reading “Cracking the code review (Part 2): Make them seem small”

Cracking the code review (Part 1): Smaller is better

(This is the first part in a series about working effectively to pass code review quickly and without missed defects. In this series I will use Git terminology with respect to source control and branch management.)

Photo by Jon Tyson on Unsplash

Let me tell you a code reviewer’s horror story. It’s the start of a sprint and Taylor is assigned to develop a spiffy new feature. They excitedly get to work. They carefully review all the requirements, spend a few hours on a whiteboard designing a solution, and then start by writing unit tests. After just 1.5 weeks of the 2 week sprint, Taylor has a robust, performant implementation that has 100% test coverage.

(shines flashlight under face) Then… they create a pull request into master for the code to be reviewed (frightened screams erupt from code reviewers around the campfire).

Continue reading “Cracking the code review (Part 1): Smaller is better”

Algorithms as objects

We usually think of an algorithm as a single function with inputs and outputs. Our algorithms textbooks reinforce this notion. They present very concise descriptions that neatly fit in half of a page. This is fine until one actually attempts to implement it as a single function; all the little details add up until you’re left with a gigantic, monolithic function.

That monolithic function lacks readability; it’s so long that you have to scroll for a full minute to get to the end. It’s nested so deeply that you have to scroll horizontally to read it. It’s nigh-impossible to trace the state of a variable that was declared at the top as it mutates every other line.

Because of that, the function also lacks maintainability. Any single line-change has the potential to affect the many lines below it, altering the behavior in unpredictable ways.

Nobody wants to touch this code because it’s such a pain to get any context. There are just too many details. It’s like trying to learn the purpose of an airplane by reading an aerospace engineering textbook.

Complex code requires abstractions. Abstractions help communicate higher level concepts, improving readability and therefore reducing the time to fix bugs or add new features.

A compiler takes code as input and spits out an executable as output. Do you think compilers are implemented as a single monolithic function?

There’s a good chance that your monolithic function should be refactored into one or more classes. It’s okay to implement an algorithm as an object. I encourage it, even.

In this blog post I’ll walk through a handful of code smells that indicate you’ve got a class instead of a function, and then follow it up with code examples demonstrating code that exhibits these code smells. Finally, I’ll demonstrate how we might refactor the offending functions into classes.

Continue reading “Algorithms as objects”