Reuse is software development’s unattainable panacea. The ability to compose systems from reusable elements has long been our achille’s heel. We want reuse so badly, yet our failures are spectacular. Almost all major technology trends of the past 20 years touts reuse as the saving grace. Vendors have sold billions of dollars in software through the broken promise of increased reusability.
What happened? Reuse was supposed to save software development. In the early 90’s, object-orientation promised to save us. It didn’t, so we moved on. In the late 90’s, component-based development promised to save us. It didn’t, and we moved on. Shortly after the turn of the millenium, SOA promised to save us. It didn’t, and we’re moving on. Why is reuse so damn hard?
The problem stems from the following rather simple statement, which is depicted in the diagram (click it to view in full size):
Maximizing reuse complicates use. (1)
In general, the more reusable we choose to make a software component, the more difficult that same software component is to use. In the extreme, an infinitely reusable component is infinitely difficult to use. Dealing with the tension between reuse and use is a complex issue, and often, we fail. Largely, the problem has to do with dependencies.
NOTE: I use the term component pretty loosely here. In general, the software development community has done a poor job defining the term “component”. Let’s just assume that when I say “component”, I’m talking about a chunk of software. No more, no less.
I recognize that we’ve done a fair job in achieving reuse at certain levels, and we’re much farther along the reuse curve than we were 20 years ago. Today, we have a plethora of frameworks to choose from that aid development. Web frameworks, ORM frameworks, and security frameworks to name just a few. But most of these frameworks are horizontal, not vertical. They address problems related to infrastructure and plumbing code, not business problems. And I want to focus explicitly on vertical reuse, because that’s the unattainable panacea we’ve been struggling with for so long. That’s the broken promise. Why have we struggled to create reusable business components?
Granularity is the extent to which a system is broken down into parts. Coarse-grained components tend to be richer in behavior than fine-grained components. Because coarse-grained components do more, they tend to be bigger than fine-grained components. To maximize reuse, we try composing coarse-grained components from fine-grained components. Of course, this results in a lot of dependencies between components, making them more difficult to use. In general, we can say the following:
Coarse-grained components are easier to use, but fine-grained components are more reusable.
Time for an example. Let’s say we’re creating a component that processes health insurance claims. Let’s keep the business process relatively simple here to maintain our sanity. There are four steps in the process. First, the system is fed the claim information. Second, the system checks to make sure it’s not a duplicate submission. Third, the system reprices the claim based on HMO and PPO agreements. Fourth, the system remits payment. A coarse-grained component would perform all four of these steps.
In doing this, we’ve made it easy to use since we only need to invoke one operation to complete the whole process. But it’s also more difficult to reuse only a portion of this process, such as the remit payment code. The logical solution is to create four fine-grained components (one for each step in the process) and one coarse-grained component composed of the four others that pulls everything together. The fine-grained components make things more reusable, but are also more difficult to use since we have to do more to pull them all together to perform a unit of work.
Weight is the extent to which a component depends on it’s environment. A heavyweight component depends on it’s operating environment, while a lightweight component avoids these dependencies. When creating a component that runs in multiple environments, we’re forced to move the environment specific dependencies (ie. context dependencies) from code to configuration. This makes the component more reusable, but it’s also a bit more difficult to use since the component must be configured for each environment.
Designing and configuring a lightweight component is more difficult than simply dropping in a component programmed to operate in that environment. In general, we can say the following:
Lightweight components are more reusable, but heavyweight components are easier to use.
Let’s elaborate using the example above, where the solution was to create one coarse-grained component composed of four fine-grained components. If each of these components only needs to run within a single application in a single operating environment, we can encapsulate all of this environmental code into each component, making each heavyweight. But if we want to reuse these components across applications and operating environments, then we have to move this code outside of the component and ensure it can be configured for each environment in which we want it to operate.
The challenge we run into when attempting to create a highly reusable component is to manage the tension between reusability and useability. In our example above, breaking out the coarse-grained component into fine-grained components makes it more difficult to use each of the resulting fine-grained components. Likewise, creating a lightweight components makes using the component more difficult since the component must be configured each time the component is used.
Fine-grained components have more component dependencies and lightweight components have more context dependencies. Each makes a component more reusable, but also more difficult to use. The key is to strike a balance, and that is a topic for another day not too far away.
(1) This statement is a derivation of Clemens Szyperski’s statement in Component Software: Beyond Object-Oriented Programming - “Maximize reuse minimizes use.”
17 Responses to “Reuse: Is the Dream Dead?”
Leave a Reply
[...] Reuse: Is the Dream Dead? (Kirk Knoernschild) [...]
[...] Reuse: Is the Dream Dead? - Kirk Knoernschild looks at the reasons why we arn’t getting huge re-use out of our code despite that being one of the guiding principles in development for a considerable time [...]
It’s hard because of this persisting myth that computer programs are a sequence of instructions written in not-so-clever languages.
We have known this for decades. While we continue to entertain the idea that programming is for dummies, then reuse will forever be hard.
[...] Reuse: Is the Dream Dead, I talked about the failed promise of reuse. In stating that maximizing reuse minimizes use, I [...]
I think the Re-use / Ease of use graph does not need to look like that. I find that during re-use the component/object needs to be configured before it can be used. If in the process of re-use ‘useful’ default configuration was provided then it would be easy to initially use the component/object and then the user could gradually learn to use the rest of the features or config options.
[...] Reuse: Is the Dream Dead - Discusses the tension between reuse and use. [...]
It’s true. Reuse comes with a price. This price is the one we have to know before invest effort on making a component more reusable, or before start using it. As an example, if using a component in a particular app costs more than creating a customized one (including configuration, deployment, maintenance, etc.) then re-using it is not the best choice.
Another problem of Reuse is a modular reusable component can be clearly identified only after you have design/developed and used it and there is a use case which is similar to the functionality of the component.
May be a Assembly oriented methodology may increase reusability as the dependency between components is assembled instead of coded as currently.
[...] Reuse: Is the Dream Dead - Discusses the tension between reuse and use. [...]
[...] to use (flexibility and complexity are another paradox?). I explore these ideas further in Reuse: Is the Dream Dead, and draw the conclusion that Maximizing reuse complicates [...]
[...] modules become more complex and difficult to use, leading us to the corollary we presented in Reuse: Is the Dream Dead:” The issue of module dependency management is well understood. Development tooling initiatives [...]
[...] his recent article “Reuse: Is the Dream Dead?“, Kirk Knoernschild continues his efforts to educate the industry on the tensions between code [...]
[...] modular software. Among other things, designing modular software requires that we understand the weight and granularity of individual modules, and use the right techniques to manage the coupling between modules. In [...]
[...] Reuse: Is the Dream Dead, I spoke of the tension between reuse and use. That tension is evidently at play here. Earlier [...]
[...] But if minimal dependencies were the only traits of great design, developers would lean towards creating very heavy, self-contained software entities with a rich API. While these entities might have minimal dependencies, extreme attempts to minimize dependencies results in excessive redundancy across entities with each providing its own built-in implementation of common behavior. Ironically, avoiding redundant implementations, thereby maximizing reuse, requires that we delegate to external entities, increasing dependencies. Attempts to maximize reuse results in excessive dependencies and attempts to minimize dependencies results in excessive redundancy. Neither is ideal, and a gentle balance must be sought when defining the behavior, or granularity, of all software entities - classes, packages, and modules. For more on the use/reuse paradox, see Reuse: Is the Dream Dead? [...]
[...] modular software. Among other things, designing modular software requires that we understand the weight and granularity of individual modules, and use the right techniques to manage the coupling between modules. In [...]
[...] modules become more complex and difficult to use, leading us to the corollary we presented in Reuse: Is the Dream Dead: Maximizing reuse complicates [...]