Communication is the key to readability
Writing code is a weird process. We try to communicate ideas in code, but in every other form of communication it is obvious who you are talking to. The writer doesn’t talk to the typewriter, they talk to the readers. The artist doesn’t talk to the canvas, though they may feel like it, they talk to the world. So who do programmers talk to, is it computers?
Reading is painful
I have sat at my desk with a crushing headache, slogging through code that lies to me, discusses how a file is written but not why, and hides away meaning. Attempting to scrape together some semblance of an idea of what is going on; to be able to feel comfortable making changes. More times than I care to admit, I have been in situations where I’m not 100% comfortable my change is safe. I always feel there’s something, somewhere, I have missed or misunderstood. This is a common feeling 1. Bad code, slows you down, tires your out, frustrates you, belittles you, and shows you up.
We expect this pain. We assume this pain disappears if we have more knowledge, or if we spend time grinding the system into our brains. This fails to see that even with decades of experience, the code we see is not easy to understand, and more knowledge has not made it more readable. It was never written with other people in mind.
The fact we can not understand the code, is more to do with who the intended audience is than our ability to read it. Reading code is like being an archaeologist. We uncover our find and sift through the code. Attempting to gain an understanding of what a group of people, over many years, have all tried to accomplish. We have the artefacts of their understanding, their competence, care and pressures. From these, we are expected to have enough understanding about the code, to see what is important, what isn’t, what questions it was trying to answer and the constraints in which they were answered.
The way we learn defines how we write code
Bzzt thump. The static quickly disappears, a blue screen is shown. Ready. The flashing cursor waiting patiently for me to tell it what to do. These are the first memories I have of learning to program. I was excited by the prospect of being able to control this machine, by learning how to communicate with it, I could get it to do things for me, create worlds!
10 PRINT “HELLO, WORLD!”
20 GOTO 10
If only learning to program was easy. When we first start programming everything is a struggle. We trip over the language, get sucked in by never ending frameworks, stumble about in the dark and eventually: “Hello world!” This struggle we have, focuses our minds to look at one line of code after another. Do this, then do that. We learn to think in steps; check kettle has water, turn on kettle, until boiled - wait. Step by step. These are little units of work that we describe in a language the computer understands. We tell the computer what to do, and how to do it.
This learning process reinforces the idea that we have to control the computer. That the code we write is all about communicating with the machine. There is little focus on learning how to express these ideas in a way people can understand.
The language of the computer
This conversation with the computer is also visible in the languages we use. Assembly language is a very definite set of instructions that the computer understands. Modern languages have built upon these ideas, focusing on simplifying these operations to reduce complexity. The idea of reducing complexity is also reflected in the principles we apply to the code we write. SOLID principles and clean code, focus on ensuring that the code we write remains maintainable.
Modern languages have allowed us to create more complex systems. By removing restrictions on names, allowing for more controlled modularity and higher levels of abstraction. We are slowly moving away from the language of the machine and moving towards a more human language.
The languages we use, the never-ending need to learn, and the process of learning, focuses on the way we get machines to do things, and the management of the resulting complexity. We think about development as a conversation with the machine.
It is time to take a step back. The languages we now use are far better at expressing complex ideas than before, the frameworks we use provide higher levels of abstraction than before, hiding away the vernacular of the machine. With a slight shift in perspective, we can produce more readable code. When we shift our focus, from controlling machines, and replace it with communicating with each other, we will write better code.
The pain of writing code
When the code is difficult to understand, it causes issues with the code we write. This creates a negative, self perpetuating, cycle of writing bad code. Rubbish attracts more rubbish.
You cannot sit down and write code in a system unless you understand it and understand what you are trying to achieve, what changes you expect to make, and where those changes will occur. From a lack of knowledge we will focus on what statements, variables, and functions are going to get the job done. We will tell the compiler, through a series of statements, what should be happening. While considering, good names, short methods and the like - to make sure that the code is maintainable. After we have something working, we pat ourselves on the back and move on.
Sometimes the changes come easy, at others we are physically ploughing the field, and often we are the surgeon, with the steady hand, making the smallest incisions.
The focus at the moment is one of struggle. To understand a system and coerce it to do something different. The issues we have revolve mostly around not having a good enough idea, about what is going on, to be able to make changes we are happy with.
Let’s try something else
Why are we not able to read the code? Because collectively we do not write for each other. I believe it is the sole responsibility of the author to ensure that they are understood. This is true in any medium where ideas are communicated. The idea has little value if it can not be presented in a way that can be understood. This process is hard, communicating across time to an audience of varying skill is not easy.
We are all authors of code. It is our job to ensure that our code explains itself to our audience. Not as is more commonly accepted, the job of the reader to learn more.
Perhaps you’re sitting there with too many ideas in your mind, fingers dancing lightly on the keys. Line after line appearing on screen as if your mind had melded with it. Or you have your head in your hands not sure how to progress. You try something out. Run it. Read some docs. Run it. Stack overflow. Run it. Slowly but surely you plough out a solution.
You now have your first draft. Having something that works is not a licence to walk away. It is not the job of everyone else, like archaeologists, to reconstruct everything in your head, from the small amount of code that remains from your hard work and effort.
Now you have figured out what you want to say, you now have to figure out how best to say it. Drafts are revised, great work does not just fall out of heads into Visual Studio Code. Consider the language that is used, does it explain itself to people, does BlockContentGet(5, bool)
reflect the fact we are getting the latest news?
Yes, that is a massive generalisation, but it makes an important point: we do not give consideration to our audience, other developers. Not all code is this bad, but most code is not good. It expects you to use your encyclopaedic knowledge of the language and frameworks, to work backwards from language the machine understands, to something you understand. It’s like playing Chinese whispers in a foreign language.
Try a little process after you have finished your work, talk someone through it, even if that person is in your head. This will highlight differences in the language you have used in code, versus the language you use to explain it. It will highlight information you have assumed. When reading code in reviews, ensure answers to the questions you have make their way back into the codebase. Throughout the writing and review process, we should concentrate on communication ahead of structure or the use of if statements. Poor code you can understand is easier to change, than well organised code that is difficult to comprehend.
Conclusion
With modern languages and frameworks, we are able to work at higher levels of abstraction. Separating the code in the trenches from that which orchestrates. Now able to instruct the compiler with relative ease, we are able to focus on communicating with each other instead.
The key to readability is communication. Not talking to machines, about sequence, selection, and iteration. But to each other, communicating ideas and intent. A shift in perspective, that expects more and delivers more. Focusing on the realities of teams and complex systems, where breakdowns in communication cost. From more configurable to less, from by convention to by design. Being more explicit about our changes, and making changes from a position of understanding.
You are the author and you are responsible.