Monday, January 3, 2022

Readability

In order to be useful, code needs to be readable.

If it’s not readable, then as things change, it is difficult to update. That has the unwanted side-effect of freezing the code in place with all of its defects. This leaves 2 bad choices: either spend a lot of effort to rewrite the code or just blindly build on top. Any code built on top or around defective code inherits its undesirable qualities.

So, unreadable code might suffice to meet a tight deadline, but its intrinsic tech debt will continue to grow.

You can reflector unreadable code into something better, but it is actually a lot less effort to just not make it unreadable in the first place. Some programmers wrongly assume that it is faster to create unreadable code, that any work to prevent that is extra and slows down the effort, but oddly unless the initial typing effort is perfect (which is so rarely the case) fixing the time spent the first round of syntactic and semantic flaws will quickly negate any perceived gains. So it is usually slower to write unreadable code and it only gets worse as it stays around in the codebase.

The most obvious factor in readability is naming. People generally believe this to be hard, but the names of most things in code come either from the problem domain or from the technical one. If naming is complicated it is usually a huge warning sign that either sufficient analysis and/or design has been skipped. That is if you don’t know what you are writing, then, of course, you don’t know what the pieces should be called, but you are also just taking a random shot at being able to craft the ‘correct’ piece of code, which usually ends up wasting a lot more time as you keep having to fiddle with it.

If you know the names of the data and functions involved in the code, the next big issue is structuring the code correctly. The easy problems in programming generally involve getting data from one location and sending it to another one, so the structure of the code is rather trivial. It gets a little more difficult if you also handle any errors properly, but there are plenty of straightforward paradigms for properly arranging this type of behavior. Some system-level code, like interpreters and operating systems, requires non-intuitive structures in order to keep the code organized, but they are well documented and there are plenty of resources available to learn the proper techniques. You just have to do the research first, before starting.

The biggest problem in structuring code is reuse. You might have dozens of screens that are each easy to write, but all pretty much share the same underlying code. It is an ‘epic’ waste of time to just write each one in its own silo. The code is hopelessly redundant, but the testing is also long and painful. So, the smart thing to do is write some underlying base code that contains the bulk of the work, then trivialize each different screen on top of it.

That reuse pattern also occurs when managing persistent data, doing imports and exports from other systems, and when keeping some other system synchronized. The super-difficult problem however is not just reusing the code, but rather doing it in a way that result is actually far more readable than just a large bunch of brute force silos. That can happen though if the levels between the parts of the code are not random, but rather they properly encapsulate different types of complexity for the different pieces.

When you encounter code that is well structured, you tend not to notice the care and effort that went into the workmanship. Instead, the code just seems rather obvious, it flows quite easily.

And that brings us to the most difficult aspect of readability. If you write some code, you will think that it is readable as you are working on it. But it still might be filled with a lot of weird, awkward, and eclectic stuff that other people would find difficult to understand quickly. That is, readability may be considered subjective when it comes to your own work, but as more people look at the code it becomes considerably more objective. So, the real measure of readability is in trying to make it quickly understandable by the largest possible audience. You really want to present the code in ways that make it inclusive to as many people as possible.

That means picking a few simple patterns that are applied consistently across all of the code. That means trying hard to not just throw in as many dependencies as possible. It means augmenting the code with any type of comments the reader needs in order to see the code the way you saw it when you wrote it. It means spending some time and effort trying to look at the code and see it the way other people will see it.

There are still people out there that believe that creating an obfuscated spaghetti codebase is job security, but that’s actually a very foolish belief. You don’t want to get stuck spending the rest of your life struggling with the mess you created, so it’s far better to create things that you can hand off to others. That helps with getting better work in the current company, but it also helps in creating lots of other opportunities in other organizations as well. Nobody wants to work with a difficult programmer again, which means that each bad experience is dwindling the possible market of new ones, rather than increasing it. In that sense, it’s not only better to write readable code now, it is also going to help you a lot in the future even if you switch jobs.

It’s also more fun to work on a well-written readable codebase. If there is a huge amount of redundant code, then it becomes increasingly likely that any given little code change will cause nasty unexpected side-effects somewhere else. So, it’s scary and super stressful to make changes. And since there is never enough time and effort put into testing, a lot of bugs seriously hurts the whole project. Thus making good changes becomes harder and harder, until the project is nearly frozen in place and everyone is angry.

Contrast that with a project where you can make a lot of good enhancements with very little stress. If the code has a lot of reuse, you can use the tools in the IDE to quickly visually check that the changes will not have unintentional side effects. A small amount of effort, but a huge gain.

As well, one little change may fix a bunch of related issues all over the system, so it looks like people have put in a lot of care and effort. So, it’s way less stressful, a little bit of extra work, but to the users, it looks like the project is moving forward really quickly now. And there are plenty of battle-tested components around that you can rely on to speed up the development, so you get much better quality at a faster pace. Instead of falling farther and farther behind in the development, you can start pursuing deeper and more meaningful changes, so people are excited and happy about the progress. It’s fun to work on, and you feel good about it.

Ultimately it’s not that hard to make code readable and it’s not that much “extra” effort. If the project starts off that way, the results will be far better. Skipping this work may get you to an early deadline slightly faster, but as the costs build up it will continually cripple the work. It’s harmful and crazy to intentionally write bad code, it’s insane that we keep encouraging it. Code isn’t disposable, it takes a lot of time and effort to get it working correctly, so it’s far better to write less code that is of good quality than it is to just spew out lots of junk code. We don’t need more code, we just need better code now.

No comments:

Post a Comment

Thanks for the Feedback!