The idea that you can go faster by sacrificing quality, or improve quality by moving more slowly, is a false dichotomy.
The reality is that speed and quality are mutually reinforcing. The ability to make changes quickly is essential to creating and maintaining a high level of quality. And a high level of quality is the only way to sustain the ability to make changes quickly.
Rather than a two-dimensional line, the best way to show the relationship between quality and speed in a system is with a matrix of quadrants.
The upper-left quadrant is where teams try to prioritize quality by sacrificing speed. They use heavyweight change management processes, believing that involving more people in making a change, with more rigorous activities to inspect, justify, and sign off on each change, will “raise the bar”. What happens in practice is that having so much friction for making a change discourages people from making smaller fixes and improvements. The list of “known issues” grows, technical debt builds up, and people become accustomed to the system’s bugginess and awkward usability.
So sacrificing speed to achieve quality achieves neither.
In the lower-right corner, teams try to “move fast” (and maybe “break things”). The most important thing is getting features into users’ hands, testing is seen as a luxury. Perfection is the enemy of building a business before the money runs out. The problem with this approach is that shoddy code is hard to change. The team reaches a point where it’s hard to make a simple change because the codebase is a tangled mess far more quickly than they had assumed.
So sacrificing quality to achieve speed achieves neither. This conclusion is backed by research (see Accelerate by Dr. Forsgren et al, plus multiple DORA reports).
In practice, sacrificing either quality or speed leads to a fragile, messy codebase that is difficult to change, which is the lower-left quadrant. Nobody aims for the lower-left quadrant, but the vast majority of teams end up there.
The upper-right quadrant is where teams prioritize both speed and quality. This was the idea behind agile software development, at least before agile became gentrified by those who believe in process over people.
The upper-right quadrant is not about finding a balance between speed and quality. It’s about using speed to achieve quality, and quality to achieve speed.
It’s about “Zero Defects” [Kent Beck] (which is not about never having any bugs, but making sure you fix them immediately when you find them). It’s about building the Best Simple System For Now [Daniel Terhorst-North].
A key to breaking the “tradeoff” mindset is in how you define quality. Quality is not features. It’s not extensibility. Quality is doing what needs to be done now, and doing it correctly. Quality code is easy to change. A good process drives quality by minimizing the friction of making a change safely.
Simple design and simple implementation make quality easy, because it means the code is easy to understand, change, test, and fix. Making small, frequent, incremental changes in a continuous flow reduces the friction that comes with heavier process (branching and merging). Pairing keeps people focused on clean, simple, and correct implementation. Really, we could do worse than to refresh ourselves on old school Extreme Programming. Daniel Terhorst-North’s CUPID approach for “joyful coding” is all about making sure your code is easy to work with.
Yeah, this is a site about Infrastructure as Code. But as with so much, the tenets of good software apply across the full system stack.