Code Review – Part 1: Clear vs Clever Solutions

Of all the Go proverbs, my absolute favorite is “Clear is better than clever.” When conducting code reviews some of the main things I focus on are solutions that are clear and straightforward and solutions that are easily debuggable. 

The Cost of Cleverness

When writing Go code it is critical to emphasize clear solutions over clever solutions. At some point almost every developer that works in teams has come across the “clever” programmer. This is someone who treats writing code like solving a puzzle as though it exists for their amusement. As developers, it is critical that we understand our role in the business. Our role is to create products that deliver real value. This means when we optimize, we want to optimize for debuggability. What’s most critical for our products is the ability to identify and fix problems quickly in production and clever solutions are completely antithetical to this. The real cost of cleverness comes when a production service goes down and we end up tracing through a complex web of clever solutions to find the problem. In my experience this is very often seen with things like overuse of reflection, forcing complex inheritance, and over-engineered dependency injection frameworks. Reflection is probably the biggest of these as can be seen in the Go proverb “Reflection is never clear.” These are things to look out for and call out as code reviewers while emphasizing the reasoning behind them to younger developers.

Code Golf vs Code Clarity

Code golf is a common programming challenge where a developer tries to write a solution in the fewest possible lines. This is another self-imposed challenge wherein developers treat writing code as a puzzle rather than as a communication of intent. This mentality inevitably leads to lack of clarity and makes this code more difficult for other developers to understand and debug. One of the Go proverbs is “A little copying is better than a little dependency”, practically speaking this means that copying code in Go is not frowned upon in the same way that it is in other languages and the common idiom Don’t Repeat Yourself (DRY) is not applicable in Go in the same way as it is in, say, Java or C#.

Trusting the Compiler

Go’s compiler is very smart. When developers are refactoring or trying to come up with the most performant solution, the compiler will actually compile it to something better anyways. Here are a handful of examples regarding this.

  1. Inlining solutions (pasting function code rather than calling a function) doesn’t get a performance boost the way that it would in a language such as C. There is minimal function call overhead and this is best left to the compiler to handle.
  2. Writing code to “keep things on the stack” often backfires. The compilers escape analysis is better at this than developers are.
  3. Optimizing out “Dead code” that makes things more clear is pointless, the compiler will remove this anyways. This does not mean don’t remove any dead code.

For all of these, it is important to note that the emphasis here is clarity. This means that when you are sacrificing clarity for some sort of clever performance boost, the compiler will often do these things anyways. I am not saying never do these things. The approach when optimizing code in Go should always be “Write clear code, profile if slow, optimize based on profiler results.”

Conclusion

For all of these it is important to note that I am not saying never do anything clever, the important takeaway is that clarity and debuggability are far more important. Clever solutions are often self-defeating in a number of ways in addition to muddying the waters in the codebase. When conducting code reviews, it’s important to keep an eye out for these things and most importantly to use these opportunities to teach greener Go developers the right way to do things.

Share this blog post:

Related Posts