This is a book I read recently. I’m not sure what prompted me to start but is is a relatively concise book that doesn’t take too much time to get through. The core premise is that code health is something you should care about and want to improve. It lays out some things you should focus on. The biggest inspirations of the book are philosophy of software design and pragmatic programmer. The author even calls this out so if you’ve internalised those you probably know a lot of what goes on here but seeing the same information in a new light with a new shape around it can help a lot to learn it.

One thing I do want to pick on though is it is not a book about AI, despite being in the subtitle. I didn’t pick it up to learn about AI so wasn’t a big deal, just I think tacking on AI to get more interest in it is not what I like. AI is changing so rapidly that whatever goes in print is going to go stale quickly so it is probably a good thing that the subtitle is almost the only mention of AI in the whole book.

Why care about Code Complexity?

Finally, the worst thing about the codebase complexity is that there is almost no way back. Complexity grows incrementally, making it extremely hard to reverse the damage. At some point, you may decide to win it back—to refactor your code into something reasonably simple, but after multiple weeks of dedicated refactoring efforts, there would likely be very little progress just because it’s impossible to pinpoint the origin of all that complexity. And there is no single origin. It’s thousands of minor complexities that accumulated and interconnected over time. We had a team in Google Maps that was moving fast until they couldn’t, so they had to take a break and spend over a year just refactoring their code.

I do see similar things with modern AI coding with this respect where debt accumulates until it seizes up all forward motion. AI just turbocharges the forward momentum until you get to the same point. Complexity in code is unavoidable in parts but we can structure it so that it doesn’t hinder us

following to be one of the most fundamental facts in programming—“isolating complexity in a place where it will never be seen is almost as good as eliminating the complexity entirely”

What is Healthy Code?

To put it positively, a healthy code is healthy because it:

  • Looks familiar
  • Has little to no obscurity
  • Has little to no duplication
  • Has a reasonable number of stable dependencies with true and simple interfaces

What is Code Complexity?

Code complexity is not a single problem. In fact, there are three problems: change amplification, cognitive load, and unknown unknowns. Change amplification is the least critical one as it typically doesn’t lead to exhaustion or bugs—it just slows you down. Unknown unknowns is the worst one as it makes you rely on luck when making changes.

Code Quality vs Style

There are hardly two concepts that are more different from each other. The whole language style guide is typically several pages long. It can be automated by your code formatter and enforced by continuous integration (CI). But most importantly, the only thing we care about with code style is its consistent application. The specifics of any particular style guide typically just do not matter!

On the contrary, code quality is extremely important, highly nuanced, and hard to formalize. You can write hundreds of pages on this topic and just scratch the surface. Healthy code is a synonym for a high-quality code

As a code reviewer, you’re responsible for ensuring code health, but it’s CI that is mostly responsible for the code style compliance.

Contracts

Contracts should be clear, concise and complete. It is a continuous effort and a shared responsibility to keep them that way

Interface Simplicity

Code complexity as a formula. I dislike these kinds of things but the concept is the following quote which helps understand what kinds of things to focus on.

complexity of a codebase is a weighted average of complexities of its parts, where weights are the time developers spend working with those parts.

Simple interfaces are your top priority as a Code Health Guardian. “Simple” here means not only easy to read but also easy to use, which typically means deep. Aim at building all your modules deep, and try to keep them small as long as it makes them more readable and not dysfunctional. At the same time, feel free to write large modules if decomposing them into smaller ones is problematic.

Dependencies with deep contracts provide you with a substantial value at the cost of adding a little bit of complexity. In contrast, dependencies with shallow interfaces provide little value at the cost of adding substantial complexity.

Interface simplicity is not a new thing and has been repeated elsewhere don’t let that take away from the importance.

Semi-Functional Programming

A perhaps new definition but a worthy one. I never put a name on this before it but it is something that feels right and what I’ve often written code in mind of doing without exactly naming or defining the concept. The core idea is to try not mutate things as much as possible

“we should strongly prefer immutability over mutability.” It’s mostly the lack of side effects and immutability that makes functional code easier to reason about.

It’s much easier to reason about a piece of code if the vast majority of the objects involved cannot change, and those that can stand out.

Here are the three principles of semi-functional programming:

  • Strongly prefer immutable objects and collections.
  • Treat function parameters as read-only.
  • Make all the mutability explicit.

Semi-functional programming is all about immutability by default. This is certainly so for objects and collections, and maybe even for the variables themselves as well. It’s about functions that don’t modify their parameters. However, at the same time, it’s about being flexible enough to allow mutability where it’s handy, but ensuring such mutability is explicit.

Working in Teams

in the order of decreasing impact on team productivity:

  • Psychological safety
  • Dependability
  • Structure and clarity
  • Meaning
  • Impact

Psychological safety is the most important one out of them all

Here is the final list of the six rubrics to keep in mind when reviewing a PR:

  • Test coverage: Are all the necessary tests there?
  • Correctness: Does it look correct to you?
  • Complexity: Is it the simplest change possible?
  • Security: Are there any security issues?
  • Documentation: Is there any relevant documentation, and is it (still) accurate enough?
  • Consistency: Does the code follow your style guide, and does the solution fit well into the overall architecture?