Summary

Programmers routinely complain about code being “unreadable”. They also routinely argue, sometimes quite heatedly, about how to make code “more readable”. I have noticed a conflict that they might be missing which could help moderate those arguments and make them more constructive.

I have written before about why I don’t like to label code as “readable” or “unreadable”, but sadly, this has not stopped the world from doing this. I have lodged complaints with the appropriate departments.

I believe that programmers generally want to spend less energy trying to understand code. Since humans are energy-conserving machines, this feels like a reasonable belief. Programmers, then, want code that costs less to understand so that they can change it safely and accurately. “Costs less” can be (somewhat) measured by time, energy, or even money. I’ll assume, for the rest of this article, that we share the goal of making code less expensive to understand. I might even call this the primary goal of “software design”.

In order to make code less expensive to understand, you have two key strategies: simplifying it or becoming more familiar with it.

By “simplifying” code, I mean reducing the number of things you need to know in order to understand the code. This tends to mean things such as moving irrelevant details out of the way and making relevant details easier to see. Becoming familiar with code usually only happens by spending time engaging with the code, such as by reading it or testing it or trying to change it.

It makes sense to try to simplify code, because this activity both reduces the amount of code you need to become familiar with and is itself an activity that causes programmers to work with code and become more familiar with it. The act of trying to simplify code helps programmers understand code sooner both by reducing the necessary investment and by also being part of making that investment. It seems like a win-win.

This is why we refactor, remove duplication, improve names, introduce abstractions, add tests… all the things that we have been talking about and debating over the decades.

What’s the Catch?!

Sadly, in order to simplify code, we risk making it less familiar. This happens because we:

  • introduce libraries that not everyone knows
  • introduce abstractions that not everyone has participated in choosing
  • need to name new design elements and we’re not excellent at naming

Not only that, but while we are in the relatively early stages of learning to do these things, we have to overdo them in order to form the judgment to do them correctly and appropriately and judiciously.

Simplifying code therefore risks making it less familiar. When we do this, we are betting that the savings from simplifying will be greater than the additional costs of losing familiarity. We’re also betting that it will become cheaper to invest in restoring our previous levels of familiarity.

When we simplify code in a way that makes the code less familiar, then I recommend focusing on improving names to make the code more familiar to your intended audience. In the process, according to The Simple Design Dynamo, you would iterate through removing duplication and improving names until you reached a new balance point where you judged the code as “good enough” to move on. When does this happen? Probably when the act of simplifying the code has given you a chance to become familiar with it again. Your subjective experience of becoming familiar with the new design informs your choices to remove duplication and improve names in a way that helps the code be more familiar to the other programmers not actively involved in your work.

In short, you’d start by focusing on simplifying the code, then you’d gradually transition to making the code (more likely to seem) more familiar before declaring victory and moving on.

So What?!

And here is the key point: we must be prepared to make the code less familiar for some time in order to simplify it. I believe the real power of the work lies here. If we are not prepared to let the code be less familiar for some time, then we will only ever simplify it when there is a clear, obvious way to simplify it. That can help, too, but I believe you would miss out on powerful opportunities to improve the design if you stuck with such a conservative, passive strategy.

Many of those programmers arguing heatedly in meetings about refactoring are objecting to changes (or refusing to merge PRs) only because the code has become less familiar to them. Their reaction seems perfectly reasonable to me, but I believe it is ultimately self-limiting. When you add to this situation the tendency to conflate complicated code and unfamiliar code as “unreadable”, those arguments become nearly impossible to resolve without resorting to dysfunctions such as deferring to the Highest Paid Person In the Room or the Loudest Person In the Room. You need another tool to avoid this fate:

If you want code to become less expensive to understand over time, then I argue that you must be willing to risk the code becoming unfamiliar; otherwise, you will miss your best opportunities to simplify it.

Do you struggle with technical leadership issues such as this one? Do you want to take advice like this, but feel emotional obstacles that you don’t quite understand or know yet how to deal with? I believe I can help. It’s not free, but software development professionals are getting the help they need as part of The jbrains Experience.