One of the popular metaphors for software development that annoys me to no end is the notion of a software factory. Even if the underlying concept is concerned with well-defined processes and structured ways of working, the image it draws up in my mind is that of a production line. And it pictures software engineers as mindless factory workers that repeat the same task over and over again.
Interestingly, mechanical design and electronics design are never described as a factory. Everybody understands that a mechanical or electronics engineer is designing a solution and verifying all its necessary properties. Once the design is finalized, we can start manufacturing. And everyone understands that these engineers need to evaluate alternatives, create prototypes, test these prototypes and then arrive at the preferred solution after having explored the design space.
For some reason, when it comes to software, especially for folks outside of the discipline, software development is equated to the manufacturing process, rather than the design process. The implicit assumption seems to be that a requirement that needs to be realized in software doesn’t require a design but is nothing more than an algorithmic translation from human text into code. I can for the life of me not understand why reasonably smart people fall into this fallacy. The only reason I can come up with is that because software doesn’t have associated manufacturing, some may think that software development is manufacturing.
There are at least three concerns with treating software development as a factory. First, it fails to recognize the creative nature of software development. It really is a creative activity where the team as well as individual engineers explore a design space, based on their best understanding of the requirement, the customers and the context in which the functionality will be used. It typically requires exploring alternatives, testing things with customers and using empathy with the user to come to a realization that best serves the intended purpose.
Second, it tends to ignore the larger scope in which a feature or requirement needs to operate. The notion of feature interaction is well established in the software engineering literature and basically refers to the fact that features aren’t simply lego bricks that can be put together; they almost always interact with already existing functionality. The integration of a new feature into the existing code can be quite challenging and requires careful exploration and design. The whole purpose of software architecture is to minimize feature interaction and, consequently, future maintenance and extension costs, but every architectural decomposition will have some types of functionality that can be easily added and other types that will require changes in many places in the code.
Third, it assumes that all features are worth building and that the specification is the ground truth when it comes to what adds value to customers. With digitalization creating more and more opportunities for DevOps and frequent feedback from the field, the whole notion of building a large set of complete features without frequent, intermediate testing that they actually add value is simply outdated. As we discussed in an earlier post in this series, we need to treat requirements and feature requests as hypotheses that need to be validated. And it’s the job of R&D to do the validation.
One way to think about this is to distinguish between efficiency and effectiveness. Efficiency is the notion of doing work at the lowest cost in terms of resources, defects and time. Effectiveness is concerned with creating maximum output against each unit of input. Optimizing the R&D organization for cranking out as many features per time unit as possible assumes that each of these features is actually used and appreciated by customers. Research shows that this is a completely wrong assumption. In fact, less than half of the features in a system are used sufficiently frequently to justify the R&D investment.
We need to shift the focus of R&D from efficiency to effectiveness. This requires us to build a slice of a new feature, get it out there and in the hands of customers, measure its impact and decide on the right course of action after reviewing the data. And this may mean canceling a feature and removing the initial code for it from the system as it doesn’t deliver the expected value.
Second, rather than focusing on building new features, we should spend more time on revising and experimenting with features that are used frequently. In many cases, we can achieve a significantly higher return on investment by optimizing existing features than by adding new features that aren’t used. For most people with the software factory mindset, that’s a complete blindspot.
One of the ways I gauge the understanding of digitalization in companies I work with is how they talk about software development. Those that use the “software factory” metaphor have real misconceptions about the role of software development and the creative design activity that it really is. Instead, focus on fast feedback loops with systems in the field, iteratively build new features to measure their impact and spend much more time optimizing existing features that are heavily used, rather than adding more and more features. It’s impossible to not end this post with the famous quote from Peter Drucker: efficiency is doing things right; effectiveness is doing the right things. Let’s focus on effectiveness first!