Posted On: 2022-06-13
In software development, there's a perpetual conflict between two implicit goals of the field: writing efficient code and writing maintainable code. Both are essential skills, but often their application is mutually exclusive. Finding the right balance can be difficult, and there may be disagreements (even within teams*) about which sacrifices should be made. Importantly, what is the "right" or "best" approach will vary by team or project, so there won't ever be one authoritative solution.
Software efficiency comes in many forms: how quickly the code runs, how little memory it uses, etc. The efficiency demands for a project will vary based on the technical hardware running it (ie. a phone versus a server farm) and the kind of software (ie. an interactive application versus a headless process updating billions of records). When software efficiency suffers, end users are directly impacted (ie. applications freezing or running out of space for the software) - and that impact is often disproportionate for users on lower end systems or systems being used for multiple tasks. As systems are increasingly designed to always be running/available (ie. how often do you leave your web browser open when doing other things?), software efficiency becomes increasingly important - even as improvements to hardware make it seem like it should be decreasing (ie. compare the price/specs of the average computer now versus a decade ago*.)
Efficiency has the (sometimes frustrating) quirk of being relative to the context it is in. A system's overall efficiency is not merely the sum of the efficiency of its parts - the system could just as easily become bogged down by one big inefficiency as by millions of tiny ones. To address this, developers typically profile the system, gathering essential data about how the system behaves while in use. Many profiling tools support finding the "hot" part of the code (where the bulk of the time is spent), or how and where memory is allocated, and this data is a key part of discussions around improving efficiency.
I've described maintainability in a previous post, but as a quick summary: modern software is constantly changing, and maintainability is key to meeting that challenge. Frequent updates, changing business demands, and the inevitable obsolecence of old technology are everyday realities for many software teams. Through writing clear, consistent, and self-documenting code, a developer makes their software more maintainable - and therefore easier to change.
Maintainability does have the interesting quirk of being fairly subjective. Different groups will be familiar with different patterns and challenges - meaning that what's intuitive and self-documenting for one developer may demand a hefty amount of background reading/explanation from another. While this is most pronounced when comparing different domains (ie. what's familiar to a web developer is alien to a driver developer - and vice-versa), looking closely even at two different teams in the same organization, one may very well see differences in style, pattern, and assumptions.
Efficiency and maintainability come into conflict whenever unintuitive changes improve code efficiency. Sometimes this can be as simple as requiring an in-code comment to explain the change*, but there are plenty of more extreme situations - such as adjusting code to improve its data locality. Navigating those conflicts can be quite tricky: on top of maintainability's normal subjectivity, efficiency-focused code often requires deep familiarity with a system's technical details - which may reduce the number of developers who can understand it, even when adequately documented.
Team and project dynamics can have a large impact on finding the right balance. Teams with a higher tolerance for inefficiency may only sacrifice maintainability when a measurable efficiency difference is considered important enough to do so. Conversely, teams that routinely work on performance-critical code may have maintainability guidelines that are designed with efficiency in mind, for example, by explicitly permitting differences in style when those differences impact performance.
As you can see, efficiency and maintainability are both important, and their (many) conflicts lead to needing to find a team/project-specific balance. This awareness is important, as one may find that changing teams or moving to new projects may force one to unlearn what had previously been the "right" balance. For myself, transitioning from internal tool development to game development has changed not only how I view my own work, but also the patterns and approaches that are considered maintainable by those who share their knowledge in the field. I hope you've enjoyed this post, and if you work in/adjacent to the field of software development, I encourage you to analyze how your group finds their own balance - and what factors may be unconsciously contributing to those choices.