Compare OnceAndOnlyOnce. You implement a concrete class pragmatically. You implement another ditto. You notice that the classes have a lot in common. You refactor to make one a subclass of another. You notice that the top one has just a few methods overridden in the bottom. You decide the system would look better if there were a class at the top with no concrete implementation of those methods, and two parallel subclasses with those methods. You do it.
The result is that you have an abstract class with two concrete subclasses. You have done it with no goal in mind other than to reduce redundancy in a particular way.
I've done this exercise and wound up with a very nice implementation of the classes in question and never had a goal in mind of the kind of abstraction I was doing. It's almost mechanical. Very interesting.
And each step of the way you had a working implementation with no stubs yet to be implemented, no worry about whether you were going to be able to implement (and like) a pre-conceived design. By building the classes one step at a time, you arrived at a better end-point than you could have pre-conceived. But it did take the willingness to incrementally modify existing design and implementation. Which is in accord with the philosophy of ChristopherAlexander. --ScottJohnston
I am currently teaching programmers that there are only two criteria a program must meet to be a well-built program:
"No goal in mind other than to reduce redundancy"
This isn't a surprising result. By the time you have the two classes, you already have your relevancy criteria; they are implicit in the class interfaces.
Abstraction is tied to polymorphism, which is about treating objects which are different at one level of abstraction as if they were the same at another level of abstraction. When you notice the classes "have a lot in common", you're identifying a level of abstraction at which they can be treated the same.
I don't see any conflict between the two approaches. Reducing redundancy is a suitable goal for abstraction. -- DaveHarris
(Some discussion originally on OnceAndOnlyOnce:)
Although OnceAndOnlyOnce is a good maxim, it doesn't address the situation where two notationally similar texts are actually at different levels of abstraction. Maybe this should be identified as a "force" driving the texts apart. -- DaveHarris
This depends on the support from the language! With adequate support, you must be able to specialize in a separate scope, thus not dealing with different levels of abstractions in the same place.
What OnceAndOnlyOnce requires in addition is version control support: the locality is defined at the level of the element, not at that of any version.
OnceAndOnlyOnce is a maxim or principle written in the form of a pattern. As such it is subject to much opinion and disagreement. There are, however, a number of patterns that embody the principle ...
This page mirrored in WikiPagesAboutRefactoring as of April 29, 2006