In the fairly famous "Defense Science Board Task Force on Military Software" released in the late 1980s, recommedation 29 was to "...develop economic incentives...to allow contractors to profit from offering modules for reuse..."
(I found this in Software Conflict 2.0 by Robert L. Glass, d.* books, 2006)
Years ago I was called in to consult on a project that had gone bad. The customer had engaged a contractor to develop the software, which was supposed to take a year and was at the time I was called in, a year late.
The main design and technical problem (ignoring for the moment Weinberg's maxim that "No matter what they tell you, it's always a people problem") was that the contractor had decided that this was an opportunity to develop a reusable software system, and that they could develop this system on the customer's dime.
This resulted in classic framework-itis. The contractor was no longer just trying to solve the customer's problem, they were trying to solve all problems that looked like it. So for that reason alone the project would have required 10x the original time and money.
And of course we are unable to avoid the people problem for very long: The architecture had many fundamental flaws, and one very big one resulting from a misunderstanding and assumed overlap between OO objects and Windows messages. This happened because there was one technical lead who was the architect, and who ruled with an iron fist and fired anyone who disagreed with him (and so everyone left was willing to agree with him). And he didn't understand as much as he thought he did.
Framework-itis in general is one way, and probably the most highly-criticized way, that attempts to reuse code go bad.
I postulate that most of the corruption in code resue comes when someone decides ahead of time that we should reuse code. That is, when it is driven by perception rather than need. I have personally found reusable code at the point when I need it a second time, as a process of discovery. And usually it's something I can't anticipate, or at least don't anticipate it in exactly the way that I need it.
Another well-known, and incredibly expensive for the industry as a whole, example of bad code reuse and framework-itis gone awry is EJB1/2 (EJB3 appears to be a completely different beast, riding on the questionable preexisting marketing of EJB). This was designed for an imaginary development process that had never happened before and apparently never happened during the life of EJB1/2, so developers ended up fighting against the framework rather than being aided by it. And I've heard numerous stories of companies having to rip EJB out of their system. Talk about expensive.
I think libraries can also fall prey to bad reuse scenarios. Again, setting out to create reusable code seems to be the culprit, along with imagining how a library will be reused rather than discovering how a library is reused. The great majority of the Python library, in my opinion, has been included after components have been used successfully in practice, and have evolved into a stable state. One notable exception, as I understand it, is the xmllib which was discovered to be un-Pythonic and messy/noisy to use, and the much cleaner elementree is being substituted in Python 2.5.
What experiences have you had when attempts at reuse have gone bad? Do you agree with me that those experiences came primarily from driving the "reuse cart" before the "use horse?"
The "three examples" pattern, in particular, should be recognized by the industry as a core practice. Fortunately, I'm running into more people who've seen that paper these days. I think that the recent emphasis on evolutionary design in agile methodologies has helped to start to bring it to the forefront again.
I think it all comes down to this: Software has to be used before it can be reused.
I agree that frameworks should be developed only if there is a need, which can provide the requirements. However, it cannot be completely reactive, there should be a proactive element to it. Most of the times I have seen following cases which have resulted in bad reuse:
- A framework is designed with incomplete requirements which results in bad design. It should also consider requirements in the near future if possible. - A framework is created when certain code is required more than once. The result is a refactored code, rather than redesigned code. - A framework designed without supporting the basics, like OO design principles, which leads to ineffective interfaces. Even if a violation is unavoidable, it has to be done consciously and sincerely documented and accounted for in future changes. - A framework is not designed at all and the notorious copy-paste employed everywhere.
I think realisation for a framework should be part of the design. If it is postponed, then a redesign at later stages is too expensive, and refactoring is not always enough.
Of course, it's the "Crystal-ball" like development that is going on here, trying to anticipate how someone will use your component in future. I assume Superman or Dr Who is probably better as reusable software development than us mere mortals ;)
Another danger word that often creeps in here is "generic". When someone says to me, "Hey, I'm developing this cool generic service". Nine times out of ten, it is harder to "configure" these reusable blobs than to write something specific in the first place.
> Another way to approach the problem is to write small > frameworks that are highly decoupled.
The danger here is in overly decoupling the design. When do you know you have "decoupled" enough? It's easy to create a totally decoupled framework that is hard to use in context. This is why I think frameworks realistically fall out of existing code rather than created afresh.
> I think this is exactly what is the advantage of Domain > Specific languages. > > Frameworks try to gather the whole range of possible uses, > whereas good DSL design focuses on a specific uses/tasks > and a defined range of parameters. > > I would rather have reuse by my customers(typically domain > experts) than developers in later projects.
That's a very good intervention. I would put it just slightly different.
A framework is an "application with holes". You can drill small and large holes and also many small holes where stuff has to be filled in a highly coupled manner to make everything work. The prototype of any framework is a language together with an interpreter. The language describes the interface between the interpreter and the application code. A small framework with few small holes will unlikely be identified as a language but a large one with many small holes is just a kind of domain specific language. If you are aware of this you can turn the viewpoint and think about designing a nice DSL in the first place. What was mentioned to be a framework becomes an interpreter. I would like to read more about the following refactoring move: "Replace framework by DSL" in future.
Hm..this is a nice example but it seams to be a bit misinterpreted, ihmo. The story doesn't tell whether it would have been a good decision for the contractor to create a framework to save money (because they often do very similar jobs and don't want to reinvent the wheel every time or so). The contractor obviously abused the contract to produce something they (might) need but was not requested originally. If they had developed a decent framework in parallel (while producing the requested (specialized) application for the customer as agreed) there would be nothing wrong. The rest is more of a design problem. Optimally you want your framework to cover all cases that fit the "design frame" but not more. As noted frameworks often mutate into the most generic service ever. On the other hand the framework will quickly become unusable if it is designed to narrow..as you never know what kind of new requirements pop up during devlopment. The whole idea of the famework obviously is to impose restrictions on the user to simplify certain tasks. These restrictions cannot fit all problems (otherwise they wouldn't be restrictions). So if you decouple the framework's services as much as possible everyone can use the bits and pieces he likes and discard those that don't fit the problem. A simple pyramidal hierachy (with the most abstract components on top) where the user can choose the level he want's to operate in should suffice often. Many frameworks appear to enforce a use all or nothing strategy..so they are forced to be super generic to fit many obscure problems. I say: Let the (framework's) user choose..he's not as stupid as you might think :)