Practice 8. Design for ReuseThe topic of reusable software has somehow become the antithesis of agility, especially among many advocates of emergent design. And yet, the best way to enhance responsiveness to new opportunities is to have something to start from. If you have to start from scratch or are continually reinventing key algorithms, you are wasting effort, effort that should be spent concentrating on the new aspects of your project that will help you differentiate from what has already been done elsewhere. Reusable software has fewer defects and cleaner interfaces than non-reusable software. Once a piece of software is used but not duplicated in more than one place, it is going to be tested twice, and likely in different ways. This makes the software more robust. When coupled with automated tests of the interfaces for each use, the resulting software has a much greater chance of being extremely low in defects than if it were used only once.
Reusable software doesn't emerge. Although reuse can be arrived at through refactoring, there are often some key architectural decisions that need to be made as early as possible and carried through the project to make subsequent work much easier and less prone to needing to be redone. For example, when extensibility is important, it's wise to design the plug-in architecture early and then use it heavily, ideally so that all new features are developed as plug-ins. Without this up-front design and architecture work, the risk is that the system might be extensible, but not in a sustainable way. Reuse is vital to sustainability because it minimizes wasted effort and allows new initiatives to be launched quickly. Unfortunately, it is only enabled by sound design and coding practices because you need to understand how to balance reuse against wasted effort. I suspect the reaction to reuse stems from projects where software is overdesigned to make it reusable (which conflicts with simple design), resulting in a complex, defect-laden mess. This is where design intelligence comes in:
One of the largest problems and most important reasons to have reusable software is to eliminate duplicated code. It's tempting to just copy and paste a section of code, and although there may be a savings in effort in the short term, over the long term there will be a large amount of wasted effort. Duplicated code not only makes the size of the program larger, it also adds to complexity and is a common source of error, where a problem is fixed in one copy of the code but not another. Reusable software also eases replaceability.If some portion of the architecture needs to be replaced, it is always easier to take out one section and change its interfaces as required than it is to try and replace the entire system. If there are no interface changes required, even better, because then at least you can reuse the automated tests on the interface to ensure your new implementation has the same behavior. The notion of completely componentized software has been around since the introduction of Object-Oriented Programming. The notion of software ICs (i.e., software chips that can be wired together, much like chips on a printed circuit board) [Cox 1986] comes from the success of product line manufacturing. The automotive industry, for example, has reduced costs and defects by using as many common components (body panels, windshield wipers, motors, seats, instruments, etc.) as possible within a line of related vehicles. Unfortunately, the ideal of fully componentized reuse as in manufacturing still largely eludes the software industry. I think this is because of the constant change in the software ecosystem and the level of overall complexity. However, despite the complexity, it is still possible to attain a high degree of reuse, and this aids sustainability by allowing teams to be more responsive to opportunities and to avoid duplicating effort. One of my hopes for open source software is that over time we can dramatically cut down on duplicated effort within the industry and allow a greater amount of common infrastructure to be developed and enhanced over time. |