When I start working on a new feature for my software, I have to figure out how it will fit in with the rest of the application.
If the application is at all mature and well-designed, there will be well-established patterns and conventions in place and many features will just fit right in.
But what about the truly new features — the ones that don’t quite fit in the existing boxes?
Schedule pressure and the desire to deliver more value sooner cause me to want to try to reuse what I have and force the new feature to fit into the existing architecture.
Reuse certain helps keep the system consistent both internally and externally. This is a good thing. If every part of the system works differently, it becomes much less usable. The whole point of merciless refactoring is that the resulting clean design is able to easily accept new features in this way.
There have been times in my career where this approach has worked really well. My colleagues and I were able to deliver something to the market quickly by casting the problem in a light that fit well with the existing architecture. I can’t talk about details, but in one particular case, force-fitting the new feature into the existing architecture and infrastructure saved many months of development time and resulted in a genuine innovation in our market.
However, sometimes force-fitting a new feature into the existing patterns is a cop-out.
Thinking about new problems in terms of an existing system limits the solutions I come up with. When I don’t give myself free rein on the design space, my creativity is limited and I miss insights that might result in a big win.
Spending extra time on a feature in order to introduce new design ideas, architecture, or infrastructure can often pay off in a big way. Suddenly, entire new worlds are open to the software; existing concepts start to find a better home; features start crystallizing into new, more effective structures.
I see this even on a small scale. I identify a tiny concept that occurs a few times in my code and turn it into a class. Once that class exists and has a name, it starts attracting methods and behavior from other parts of the system. Making the new concept concrete has a major positive influence on the rest of the system.
The next time you have a problem to solve or a feature to implement, take time to think about whether reusing what you have is a cop-out. Maybe this feature needs a new approach. It might not, but it’s always worth thinking about and making a conscious choice to either reuse or innovate.