Just Good Factoring

See BridgePatternIsJustGoodFactoring, ContainerManagedPersistence.

A number of patterns recommend centralizing this or that functionality, responding to various specific forces. I am coming to suspect that OnceAndOnlyOnce is a very basic pattern, a "generating" pattern, that directs the emergence of the specific pattern.

In ContainerManagedPersistence, for example, the developers of the app that uses serialization for persistence are dismayed when they have to make mass changes all over to remove serialization and replace it with something else. (Relatedly, a project I know of at a US auto company has code "all over" putting objects into an RDB.)

The "real" bug is that the code to do one thing is "all over". The commonality almost certainly exists - it just wasn't observed, extracted, abstracted, and implemented as an object. --RonJeffries


What I'm getting at here is that the "good factoring" patterns, whatever they are, seem to generate more specific patterns. I suspect one could generate Composite by refactoring a container and some specific objects, for example. Would a pattern that generates patterns be meta? --RonJeffries


JustGoodFactoring, like ShieldPattern, is too basic and simple to be useful - we have to know enough to know how to apply really complicated boundary conditions to derive the right answer. Both are missing metrics that give indications of whether we are moving in a useful direction or not. OnceAndOnlyOnce contains such a metric, and as such is far more useful.

So yes, once you know the answer and the boundary conditions, any design can be demonstrated to be JustGoodFactoring - but without them, you can't argue. OnceAndOnlyOnce is a hypothesis, from my standpoint, because it is a really strong statement, and I think not suitable under all circumstances (there are boundary conditions of applicability, having to do with the size, cost and time schedule of the development).

I personally like finding the really basic patterns, along with their boundary conditions, because then we can roll out lots of other patterns and understand the line of reasoning that got us there.

Centralizing this or that functionality is great - once you have identified the functionality to centralize. Identification is the nebulous part, centralizing is the "easy", "standard OO design" part. So saying, "centralize things" is also not useful, in my book. It begs and directly asks the question, "How do I decide what things to centralize and what not?" --AlistairCockburn


Yes, Alistair, this is wise. Very well-expressed and thank you. It's not just doing OnceAndOnlyOnce, it's knowing which ones to focus on.

Often I don't know why I want to move the code from over here to over there. Sometimes there are patterns that say where to go: Aha, let's do Flyweight. This points us back to the discussion on forces in XP patterns. Almost certainly I'm unconsciously balancing forces when I push the design this way or that.

And yet, I suspect that there's more to OnceAndOnlyOnce than meets the eye. Very often when something in C3 isn't well-factored, there is obvious duplication in the code. Obvious enough that something like RefactoringBrowser could find it with long enough search times.

In all the refactorings we have done on C3, we have never once, to my recollection, wanted instance-specific behavior or multiple inheritance. We haven't felt that we were centralizing this at the expense of decentralizing that. This makes me think that most often, there is a global OnceAndOnlyOnce that makes the whole system properly factored. Maybe I'm dreaming. --RonJeffries


Relatedly, I wonder whether there is something about C++ and Java that cause it to be harder to observe the commonality or to make the extraction. Smalltalk is of course quite reflective, so that it is easy to ask an object questions about what it contains. But one still needs to know the types of the instance variables and so on, so it certainly isn't trivial. --RonJeffries


I think manifest types are directly opposed to OnceAndOnlyOnce. In Java I come across repetition that is hard to factor out because so much of it is due to the verbosity of the language. The refactored form wouldn't be any smaller.

Here's a bad example (bad because there are things that can be done):

Enumeration links = note.getLinks();
while (links.hasMoreElements()) {
Link link = (Link) links.nextElement();
// Use link.
}
These 4 lines of code are repeated many times in my current project. It is a standard Java enumeration idiom. The ways I've thought of to refactor it barely seem worth abandoning the "least surprise" benefit of the standard way. -- DaveHarris


Yes ... the language limits what we can effectively refactor. Smalltalk's blocks, collection methods, and symbols really do make a difference. If I hadn't already programmed in everything from APL on, I think I'd become a Smalltalk bigot. --RonJeffries


EditText of this page (last edited February 19, 2004) or FindPage with title or text search