Is it possible that a program can reach a state where implementing X OnceAndOnlyOnce causes Y to be implemented in two places, and vice versa, so that OnceAndOnlyOnce would loop?
Put another way, can a program reach a state where making one of two aspects "well-factored" perforce causes another aspect not to be, and vice versa?
In principle, can it happen? In practice?
Simple proof: OnceAndOnlyOnce for X may be mutually exclusive with OnceAndOnlyOnce for Y, by DeMorgansLaws.
~[(X ^ Y) v (~X ^ ~Y)] = (~X v ~Y) ^ (X v Y)
~[(X v ~Y) ^ (~X v Y)] = (~X ^ Y) v (X ^ ~Y)
One can optimize or (v) or and (^), but not both. QED.
Yes, I think refactoring one aspect of a collection of software can change the other well-factored aspects of the same code. For example, what if you had two class libraries, one very well suited for task A, say financial applications, and another well suited for task B, say statistical tools for scientific experimentation. Each has their own inherent architecture, their own abstractions and frameworks for invoking computations, etc.. And each might have a random number generator built in. Following the rule of OnceAndOnlyOnce, they quickly decide to combine them.
Along the way they uncover sizeable differences between the two capabilities, because of the emphasis of one package toward market prediction, the other toward accurate fine-grain control of random number generation to facilitate statistical analysis. Should they hybridize these two similar overlapping capabilities, creating a dependency between these previously independent libraries? Or maybe they could go look at OnceAndOnlyOnce again, to see that it originated to describe a practice in external documentation, not necessarily programming practice, and decide it is ok to just let things be. --ScottJohnston
This seems like a setup to me, on two grounds.
Unless, of course, they re-read the whole page and the many other pages that make reference to it. It's correct that the page originated about documentation, but that's a little irrelevant. It's easy to spot the references made by contributors to OnceAndOnlyOnce in programming terms. Further, if one reads the XP-ish wiki pages, the concept is most generally used re: programming practice, not external documentation practice. -- MichaelHill
Yes, it was a setup, an example made up in attempt to illustrate a point. Where I've come across this in practice would take a lot longer to present clearly, but the jist would be the same. And I was thinking of redundant sets of functions for generating random numbers, probably without common architecture or symbols. Different ways of setting the random seed, different ways of generating vectors of random numbers, different ways of selecting and parameterizing random distributions.
Anyways, I think I'm talking about the same thing someone else has said around here, of listening to the code more than listening to a preconceived notion of how the code should be. Perhaps YouArentGonnaNeedIt can apply just as well to a refactoring activity as a code generation one. Don't get me wrong -- refactoring is a beautiful thing. But in my experience, when working with software foundations laid down by others, tolerance for yet-to-be-refactored code can be a boon to projects, by keeping the focus on customer requirements. As long as you're willing to go back in later, to carry on with incremental improvements and refactoring where it seems most appropriate, after the heat is off. --ScottJohnston
One of the main ways we listen to the code is to observe the same code in more than one place. We take this as a suggestion that the multiple occurrences of the same code should be consolidated into one. Under what circumstances would this be inadvisable?
Note, however, that the Extreme rules regarding refactoring are specifically stated to be part of generating our own code. To my recollection we have made no assertion that you should take other people's libraries and refactor them. --RonJeffries
Also please note that the original question isn't about one's opinion as to whether refactoring is a good idea. The question is whether there can exist a configuration of code such that application of the OnceAndOnlyOnce rule can loop.
People will usually stop refactoring before the code is perfect, in the real world. But can the rule, driven to the limit, fail ... or does it always stand as an ideal, more or less well attained? This is the wrong question, as it is a false dichotomy. The rule can indeed loop, because programming languages are not infinitely expressive. Therefore, in any real programming language, you'll encounter occasional situations where you'll need to allow duplication. But you still try to manage the duplication. You put the duplicated parts close together in the same module or make sure that the duplicated text will never need to be changed, and you provide ample documentation as to what's going on. And new language features can allow you to remove duplicated code, because they make the language more expressive. OnceAndOnlyOnce driven to the limit can loop; but it still stands as an ideal.
The rule cannot loop. You are always striving for 1) less duplication and 2) more communication. These are both monotonic functions. I do a refactoring. There is now either less duplication or more communication or both. When there is no more duplication and there is nothing more I want to communicate, I am done.
I guess my example didn't work as I hoped, perhaps because I used a somewhat personal interpretation of what "well-factored aspects" meant without fully disclosing it. In my view well-factored code is code where every generic capability gets used more than once, and any generic capability that gets used only once gets either merged with its peer mechanisms or used again by some other code. So instead of OnceAndOnlyOnce rule, I follow a UsedAtLeastTwice? rule.
Which is why they have ThreeStrikesAndYouRefactor.
This allows for separate implementations of almost the same thing to live side by side indefinitely, as long as they have been adequately leveraged by other more application specific code. And it gives more time for the programmer to experiment with alternates, to consider which of two or three different approaches proves easiest to use/understand/communicate in the long run. Once all the ramifications have been theoretically and empirically worked through, the programmer can undertake the sizeable refactoring with confidence. The RalphJohnson patterns on evolving frameworks goes over some of this. Now I know this discussion doesn't belong here, in fact the above paragraph seems to say no further discussion is required at all, but the way I read the original question was close enough to something I wanted to say, so I did. --ScottJohnston
When you see what the bottom part of this page should be called, make a page for it and leave a pointer.
I think what you are getting at is that you don't want indirection that doesn't pay for itself. Indirection can pay for itself by creating isolation for a piece of code (reducing the risk that a change there will have an effect here), it can enable sharing, and it can explain. It is this last use of indirection that doesn't meet your criteria. The method:
highlight: aRectangle self reverse: aRectangleis a good idea, even if it is only called in one place. --KentBeck
This problem is orthogonal to the "multi-team environment"/"refactoring other peoples' libraries" issue, which I feel is actually a more significant one for XP, so I'm planting a WikiFlag here: MultiTeamExtremeProgramming. -- TomRossen
Perhaps this relates to the "interweaving orthogonal factors" issue that I describe at:
http://www.geocities.com/tablizer/struc.htm#if
The problem is projecting a multi-dimensional "shape" into the one-dimensional world of ASCII code.
This page mirrored in WikiPagesAboutRefactoring as of April 29, 2006