Software development as a humanity
One of the principles I find most important in developing software is the idea of reducing cognitive drag. Cognitive drag is the mental work that obstructs you from getting what you’re looking for. Say you’re interested in having dinner at a restaurant tonight. A source of cognitive drag might be finding out which restaurants are even open, then selecting one based on its merits, before being able to enjoy the experience of the restaurant itself. In software development, cognitive drag often comes up in fixing bugs. Let’s say my email app crashes each time I click the button for drafting a new email. My main task is to fix the cause of the crash, which necessitates pinpointing that cause. Identifying the cause in turn requires examining the series of events leading up to the crash. If it’s difficult to find the code dictating those events in the source files across the code base — if for instance, the files are poorly named or hard to search across — that’s a good example of cognitive drag.
I first encountered the concept of cognitive drag in a book on designing user interfaces: Steve Krug’s Don’t Make Me Think. That book focused more on designing web and app interfaces and the associated workflows for end users (“user experience”), rather than on coding techniques or code organization. The main idea is that as a user I want as little as possible to get in the way of me and my end goal. Interfaces and behavior should be intuitive, self-explanatory, convenient, etc. The concept extends to the actual code though, where text, files, and editors constitute their own interfaces and workflows with their own end users: software developers. The idea that fellow developers should be able to easily understand and navigate a collection of code is not new. Any primer on software construction will recommend being thoughtful about how you name functions, that their constituent code is not too long to wrap one’s head around, etc. In my case though, I became acquainted with that idea from the perspective of user experience design.
For me the code base is an artifact that gets consumed and interpreted in the same way as a novel or a historical document. A work of science fiction establishes the mechanics of its own universe, defining behaviors for androids, faster-than-light travel, biotech or something else. Fictitious as this world might be, if it’s constructed well it will be clear to readers what constitutes a violation of those mechanics: how that universe should work and how someone can interact with it to achieve some end. This idea extends even more strongly to game play like that in Dungeons & Dragons. Taking it to the digital realm of online games brings us back to software and user experience. The code base is a microcosm, with constraints on possible scenarios and chains of cause-and-effect leading to them. If these rules are inconsistent or unclear to users, that creates not just cognitive drag but also a sort of existential chaos rendering goal-seeking behavior untenable. If the physics are arbitrary, if the game doesn’t make sense, if the code is convoluted and nondeterministic, people won’t be able to realize anything with it.
Similarly, people have relied on the historical record to inform our understanding of how the world works and how to effect certain results within it. Why did the Maya or the Soviet Union collapse? How can we prevent the worst effects of societal destabilization? That’s just one of the bigger questions history can address, but smaller ones abound. History encompasses relatively recent phenomena such that technical documentation and case studies fall under its purview. Think of the records of Three Mile Island and Chernobyl and how they factor into current approaches to preventing catastrophic failure at nuclear facilities. Like the anarchic universes mentioned above, when the record is unclear there’s a breakdown in our grasp of cause and effect. If we didn’t have exact details on the actions leading up to nuclear meltdown, we wouldn’t be as equipped to prevent similar situations in the future. If two writers conflict over basic historical facts, we’re left to guesswork which stymies our ability to reproduce or avoid certain situations. Like cognitive drag in a constructed world, cognitive drag stemming from poor documentation of our own hinders our ability to get us where we want to go.
There’s this preconception that if you’re a programmer — especially a backend programmer removed from working directly with end users— there’s little human-oriented element in your work. But that isn’t true. Optimizing an algorithm for performance and meeting the immediate requirements of an assignment are just as important as composing your code in way that will be workable in future cases, so the next person who comes along can potentially build upon it or fix a bug in it. For that, people need narrative in the form of clarity of cause and effect. The formal logic might technically be there, but how much can I expect from someone else’s background in comprehending it? How much time will they have to answer, “How does this work? How can I interact with it?” We should make it easy to answer those questions.
This gets into the emotional experience of working with code. For all the culture of intellect in the field of software development, there’s a big emotional component. We pursue the application of intellect because we derive satisfaction from it, getting that dopamine hit once we see our mental efforts come to fruition. If it’s particularly frustrating to understand or work with a collection of code, people get discouraged and the project suffers. What developer hasn’t been deflated by the prospect of working with a piece of legacy code again, a piece that’s poorly organized and hard to work? Because people want agency and to feel good about accomplishing something, if the game is too challenging they won’t advance in it. The emotional experience of working with code determines whether people enjoy their jobs and whether they’ll stick around or pursue something more emotionally and intellectually satisfying.
So as I write code and organize it into higher-level entities, I think of it as fashioning a literary world, a historical record, a clear story of its mechanics. I think about whether my professional descendants — or even my future self — will appreciate my artifact or be frustrated by it. Software developers are creating systems that are lasting decades and may even last centuries, in the same way Roman aqueducts have. But those foundations needed extension and reworking at times to fill the role they play today. How do we construct software so that people will be able to understand and repurpose it as circumstances evolve? Treating software development more like a humanity will help us achieve that.