I ask because earlier this week I saw the following tweets:
@zspencer It appears that @jimweirich is recommending reordering the 4
rules of simple design. Is intent revelation more important than dry?
#scna
@jimweirich @zspencer I've seen both orderings. See
http://c2.com/cgi/wiki?XpSimplicityRules and the original vs the
@ronjeffries version.
@RonJeffries @jimweirich @zspencer in the original white book, i
believe it appears twice with 2 and 3 in each order. i prefer DRY
first. makes u think
@jbrains @RonJeffries @jimweirich @zspencer I remove dup'n to uncover
good structure, then improve names to distribute responsibilities
better.
I think I also saw a tweet saying that talks were not recorded.
If you were at the talk: what was Weirich's message?
The talk was a live performance of (a portion) of the Roman Numeral Converter kata, followed by an analysis of the decisions made during the kata. The code portion of the kata is more or less reproduced in a static form here: https://gist.github.com/1095310
I made the following points during the talk:
* Know where to start (put some thought into picking your first test)
* Know where to continue (the right sequence of tests can make finding the solution easier)
* Allow the solution to drive the tests (counterpoint to letting the tests drive the code)
* Know what to skip (sometimes delaying some tests until later is helpful)
* Recognize duplication (even when it doesn't look like duplication)
* Know when to not remove duplication (when it impacts readability)
* Know the edge cases of your problem space
I think the second to the last point is what caused the twitter stream. At some point in the kata, we reached a data structure that looked like this:
ROMAN_REDUCTIONS = [
[1000, "M"],
[900, "CM"],
[500, "D"],
[400, "CD"],
[100, "C"],
[90, "XC"],
[50, "L"],
[40, "XL"],
[10, "X"],
[9, "IX"],
[5, "V"],
[4, "IV"],
[1, "I"],
]
There is some obvious duplication in the 1,4,5,9 pattern that repeats for each power of ten. I suggested you *could* remove that duplication with something like this:
def self.power_of_ten(power, ones_glyph, fives_glyph, tens_glyph)
[
["#{ones_glyph}#{tens_glyph}", 9*power],
[fives_glyph, 5*power],
["#{ones_glyph}#{fives_glyph}", 4*power],
[ones_glyph, 1*power],
]
end
CONVERSION_TABLE = [ ["M", 1000] ] +
power_of_ten(100, 'C', 'D', 'M') +
power_of_ten( 10, 'X', 'L', 'C') +
power_of_ten( 1, 'I', 'V', 'X')
In the talk, I suggested that the change was not an improvement. The complexity introduced by the power_of_ten method overshadowed the rather minor duplication in the data table. Since the duplication was (1) minor, (2) well communicated by the existing table, and (3) unlikely to be subject to change, I felt the explicit data table was preferable. The audience seemed to agree with the assessment.
I also said that when balancing removing duplication VS adding complexity, I tend to weigh readability and understandability heavier in tests than I do in regular code.
That's the meat of the talk and what generated the twitter conversation. I wasn't advocating reordering the 4 rules for simple design (although there seems to be some confusion on the exact ordering anyways). I was merely suggesting that sometimes (not always) removing duplication adds complexity and that in some cases the benefit of removing duplication is outweighed by the added complexity. You need to be aware of the trade-off and make well informed decisions.
I hope this helps.
--
-- Jim Weirich
-- jim.w...@gmail.com
There is some obvious duplication in the 1,4,5,9 pattern that repeats for each power of ten. I suggested you *could* remove that duplication with something like this:
def self.power_of_ten(power, ones_glyph, fives_glyph, tens_glyph)
[
["#{ones_glyph}#{tens_glyph}", 9*power],
[fives_glyph, 5*power],
["#{ones_glyph}#{fives_glyph}", 4*power],
[ones_glyph, 1*power],
]
end
CONVERSION_TABLE = [ ["M", 1000] ] +
power_of_ten(100, 'C', 'D', 'M') +
power_of_ten( 10, 'X', 'L', 'C') +
power_of_ten( 1, 'I', 'V', 'X')
In the talk, I suggested that the change was not an improvement. The complexity introduced by the power_of_ten method overshadowed the rather minor duplication in the data table. Since the duplication was (1) minor, (2) well communicated by the existing table, and (3) unlikely to be subject to change, I felt the explicit data table was preferable. The audience seemed to agree with the assessment.
The talk was a live performance of (a portion) of the Roman Numeral Converter kata, followed by an analysis of the decisions made during the kata. The code portion of the kata is more or less reproduced in a static form here: https://gist.github.com/1095310
On Nov 26, 2011, at 2:59 AM, Jim Weirich wrote:CONVERSION_TABLE = [ ["M", 1000] ] +
power_of_ten(100, 'C', 'D', 'M') +
power_of_ten( 10, 'X', 'L', 'C') +
power_of_ten( 1, 'I', 'V', 'X')
In the talk, I suggested that the change was not an improvement. The complexity introduced by the power_of_ten method overshadowed the rather minor duplication in the data table. Since the duplication was (1) minor, (2) well communicated by the existing table, and (3) unlikely to be subject to change, I felt the explicit data table was preferable. The audience seemed to agree with the assessment.I would certainly agree with the assessment that the particular method chosen to remove that duplication was not an improvement at first glance, and maybe not at all. However, that doesn't tell us that no better way exists.
> Delightful, by the way, even in written form. I like how you bring out the discoveries. The "IF is a WHILE" one is delicious!
Delicious is a good word to describe that.
> I wonder about a recursive approach. Would it eliminate the whiles and turn them all back into IF? Would a big outer loop WHILE n > 0 remove the IFs?
There is an alternate solution where we turn the WHILEs into IFs by calculating the number of glyphs needed using a bit of modulo math. Then we don't need the inner whiles at all and they can become IFs. (Hmm, as I write this, it occurs to me that the IFs might not be needed either. I might explore that the next time I do the kata.)
> The "duplication" in the table remains interesting, but in the grand scheme, not VERY interesting :)
Agreed.
--
-- Jim Weirich
> What if we would take removing the duplication further? For example in the above code X, C and M are each repeated twice. Maybe we would end up with code like this:
>
> ROMAN_REDUCTIONS = [
> [1000, "M"],
> [500, "D"],
> [100, "C"],
> [50, "L"],
> [10, "X"],
> [5, "V"],
> [1, "I"],
> ]
It would be interesting to see how that choice effects the code.
--
-- Jim Weirich
> For me, I leave duplication above expression because duplication is easy to spot and it needs to be heeded so often that it deserves high priority. In addition, many programmers, though of course none of us here, think that their code is perfectly expressive as it stands. I fear that if we rank expression over duplication, the normal tendency to think our code is great will cause us to miss opportunities to improve.
>
> It's a very interesting list. In some ways, the most interesting thing Kent ever did. For sure, 2 and 3 are close together in priority. In theory, I think expression trumps duplication removal. In practice, I think that happens very very rarely, if ever.
Thanks for the insight on the tension between expression vs duplication. I like this explanation.
--
-- Jim Weirich
>I hope this helps.
That was very helpful and much appreciated: thank you.
Philip
On Nov 26, 7:59 am, Jim Weirich <jim.weir...@gmail.com> wrote:
> On Nov 26, 2011, at 12:29 AM, Philip Schwarz wrote:
>
>
>
>
>
>
>
>
>
> > Were you at Software Craftmanship North Americahttp://scna.softwarecraftsmanship.org/
> > ? Were you at Jim Weirich's "Code Kata and Analysis"?
>
> > I ask because earlier this week I saw the following tweets:
>
> > @zspencer It appears that @jimweirich is recommending reordering the 4
> > rules of simple design. Is intent revelation more important than dry?
> > #scna
> > @jimweirich @zspencer I've seen both orderings. See
> >http://c2.com/cgi/wiki?XpSimplicityRulesand the original vs the
Philip
That's all very reasonable. I have no problem with that, though I would
probably explain this particular situation differently.
I noted today that Kent's list in XPE1 (p. 57) says "Has no duplicated
logic." I would say that the 1,4,5,9 pattern is not duplicated logic,
but just a pattern found in Roman Numerals. Minimizing the space of
this table requires some more complicated logic.
I call this "incidental duplication" and think it's not worthy of
removal. It's not that the V, L, and D share something special. They
just happen to appear similar after being converted to base 10.
I liken the impetus to remove them to, in C, declaring "#define ONE 1"
and using "ONE" everywhere a 1 might appear. If the 1s are unrelated,
this is not duplication and the substitution adds an unnecessary coupling.
Like Ron, I've never found steps 2 & 3 to be in conflict. Considering
apparent conflicts such as this one helped me to see duplication as more
than similar numbers or words.
- George
--
----------------------------------------------------------------------
* George Dinwiddie * http://blog.gdinwiddie.com
Software Development http://www.idiacomputing.com
Consultant and Coach http://www.agilemaryland.org
----------------------------------------------------------------------
An easy move is to compute the complete reductions set from the DRY one.
For example:
Hi Olivier,
On Nov 27, 2011, at 9:49 PM, Olivier Azeau wrote:
An easy move is to compute the complete reductions set from the DRY one.
For example:This must be some new kind of easy that I wasn't previously familiar with. I found the resulting code to be quite opaque. But it could be me, my IQ is only 160-something and I've only been programming for a half-century.
But seriously ... I would not say that transformation was an improvement. :)
ROMAN_REDUCTIONS = [ [1000, "M"], [900, "CM"], [500, "D"], [400, "CD"], [100, "C"], [90, "XC"], [50, "L"], [40, "XL"], [10, "X"], [9, "IX"], [5, "V"], [4, "IV"], [1, "I"], ]
ROMAN_SINGLE_CHAR_REDUCTIONS = [ [1000, "M"], [500, "D"], [100, "C"], [50, "L"], [10, "X"], [5, "V"], [1, "I"], ]
ROMAN_REDUCTIONS = add_double_char_reductions_to(ROMAN_SINGLE_CHAR_REDUCTIONS)
> I noted today that Kent's list in XPE1 (p. 57) says "Has no duplicated
> logic." I would say that the 1,4,5,9 pattern is not duplicated logic, but
> just a pattern found in Roman Numerals. Minimizing the space of this table
> requires some more complicated logic.
>
> I call this "incidental duplication" and think it's not worthy of removal.
> It's not that the V, L, and D share something special. They just happen to
> appear similar after being converted to base 10.
Agreed. This reminds me of the circumference/area problem with Circle:
we don't extract pi*r to its own function, because we wouldn't know
what to name it. I don't know many examples like this, and I consider
them somewhat pathological.
--
J. B. (Joe) Rainsberger :: http://www.jbrains.ca ::
http://blog.thecodewhisperer.com
Author, JUnit Recipes
Free Your Mind to Do Great Work :: http://www.freeyourmind-dogreatwork.com
Find out what others have to say about me at http://nta.gs/jbrains
Agreed. This reminds me of the circumference/area problem with Circle:
we don't extract pi*r to its own function, because we wouldn't know
what to name it. I don't know many examples like this, and I consider
them somewhat pathological.
units = [ "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" ]
tens = [ "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" ]
hundreds = [ ... ]
return hundreds[arabic / 100] + tens[arabic / 10 % 10] + units[arabic % 10]
Is it now "too much duplication" ?
Is it worth it to avoid the lopping?
When is duplication duplication that counts?
Cheers
Jon
> --
> You received this message because you are subscribed to the Google Groups
> "software_craftsmanship" group.
> To post to this group, send email to
> software_cr...@googlegroups.com.
> To unsubscribe from this group, send email to
> software_craftsma...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/software_craftsmanship?hl=en.
--
CyberDojo - a game-server for practising the collaborative game called
software development.
Explained at http://jonjagger.blogspot.com/p/cyberdojo.html
Open-sourced at http://github.com/JonJagger/cyberdojo
Server probably at http://www.cyber-dojo.com
Video of Roman Numerals kata in Ruby at http://vimeo.com/15104374
> What about if the arabic to roman numeral solution does this...
>
> units = [ "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" ]
> tens = [ "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" ]
> hundreds = [ ... ]
>
> return hundreds[arabic / 100] + tens[arabic / 10 % 10] + units[arabic % 10]
>
> Is it now "too much duplication" ?
> Is it worth it to avoid the lopping?
> When is duplication duplication that counts?
These are all good questions. In this particular case, my judgement is that
(a) The duplication is small ... only three repetitions.
(b) The probability of a change is small, I don't think Roman numerals have changed much in, oh, say 2000 years.
If either of (a) or (b) were not the case, I would be much more inclined to do something about the "just barely duplicated" duplication.
As an aside, it is interesting to note that the tens pattern given above is incorrect, in that it omitted the initial "". Also when I transcribed your code (to run it locally to verify it gave good numbers), I had a typo in the hundreds array (typed "DC" instead "CD"). So in the end between you and me, we got two errors in duplicating the units array.
Another aside, removing duplication is (IMHO) easier in your formulation than my original. It could be written like this:
units = [ "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" ]
tens = units.map { |glyph| glyph.tr("IVX", "XLC") }
hundreds = units.map { |glyph| glyph.tr("IVX", "CDM") }
Simple enough to do rather than explicit arrays? Maybe.
Another aside, removing duplication is (IMHO) easier in your formulation than my original. It could be written like this:
units = [ "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" ]
tens = units.map { |glyph| glyph.tr("IVX", "XLC") }
hundreds = units.map { |glyph| glyph.tr("IVX", "CDM") }
Simple enough to do rather than explicit arrays? Maybe.
Probably not.
> Is it worth it to avoid the lopping?
I like the other looping opportunity this opens up:
arabic = 901
n = arabic # Need a better name
parts = [units, tens, hundreds, ...].map { |each| each[n % 10]; n /= 10 }
parts.should == ["I", "", "CM"]
roman = parts.reverse.join("")
roman.should == "CMI"
Now you can extend it for thousands, myriads, … as long as you have
the glyphs you want.
> When is duplication duplication that counts?
If I don't just see it, then I follow this rule of thumb: if either
there's 3 copies, or I can name it, then I extract it.
These are all good questions. In this particular case, my judgement is that
On Dec 15, 2011, at 1:42 AM, Jon Jagger wrote:
> What about if the arabic to roman numeral solution does this...
>
> units = [ "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" ]
> tens = [ "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" ]
> hundreds = [ ... ]
>
> return hundreds[arabic / 100] + tens[arabic / 10 % 10] + units[arabic % 10]
>
> Is it now "too much duplication" ?
> Is it worth it to avoid the lopping?
> When is duplication duplication that counts?
(a) The duplication is small ... only three repetitions.
(b) The probability of a change is small, I don't think Roman numerals have changed much in, oh, say 2000 years.
ROMAN_SYMBOLS = [ [1000, "M"], [500, "D"], [100, "C"], [50, "L"], [10, "X"], [5, "V"], [1, "I"], ]
just reading this reply of yours again, 2 years after you wrote it, because last week, in "Putting an Age Old Battle to Rest" [1], J.B.Rainsberger blogged on "the controversy" of the relative ordering of simple design rules 2 and 3, and these great thoughts of yours on the ordering of the rules are very interesting and so I left a comment pointing out how you teach the Simple Design order.
My approach to communicating complex ideas at the time was toformulate a simple set of rules, the emergent property of whichwas the complex outcome I was aiming at (cf patterns). (I havesince become disenchanted with this strategy.) I thought about howI recognized simplicity, turned those criteria into actions, sortedthem by priority (it’s no coincidence that human communicationis number two)...