Once And Only Once

One of the main goals (if not the main goal) when Re Factoring code. Each and every declaration of behavior should appear Once And Only Once. Conceptually analogous to normalization in the Relational Model. See also Dont Repeat Yourself.


Code wants to be simple. If you are aware of Code Smells, and duplicate code is one of the strongest, and you react accordingly, your systems will get simpler. When I began working in this style, I had to give up the idea that I had the perfect vision of the system to which the system had to conform. Instead, I had to accept that I was only the vehicle for the system expressing its own desire for simplicity. My vision could shape initial direction, and my attention to the desires of the code could affect how quickly and how well the system found its desired shape, but the system is riding me much more than I am riding the system. -- Kent Beck, feeling mystical, see Mystical Programming


Beware of introducing unnecessary coupling (Coupling And Cohesion) when refactoring for Once And Only Once.


Refactoring is the moving of units of functionality from one place to another in your program. Refactoring has as a primary objective getting each piece of functionality to exist in exactly one place in the software. -- Ron Jeffries

It's not OAOO, and this comment probably ought to be somewhere else, but doesn't refactoring also cover replacing one piece of code with another, simpler piece of code that has the same external "appearance" and function?

Yes - good point. Note Ron's subtle use of "a primary objective" instead of "the primary objective". I personally use two "first tier" refactoring rules - Once And Only Once and Separate The What From The How (my name - the common name is Composed Method)


Once And Only Once is a profound concept, but difficult to apply. I've spent my entire professional life (25 years) learning how to apply it to programs. This page [many versions ago] ... was rewritten to make Once And Only Once seem like a simple rule to apply, instead of a prime principle. Once And Only Once is NOT easy! And it was wrong to refactor this page so that all hints of tension and disagreement are removed from it.

Once And Only Once is not a pattern. A pattern is something you can teach someone to do in a fairly short amount of time. A day, usually. Perhaps a few weeks. But learning how to refactor classes to form a Template Method does not help you see how to use XML to represent your user interfaces (a recent Once And Only Once technique applied to Squeak), or how to make a good virtual machine. These are patterns; Once And Only Once is not a pattern. Once And Only Once is a principle. -- Ralph Johnson


Well said. Once And Only Once is not just a simple rule, but one of the core goals of all software design. It's why functions were invented. Remember that your program could have been written as a single long function using only ifs, whiles, and try/catch blocks for flow control, and primitives for all the data. Consider what that would look like. For "hello world", it's the default.


I once saw Beck declare two patches of almost completely different code to be "duplication", change them so that they WERE duplication, and then remove the newly inserted duplication to come up with something obviously better. -- Ron Jeffries, from the Xp Mailing List

or, the long version...

I recall once seeing Beck look at two loops that were quite dissimilar: they had different for structures, and different contents, which is pretty much nothing duplicated except the word "for", and the fact that they were looping - differently - over the same collection.

He changed the second loop to loop the same way the first one did. This required changing the body of the loop to skip over the items toward the end of the collection, since the previous version only did the front of the collection.

Now the for statements were the same. "Well, gotta eliminate that duplication, he said, and moved the second body into the first loop and deleted the second loop entirely.

Now he had two kinds of similar processing going on in the one loop. He found some kind of duplication in there, extracted a method, did a couple of other things, and voila! the code was much better.

That first step - creating duplication - was startling. -- Ron Jeffries, from the Xp Mailing List

It isn't so startling. That technique is necessary for the more powerful space optimizations of program code: you reduce everything as much as possible, then you find two subgraphs that are similar, you add conditional nodes to them until they're identical (and inject the proper conditions), then you combine them. Repeat until the apparent gains aren't worth the resource cost to acquire them. Beck is just doing it by hand.

It is also frequently used to allow consistent idiomatic expressions to emerge. This allows bugs to be detected via inspection for all cases where the idiom was not followed properly. This is more than superficial coding standards. For example: a loop guard of < n or <=n will behave differently if n starts at 0 vs starting at 1. It is best to pick one idiom and stick with it. I suspect the duplication here was semantic in nature and culling it out allowed a reuse opportunity to emerge.


OAOO And Parallel Inheritance Hierarchies

In the slides for Xp Immersion, Robert Martin mentions parallel inheritance hierarchies as an example of Once And Only Once. I find it to be one of the hardest repetitions to refactor away, though. Does anyone have any hot tips?

There are two ways to go. To remove the parallel: refactor either or both hierarchies until their members are congruent, then collapse pairwise. To remove duplication between the parallels: define distinct responsibilities refined by each hierarchy and relocate methods as appropriate. -- Ward Cunningham

This all became a little abstract for me. What about an example? Say I have an accounting and logistics system. I have an abstract class Account and an abstract class Transaction. Each transaction transfers something from one account to another. Now, I have several types of accounts: SecuritiesAccount, BondsAccount, MoneyAccount, etc. For each type of account there is a transaction: SecuritiesTransaction, BondsTransaction, MoneyTransaction, etc. Now what? -- Johannes Brodwall

To solve your dilemma, try building the abstracts Transaction and Account. If you find something abstract enough to put there, you then might find something to reuse between different types of Accounts and Transactions. If not, it might be that those are just abstractions with no functional meaning for your context of usage. Another idea (some get it as an abuse, some as a smart oop move) is to move from hierarchy/inheritance design to aggregate/composition design, in your case, refactor to Transaction, Account and Transactionable (or Accountable) and descend from Transactionable to Money, Bond, etc. This way all your similarities (read code duplicates) should cut up to Transactionable, leaving Account and Transaction to deal only with the abstract behaviour/data that their names imply. The con is that you will have to invent notions to tie Transactionable to Account/Transaction together. Actually, that's the point where abstraction meets creation, but that's another story (see Abstraction Addiction, Too Much Abstraction, Parallel Inheritance Hierarchies). -- Cosmin Apreutesei

A good example indeed. My experience on Wy Cash was that the prevailing domain classification exerted way too much influence over our initial hierarchies as it may have yours too. We couldn't merge the two hierarchies because Transaction and Account instances have different lifetimes. Instead, as per the second choice above, we focused on redistribution of responsibilities which turned out as follows.

Transactions -- long lived private factual information

Accounts -- organizational structure related to reporting

Calculators -- industry accepted analytic components

Advancers -- mechanics of interpreting transactions

We were stunned at the discovery of advancers two years into maintenance. We never would have gotten this far without a long term commitment to aggressive refactoring. -- Ward Cunningham (See What Is An Advancer)


OAOO And Tests

Once And Only Once sounds like a nice principle but, when taken at face value, would lead to untested code. Even XP advocates stating each fact at least twice, preferably three times.

The three places where our fact is stated are:

what the customer wants (Functional Tests)

what the programmer wants (Unit Tests)

what the program does (the program itself)

This is a good point, Dave. I have another rule I use when information must be duplicated: When you must duplicate information make sure you will automatically detect if the duplicated information falls out of sync. Tests do this implicitly, and by definition. There are other common cases where the duplicated information is not self-testing, though. Assertions are a classic tool for handling this kind of problem. -- Curtis Bartley

This point is valid only if the code is perfect. Otherwise the two types of test add information to the overall system, and hence are not duplicating knowledge. Also, to be fair, what you're critiquing here is not really OAOO (which is about code refactoring), but Dont Repeat Yourself, which is wider ranging. -- David Thomas

The OAOO principle in XP refers specifically to the program. The program should express each idea once and only once - there should be no duplicate code.

Further, comparing the code:

square(NUMBER x) { return x*x; }

with the test:

assertEquals(4, square(2)); assertEquals(9, square(3)); assertEquals(4, square(-2)); assertEquals(9, square(-3));

we see no duplication of fact (though the test could be optimized OAOO-wise). As for duplication of tests of specific things, there's no inherent objection, except, of course, that you have to find and change all the places when a change is needed. -- Ron Jeffries


OAOO And SQL

I like the idea of OAOO. However, much of my work is RDBMS based (Oracle), meaning that I write a fair bit of SQL. Sometimes, the simplest way to get the data you need is to throw everything into one big (possibly ugly) SQL statement. The database optimizer then works out the best way to get what you need. If the data changes, it does it a different way. The problem is that if I want to encode something once and only once, that means I have to break up these large SQL statements and do things procedurally instead (PL/SQL). This means that the code looks good but runs like a dog and all that money spent on the database and its optimizer is as good as wasted. Thoughts anyone? -- Chris Rimmer

Anything stopping you from building up the massive SQL statement from the decomposed procedures, and running the optimizer on that?

Yes. I think you've misunderstood the problem. The point about SQL is that you tell it what you want, not how to do it. These procedures actually return data, not a fragment of SQL. So there's no way to combine them to produce some big SQL statement.

The answer is, I believe, to use database views to encapsulate multi-table relationships. I had already pretty come to this view (pardon the pun) when I read this article by Martin Fowler:

You won't get much direct benefit to performance by practicing OAOO. The benefit comes in reducing complexity and therefore increasing understanding/maintainability/extensibility. In the statement above, "one big (possibly ugly) SQL statement" can translate to one big complex, off-putting statement. It may run well, but the next guy that sees it, even if it is you one month from now, may find it sooo hard to understand that he shies away from it, or spends 5 times the effort in understanding and modifying it as would have been necessary for a few separate procedures. -- Jeff Santini

I have found that I usually get a big performance benefit from this practice; as the refactoring continues and code is isolated and shared, the processing pattern of higher level application layers becomes clearer, function pointers start coming into play (for those of us who did a lot of C and assembler) which makes these higher layers of code properly use polymorphic function/method definitions. Redundant decision making/branching is always reduced or eliminated by doing it. -- Grant Wesley Parks

I didn't expect to get a benefit to performance. I was looking for the kind of maintenance gains you talk about. However, what I don't want is a thousand-fold decrease in performance! This is quite possible in the situation I describe. See my comments above about the use of views. -- Chris Rimmer

I don't get it: you think views solve the problem of the execution plan or not? I think they do, with all the benefits of the OAOO. -- Cosmin Apreutesei.


OAOO and Code Generation

OAOO is once and only once of human input. If a copy can be regenerated without a human then it does not violate OAOO. Consequently Code Generation, for example, does not violate OAOO. Any automated duplication does not violate OAOO. For example, automatically generated program documentation does not violate OAOO even if it contains many duplicates of many pieces of code, as there are two different aspects - OAOO of human input (Primary Information) and OAOO of computer generated (Secondary Information). -- Aleksey Pavlichenko

OAOO of Primary Information doesn't care about space or runtime performance efficiency; OAOO of human input is what helps produce better code.

OAOO of Secondary Information affects runtime execution performance or space, but doesn't affect programmer performance. For example, use of C++ templates can easily result in duplicated code, which is not a violation of OAOO because it is code that would not, under normal circumstances, be seen by (or even accessible to) a human.


For applying this concept to a more general frame (than programming) please contribute to: www.communitywiki.org


Wouldn't it be that writing to same subject to that other page breaks once and only once? :)


I think that Once And Only Once is a great concept but cannot be taken perfectly literally.. as for example in the documentation, sometimes points need to be repeated in different ways on different pages to ensure the safety of the readers (repeating warnings and such things). Also in code sometimes we have no other choice but to repeat something to make code clearer.... consider:

print('more text\nmore text\n');

Versus

println('more text'); println('more text');

The second one may be arguably more repetitive and can be reduced to one print statement.. but not necessarily more clear. If this is not related to Once And Only Once then please feel free to move this discussion to Needless Repetition.

No modeling principle is absolute. There are almost always exceptions and counter-factors. Once And Only Once is probably one of the simplest and most-agreed-upon modeling principle there is (in a general sense), but there are also exceptions, gray areas, and philosophical dances surrounding it.

Chuck Moore has something to say on this, found in Thinking Forth, page 188. While pontificating on the frequency of the idiom OVER + SWAP in Forth software (e.g., OVER + SWAP DO I C@ . LOOP) and why it lacks its own word (e.g., RANGE), he writes,

That particular phrase, OVER + SWAP, is one that's right on the margin of being a useful word. Often, though, if you define something as a word, it turns out you use it only once. If you name such a phrase, you have trouble knowing exactly what RANGE does. You can't see the manipulation in your mind. OVER + SWAP has greater mnemonic value than RANGE.

Leo Brodie calls them "cliches," but "idioms" works as well. The point is, sometimes, over-factoring can produce a net loss of readability to the program. I do not believe that OAOO to be such a hard-and-fast rule that it takes precedence over readability, considering OAOO's sole purpose is the betterment of readability.

The println example isn't repetition. You're saying "Print some text". Then the next step is "Print a second lot of text". It's the output that's repeated, not the code.

Actually println is good OAOO. Enumerating print drivers and writing bitmaps/postscript/whatever for each of the 9 chars, then (deep breath) doing it all again would not!


The more one generalizes and abstracts, the more difficult it becomes to OAOO. The more you refactor and get it closer, the harder it becomes - kinda like folding paper. - Jonathan Crossland


Note: New discussion should use "Dont Repeat Yourself"; the DRY term is much more successful, for obvious reasons... C-:

Why not use Exactly Once instead? It's a much better and more concise term.

Because it's too strict. It implies we will use Big Design Up Front to achieve perfect unity. A little duplication is okay; DRY is a transitive verb.

Say, what?!? What in the phrase "exactly once" implies big design up front? It's simply a more concise, grammatically accurate rendering of the concept. And by the way, please don't Disagree By Deleting.



See original on c2.com