Code is a manifestation of understanding.
A programmer gradually builds up programming instructions based solely around the knowledge they have acquired. If they don’t know or understand something, it is unlikely that the runtime behavior of their code will meet expectations.
In reading code, we usually get a sense of the clarity and depth of the original author. If they were confused, the code is confused. If they saw the problem clearly, the code lays it out in neat organized blocks. In that sense, it isn’t all that different from writing, in that the writer leaves personality traces in their text as well, it is just that for writing that makes it interesting while for code it adds accidental complexity.
Reading good code can be similar to reading a novel, in that, during the process the reader isn’t aware of the syntax and grammar, but rather just visualizing the story as the author has laid it out. This requires that the writing of the text isn’t awkward, so the reader flows smoothly through the work. The same is essentially true of well-written, readable code. The reader gets the narrative from the code, without necessarily getting bogged down in the syntax or underlying calls. That narrative explains how the data flows or the components interact. That is its story.
If code is quick and easy to read and confers a strong understanding of its purpose, it is elegant. This obviously requires a significant editing stage, just like editing a novel. The code is reworked, over and over again, until it flows.
Some types of changes intrinsically degrade the quality of the code. Often when programmers locally optimize, their work ignores the greater context, so it is really just causing obfuscation. They’ll add in parts that don’t fit or flow with the surrounding code. This degrades readability, but it also clouds the overall understanding.
When a programmer is rushed or under tremendous stress, their thought process is impaired. They don’t have time to think, they just need to act. They skip over the details and relationships, just banging out the most obvious localized manipulations possible. It is as if someone was just adding random tidbits to an existing novel that barely relate to the original story.
Programmers need to get into the zone (http://randsinrepose.com/archives/a-nerd-in-a-cave/). They need this so that they can visualize the largest portions of the code possible; so that their changes fit into the overall context. Big programs are never one or two person shows, they are too large, they need a team to get built. And they need a team to keep them from rusting.
In the zone, programmers can hyperfocus on visualizing how the data and code relate, which will allow them to organize it in their heads first before committing to making changes. They need to have the time to edit and re-edit as necessary until they have added as much readability back in the code as possible. They need to remember and cross-check a huge amount of moving parts, and to ponder the accumulating corner-cases.
If you want to study and learn a difficult subject, a library or quiet room is the best place. It minimizes the distractions. Even though most programming is routine, the collective weight of any large system makes fitting in new code a difficult subject. Disruptions lose the context; flipping back and forth between something else like Googling just slows down the work and likely causes the programmers to skip over important details.
Code needs time, patience and focus, that is the only way to enhance its quality. To ensure that it runs as expected. Bad quality doesn’t show up right away but gradually percolates until the code is unsustainable.
If a programmer is rushing through their work, they are doing this by deliberately ignoring a lot of necessary details. They can call a library to do something for them, but they may not understand where it is used correctly or what is happening underneath. They may be relying on really bad assumptions or fundamental misconceptions. Code that is based on that type of rapid construction is fundamentally weak, and even if it looks reasonable it will generally fail badly at some point. It can be pounded into functioning for sunny days, but it won’t survive any storms.
The programmers may also just skip the higher level organization hoping that it will magically sort itself out along the way. That is always a fatal tactic, in that problems only ever grow and eventually grow so large that they cannot be fixed in a reasonable time frame. Building a large system on top of a bad foundation is an easy way to fail.
The history of software development is all about having to write crazier and crazier code that just dances between these unnecessary artificial messes that we have allowed to build up through our bad practices. Most common programming problems are unnecessary and a direct byproduct of rushing through the work. This slows us down and increases our stress.
Stress eats up intellectual resources and it degrades the effort put into producing good code. If there is enough stress, the results are often code that is so hopelessly littered with interconnected bugs that no amount of reasonable effort will ever correct it. We live with a lot of awful code, we have just grown used to it.
The best code comes from studying a problem, doing some research and then visualizing the results into a clear articulation of the data and logic. It requires many passes of editing and an attention to detail where we dot the i’s and cross the t’s. If the time and patience is put into crafting this level of work, it will remain viable for a very long time. If not, it rusts quickly.
Good systems slowly build up large collections of reusable components that make the development process faster and smoother as time progresses. Bad systems build up artificial complexity that increasingly prohibit further effort as time goes on. They get worse as they get larger. As the problems grow out of control, so does the stress which feeds back into problems and thus many projects fall into this vicious downward spiral until they finally implode.
There is always some code that is throw-away. We might just need something to fill in, for now, it can be quick and dirty. But most code ends up filling in the problem and gets built upon, layer after layer. Even if it started as throwaway code, it never gets tossed.
If it is really foundational code, it makes no sense to just whack out crap in a high-stress environment. That is counter-productive since everything built on top needs to be arbitrarily more complex than necessary.
Even if the upper layers do correctly cover all of the artificial corner-cases, they do so at a disadvantage and replication of the mess they were intended to cover. That often just delays the inevitable.
To get stress-free programming, coders need a quiet environment. They need it to be neat and organized and they need any and all distractions removed. They can’t have loud music or texts popping up on their screens. They need to remain in the zone for as long as possible and they need a place where they can easily get there.
They also need to partition out the analysis, design and coding work from each other. Intermixing them is inefficient and disruptive. If you have to stop coding to search for missing data, or to investigate the data model, or to make architectural decisions, those interrupts become reflected in the results. If the workflow is messy, the code is too.
Like any good craftsmen, the tools and supplies should be assembled before the coding work begins, so that the flow is as continuous as possible. It will hold together far better in the first draft if it is a single connected effort.
But like writing, there are also many editing passes that are necessary before the rough work becomes smooth and pleasant. That is a slow process of going over and over again to refactor the code at parts that are awkward to read. It is a different skill than the initial programming and takes a huge amount of time to master. It is, however, the very essence of quality. Few humans can write out a novel in one pass, the same is true of code. Mostly we try for one pass and then ignore the ugliness of the work.
Time is the one declining resource that programmers need the most. We lived in a rushed society and we run around like chickens with our heads cut off because we are constantly told this is the path to success. It isn’t. It’s the path to fruitless mediocrity and somehow this 21st-century madness has embedded itself into everything including software development. People routinely want a year's worth of work done in a few weeks, so it is no wonder that the results are so craptastic.
Programmers quite obviously need more time and they need a reasonable environment where the expectations are back under control. By now we should be analyzing the various causes of stress in software development and finding ways to ensure that this doesn’t degrade the quality of the effort. However, we went off for at least a decade in the completely opposite direction and proceeded to inject far more stress into the workflow through a misguided attempt at gamification. Slowly the reality of those bad choices have made their way back into the mainstream, we are hopefully on some saner path of development these days. Programming will never really be stress-free, there are always too many unknowns since the full amount of required knowledge is vast, but if we must rely more and more on code then it should be code that we have at least tried to make correct. To increase our abilities to do that, we need to think more, and to do that we need less stress in our environments. It sounds great to just hack at some code with reckless abandon, but would you ever really trust that code with the important aspects of your life? “It kinda works” is a very low bar, and often far more destructive than useful.