Most people agree that quality is desirable. It leads to the kind of experiences that we want in the world. Those that bring joy and reduce people’s struggle. It’s what makes work meaningful.
But, we can always always improve things. So, we have to decide where to stop. We have to make trade-offs. And it’s in these discussions that the lines get blurry.
In software, quality can mean many things. It can describe the visual design and the user experience. It can describe how performant things feel. It can also describe how the code is structured, the boundaries and interfaces. How things are named. How well we can verify functionality.
To understand what the trade-offs are, we need to figure out what ‘quality’ is. Being specific helps avoid conflating different attributes.
Users can see and appreciate the visual design and how well the software meets the needs of the user. Let’s call these the functional qualities. Then there’s the non-functional qualities: performance and security. And finally, there’s the quality that a users cannot see: the technical quality.
When we think to improve quality. We find it easy to justify spending time improving the UI, or making things faster. These are things that are visible to users.
It is hard for users to tell how well put-together your software is under the hood. So our thinking leads to why we should improve internal quality.
But this thinking is backwards.
Software is not like building in the physical world—despite being a well-used analogy. Software is always changing. Requirements even change whilst building. When engineers add features, they need to build on top of existing features. This requires understanding the existing code. Understanding what needs changing and then being able to make changes confidently. How easy the existing code is to understand affects how quickly features are built.
This is why the technical quality is so important. Because technical quality makes a system easy to maintain, and change.
well-thought out interfaces can allow you to remove or replace whole components without following tendrils into all corners of the codebase; good test coverage can make you more confident when making changes, can reduce the number of bugs, and helps to minimize time in QA”
— Dan Pupuis
Spending time on the architecture, defining the boundaries between components is not a cost but something that makes future changes easier. Which speeds us up over time.
And users do see this: they get more features over time. They get better reliability.
Next time you enter a discussion on speed vs quality consider what the true trade-off is. Understand what aspects of quality you may not need yet. Don’t compromise on the technical quality and maintain your speed well into the future.