Skip to search.

Breaking News Visit Yahoo! News for the latest.

×Close this window

extremeprogramming · Extreme Programming

The Yahoo! Groups Product Blog

Check it out!

Group Information

  • Members: 9644
  • Category: Object Oriented
  • Founded: Jan 1, 2000
  • Language: English
? Already a member? Sign in to Yahoo!

Yahoo! Groups Tips

Did you know...
Message search is now enhanced, find messages faster. Take it for a spin.

Messages

Advanced
Messages Help
Messages 107756 - 107785 of 158671   Oldest  |  < Older  |  Newer >  |  Newest
Messages: Show Message Summaries Sort by Date ^  
#107756 From: Tony Byrne <yahoogroups@...>
Date: Tue May 31, 2005 11:45 am
Subject: Re[2]: [XP] Zen Refactoring
tony_j_byrne
Send Email Send Email
 
Hello Ron,

RJ> I once saw Kent Beck do that in a most amazing way, but I haven't
RJ> learned the trick of making code look similar prior to removing
RJ> duplication;

I find I can do this easily with relatively simple code, but there are
other times when it feels it should be easy but isn't and I'm left
scratching my head. In that respect it reminds me of algebra.

RJ> would love to see an example.

As a TDD kata, I recently implemented a small program to convert
integers to a string representation in words. (e.g. 1 --> one, 55 -->
fifty-five). For me, this problem contains one example of duplication
which was easy to make disappear once the duplicated code was made
similar, and one where no matter how I look at it, I can't make the code
similar enough to make the duplication disappear.

I don't have source code for the intermediate stages, so I'll work
from memory. As I TDD'd, I evolved code that handled the suffix for
each of the orders of magnitude (hundred, thousand, million, billion)
with what was effectively a switch. As I refactored the code, I
replaced the switch with code that uses a hashmap to lookup the proper
suffix (hundred, thousand, etc.) for each order of magnitude. The
original switch also handled the decision for determining the
concatenator to use for joining up the sub-strings of the answer i.e.
', ' and ' and '. I was able to re-arrange the cases of the switch so
that they handled the appending of the concatenator in the same way. I
then factored out that concatenator code to a method.  This made the
cases similar enough that I could move to replace the switch with a
lookup and a tiny fragment of code.  So far, so good.

The more 'troublesome' duplication case is the obvious similarities
between the code that handles the sub one-hundred integers and the
more general code that handles all other orders of magnitude. Both
have code that splits the bit to be converted into two parts using
modular arithmetic, but they deviate sufficiently in how they process
the parts that the duplication remains.

I can post real code if required, but be warned it's Perl. I'm not
actually looking for an answer, but maybe the example is worth
pursuing in the "Look! real code!" sense.

Regards,

Tony.

--
Tony Byrne

#107757 From: Luiz Esmiralha <esmiralha@...>
Date: Tue May 31, 2005 11:59 am
Subject: Re: [XP] Zen Refactoring
lesmiralha
Send Email Send Email
 
In my oppinion, ProgrammingByIntention is the father of
TestFirstProgramming. And it feels so natural that I wonder if I ever
did program any other way.

Thanks for your example, Ron.

On 5/31/05, Ron Jeffries <ronjeffries@...> wrote:
> On Monday, May 30, 2005, at 10:11:41 PM, hammett wrote:
>
> > Sometimes I create methods with hundreds of lines - aware that it must be
> > refactored.
>
> > After testing and debugging the flow I extract the body into smaller
> > methods. I'm not proud of it, but it's seems/feels faster than refactoring
> > during code. Sometimes the code is not simple, so I use my energy to stay
> > focused on the problem I'm trying to solve. After that I use my energy on
> > the refactoring.
>
> I do that sometimes, but far less often than I did. For me, it is
> definitely not faster, beyond maybe ten or twenty lines, if then.
>
> When I'm working in that linear way, I'm always thinking, something
> like:
>
>   OK, first I'll open the file ...
>     bang out a few lines;
>
>   Now I'll loop reading it ...
>     a few more, with a {}, position cursor inside;
>
>   Each line I'll check for "foo" ...
>     an if statement;
>
>   And if I get it, parse the line ...
>     a bunch of regexp;
>
>   And toss it in the output ...
>     a couple of lines;
>
> I find that what works better for me is a technique that I learned
> from Kent Beck, which I call "Programming by Intention" (because I
> believe that's what he called it). It goes like this for the same
> problem:
>
>     file := OpenFile("something");
>     ProcessFile(file);
>     close(file); /* did you notice I forgot? Neither did I! */
>
>   procedure ProcessFile(aFile)
>     while (! aFile.EOF ) {
>       ProcessLine(aFile.readLine)
>     }
>
>   procedure ReadLine(aLine)
>     if (aLine.contains("foo")) {
>       resultLine = ParseLine(aLine);
>       SaveLine(resultLine);
>
>
>   function ParseLine(aLine)
>     return regexp stuff;
>
>   procedure (SaveLine)
>     output += SaveLine;
>
> When I work this way, my first draft of the program might not be
> quite this highly factored, but often it is. When it's not, it might
> look like this:
>
>   procedure ProcessFile(aFile)
>     while (! aFile.EOF ) {
>       line = aFile.ReadLine;
>       if (line.contains("foo") {
>         resultLine = ParseLine(line);
>         output += resultLine;
>     }
>
> Generally speaking, the sooner I express /what/ I'm doing, rather
> than /how/ I'm doing it; the longer I leave off expressing /how/ I'm
> doing it ... the better it works for me.
>
> Next time you feel one of those hundred-line blocks coming on, you
> might want to try programming it "by intention". Please let us know
> what happens, if you do.
>
> Regards,
>
> Ron Jeffries
> www.XProgramming.com
> I could be wrong, but I'm not.  --Eagles, Victim of Love
>
>
>
> To Post a message, send it to:   extremeprogramming@eGroups.com
>
> To Unsubscribe, send a blank message to:
extremeprogramming-unsubscribe@eGroups.com
>
> ad-free courtesy of objectmentor.com
> Yahoo! Groups Links
>
>
>
>
>
>
>
>

#107758 From: "PierG" <piergiorgio_grossi@...>
Date: Tue May 31, 2005 12:39 pm
Subject: Remote teams
piergiorgio_...
Send Email Send Email
 
Ciao,
I know there are experiences around about working with XP teams
geographically splitted into 2 or more sub-groups.

Could you share with us: the worst problem you faced and the thing
that helped you more in this challenge?

Thanks,
PierG

#107759 From: Chris Dollin <kers@...>
Date: Tue May 31, 2005 12:40 pm
Subject: Re: [XP] Zen Refactoring
eccentric_he...
Send Email Send Email
 
On Tuesday 31 May 2005 12:59, Luiz Esmiralha wrote:
> In my oppinion, ProgrammingByIntention is the father of
> TestFirstProgramming. And it feels so natural that I wonder if I ever
> did program any other way.

In the Old Days, my wife would look over my shoulder when I was
writing code for our Beeb.

     10PROCbegin
     20REPEAT
     30PROCplay
     40UNTIL FNnoMore()
     50END

     100DEF PROCbegin
     110ENDPROC

     200DEF FNnoMore()
     210=TRUE

     300DEF PROCplay
     310ENDPROC

Now expand PROCplay, adding to PROCbegin as needed. Expand FNnoMore()
when we want to play two games. Etc.

Her comment was, "all you ever do is define another procedure for
anything you're not sure about yet ... but it works!".

--
Chris "electric hedgehog" Dollin
"The compiler is free to insert padding because it makes the struct
look bigger and scares away predators." [Keith Thompson, comp.lang.c]

#107760 From: Paul Friedman <samandtwitch@...>
Date: Tue May 31, 2005 1:26 pm
Subject: Re: [XP] Remote teams
paulsanfordf...
Send Email Send Email
 
Pier,

There was a pretty decent discussion on this list in December that is
summarized here:

http://c2.com/cgi/wiki?VirtualPairProgramming

Look toward the bottom of the page.

The message thread is entitled 'Remote Pair Programming' and starts w/
msg 100535 on December 9, 2004.

pax et bonum. p.


PierG wrote:

>Ciao,
>I know there are experiences around about working with XP teams
>geographically splitted into 2 or more sub-groups.
>
>Could you share with us: the worst problem you faced and the thing
>that helped you more in this challenge?
>
>Thanks,
>PierG
>
>



--
No virus found in this outgoing message.
Checked by AVG Anti-Virus.
Version: 7.0.322 / Virus Database: 267.3.0 - Release Date: 5/30/2005

#107761 From: "PierG" <piergiorgio_grossi@...>
Date: Tue May 31, 2005 1:33 pm
Subject: Re: [XP] Remote teams
piergiorgio_...
Send Email Send Email
 
Sorry Paul,
I was talking about Virtual Teams and not Virtual Pairs.

Anyway thank you: I found this <http://c2.com/cgi/wiki?
DistributedSoftwareDevelopment> and it's a usefull reading.

PierG

--- In extremeprogramming@yahoogroups.com, Paul Friedman
<samandtwitch@c...> wrote:
> Pier,
>
> There was a pretty decent discussion on this list in December that
is
> summarized here:
>
> http://c2.com/cgi/wiki?VirtualPairProgramming
>
> Look toward the bottom of the page.
>
> The message thread is entitled 'Remote Pair Programming' and
starts w/
> msg 100535 on December 9, 2004.
>
> pax et bonum. p.
>
>
> PierG wrote:
>
> >Ciao,
> >I know there are experiences around about working with XP teams
> >geographically splitted into 2 or more sub-groups.
> >
> >Could you share with us: the worst problem you faced and the
thing
> >that helped you more in this challenge?
> >
> >Thanks,
> >PierG
> >
> >
>
>
>
> --
> No virus found in this outgoing message.
> Checked by AVG Anti-Virus.
> Version: 7.0.322 / Virus Database: 267.3.0 - Release Date:
5/30/2005

#107762 From: Willem Bogaerts <w-p@...>
Date: Tue May 31, 2005 1:41 pm
Subject: Re: [XP] Remote teams
toetah2000
Send Email Send Email
 
Probably not entirely what you are looking for, but maybe useful:

http://www.martinfowler.com/articles/agileOffshore.html

Best regards,
Willem Bogaerts

Paul Friedman wrote:
> Pier,
>
> There was a pretty decent discussion on this list in December that is
> summarized here:
>
> http://c2.com/cgi/wiki?VirtualPairProgramming
>
> Look toward the bottom of the page.
>
> The message thread is entitled 'Remote Pair Programming' and starts w/
> msg 100535 on December 9, 2004.
>
> pax et bonum. p.
>
>
> PierG wrote:
>
>
>>Ciao,
>>I know there are experiences around about working with XP teams
>>geographically splitted into 2 or more sub-groups.
>>
>>Could you share with us: the worst problem you faced and the thing
>>that helped you more in this challenge?
>>
>>Thanks,
>>PierG
>>
>>
>
>
>
>

#107763 From: "John D. Mitchell" <johnm-extreme@...>
Date: Tue May 31, 2005 2:08 pm
Subject: [XP] Remote teams
johnm-extreme@...
Send Email Send Email
 
>>>>> "PierG" == PierG  <piergiorgio_grossi@...> writes:
[...]

> Could you share with us: the worst problem you faced and the thing that
> helped you more in this challenge?

Poor and mis-communication.

Developing "personal" relationships.  I.e., getting the separated teams /
team members together (in-person) on a relatively regular basis for both
work and non-work activities.


Basically, remote teams suffer from the fact that, as in in-person groups,
there's the official way things are supposed to get done and then there's
the way that things actually get done.  This is one of the underlying
flaws/benefits of how outsourcing (and offshoring) works.

Have fun,
	 John

#107764 From: Andrew McDonagh <andrew.mcdonagh@...>
Date: Tue May 31, 2005 2:19 pm
Subject: Re: [XP] Remote teams
andy_ipaccess
Send Email Send Email
 
John D. Mitchell wrote:

>>>>>>"PierG" == PierG  <piergiorgio_grossi@...> writes:
>>>>>>
>>>>>>
>[...]
>
>
>
>>Could you share with us: the worst problem you faced and the thing that
>>helped you more in this challenge?
>>
>>
>
>Poor and mis-communication.
>
>Developing "personal" relationships.  I.e., getting the separated teams /
>team members together (in-person) on a relatively regular basis for both
>work and non-work activities.
>
>
>Basically, remote teams suffer from the fact that, as in in-person groups,
>there's the official way things are supposed to get done and then there's
>the way that things actually get done.  This is one of the underlying
>flaws/benefits of how outsourcing (and offshoring) works.
>
>Have fun,
> John
>
>
>

Agreed, this often leads to there being more than one team - each
geographic grouping becomes (or maintains if they already exist) a
stand-alone-team. This in itself can lead to the teams blaming each
other for problems that arise.  "...its the UK's fault so-and-so is late
as they changed blar-blar at the last minute..."

I've heard some companies having success with distributed development,
have created the 'one-team' environment by seconding people from one
team to another, by daily hand-over (video) meetings everyday, by the
many distributed groups of people working as a single team on the same
project, rather than distributing responsibility for the project around
the world.

KeithBraithwaite
<http://www.xpdeveloper.com/xpdwiki/Wiki.jsp?page=KeithBraithwaite> from
WDS Global recently did a seminar in London on their implementation of
distributed XP - it was very good - but I can't find any slides on line.....

Andrew

#107765 From: "Jeff Grigg" <jeffgrigg@...>
Date: Tue May 31, 2005 2:37 pm
Subject: Re: [XP] Zen Refactoring and duplication
jeffgrigg63132
Send Email Send Email
 
> --- Friedrich Brunzema wrote:
>> do you sometimes introduce deliberate duplication of code?
>> I sometimes use this technique because it seems easier to
>> refactor later than to try to do the refactoring first.
>> I have also sometimes created the duplication, and then
>> worked to make the duplicated code as similar as possible
>> before removing the duplication.  Does anyone else do this?

--- Tony Byrne <yahoogroups@b...> wrote:
> More or less, yes.  I tend to spot simpler forms of
> duplication as I create them.  I try to resist the urge
> to remove the duplication before the test I'm working
> on passes.  It's not always easy, and when I fail to
> resist I usually regret it.

--- Phlip <phlip2005@g...> wrote:
> When adding behavior, duplicate code on purpose, to then
> permit Refactors, beginning with Extract Method, to isolate
> the common cases from the special cases.


Yes, like Tony and Phlip, I often notice that I create duplication
when adding new features, and purposely refrain from refactoring it
out until I have a green bar.  So it's...

1. Green Bar.
2. Add test.
3. Red Bar.
4. Add code to pass the test.  (Often really nasty code with
duplication, hard-coded values, and other nasty icky stuff.)
5. Green Bar.
6. "That code *stinks!*"  (...about the newly added code.  ;-)
7. Refactor.
8. Green Bar (and good code with no smells or duplication).

- - -

I've also been known to refactor *in* duplication, as needed to
reach a desired end state.  In the "Order of Stories and Cost/Order
of Stories - Jeff Grigg - 2005-05-30.zip" example I uploaded to the
Files section last night, there were several cases of adding
duplication to get to a desired final simplified state with no
remaining duplication.  Unfortunately, I glossed over such steps in
my description of what I was doing.

For example, in the "Scenario 2c - Basic, Plus Sorting.doc"
document, I say, "So I refactor to replace the ArrayList fields with
TreeMaps, [...]" and present the refactored result.  I did not show
the detailed steps which went something like this:

1. Add a TreeMap field, next to the existing ArrayList field.

2. Add TreeMap maintenance code in all the methods that change the
ArrayList contents.  The duplication starts to look ugly at this
point.

3. Add code to the methods that read and use the ArrayList, to use
the TreeMap instead.  Sometimes I comment out the old code,
sometimes I do "if (true) { <new code> } else { <old code> }", and
sometimes I just delete the old code.  As long as the old code is
there, the duplication is really obvious and annoying.  (OK, if I
was really gutsy, I'd just delete the old code.  But I'm not always
that self-confident.  ;-)

4. Once all the methods are using the TreeMap field, and all the
tests pass, start deleting the ArrayList code, running the tests
from time to time, until I can delete the ArrayList field.

5. Do refactoring, often renaming fields and variables, and
sometimes extracting methods, to reduce duplication and eliminate
smells.

So this is an example of introducing duplication, through
refactoring, to reach a later state of fewer smells and less
duplication.  I find that to go from a "local maximum" to a
different and better state, it's sometimes necessary to go "over a
hump" between them.  And doing that in small steps requires making
things worse before they can get better.

#107766 From: William Pietri <william@...>
Date: Tue May 31, 2005 3:03 pm
Subject: Re: [XP] Remote teams
william_pietri
Send Email Send Email
 
On Tue, 2005-05-31 at 12:39 +0000, PierG wrote:
> Ciao,
> I know there are experiences around about working with XP teams
> geographically splitted into 2 or more sub-groups.
>
> Could you share with us: the worst problem you faced and the thing
> that helped you more in this challenge?

My general feeling is that it's much less fun than all-in-one-room
development, and that a distributed group needs to spend a lot more time
meeting, emailing, and maintaining documentation. It's much harder to
keep a distributed team in sync, so I like it when each team has a queue
of work that they can do when the other side falls behind.

However, the times I've seen it work adequately are where there's a
natural place to split things that reduces the need for information to
flow across the boundary. For example, a client/server app might
naturally split into client-side and server-side development.

It can be especially helpful when the communication includes test cases,
or at least the kinds of examples that can easily be turned into test
cases.

William

--
William Pietri <william@...>

#107767 From: "hammett" <hammett@...>
Date: Tue May 31, 2005 3:52 pm
Subject: Re: [XP] Zen Refactoring
hammett1233
Send Email Send Email
 
----- Original Message -----
From: "Ron Jeffries" <ronjeffries@...>

> Next time you feel one of those hundred-line blocks coming on, you
> might want to try programming it "by intention". Please let us know
> what happens, if you do.

Definitely. Thanks

--
Cheers,
hammett
http://www.castleproject.org/~hammett

#107768 From: "Kent Beck" <kentb@...>
Date: Tue May 31, 2005 5:47 pm
Subject: RE: [XP] Zen Refactoring
kentlbeck
Send Email Send Email
 
Hammet,

Do you notice any negative effects from writing "long" methods?

Kent Beck
Three Rivers Institute

> -----Original Message-----
> From: extremeprogramming@yahoogroups.com
> [mailto:extremeprogramming@yahoogroups.com] On Behalf Of hammett
> Sent: Monday, May 30, 2005 7:12 PM
> To: extremeprogramming@yahoogroups.com
> Subject: Re: [XP] Zen Refactoring
>
> Sometimes I create methods with hundreds of lines - aware
> that it must be
> refactored.
>
> After testing and debugging the flow I extract the body into smaller
> methods. I'm not proud of it, but it's seems/feels faster
> than refactoring
> during code. Sometimes the code is not simple, so I use my
> energy to stay
> focused on the problem I'm trying to solve. After that I use
> my energy on
> the refactoring.
>
> --
> Cheers,
> hammett
> http://www.castleproject.org/~hammett

#107769 From: "Kent Beck" <kentb@...>
Date: Tue May 31, 2005 5:47 pm
Subject: RE: [XP] Re: Extreme Programming Refactored book (Danger of XP in fact)
kentlbeck
Send Email Send Email
 
Paul,

Six or seven years ago I was uncomfortable with the idea of other people
having different answers than mine. Since then I've learned, in no uncertain
terms, that there are as many answers as there are people asking. The first
edition of XPE is "the" answer (which is absurd but comforting for those who
don't like ambiguity). The second edition is, as you say, a method for
finding the answer with hints of previously-valuable directions for
exploration.

Kent Beck
Three Rivers Institute

> -----Original Message-----
> From: extremeprogramming@yahoogroups.com
> [mailto:extremeprogramming@yahoogroups.com] On Behalf Of Paul Sinnett
> Sent: Sunday, May 29, 2005 11:04 AM
> To: extremeprogramming@yahoogroups.com
> Subject: Re: [XP] Re: Extreme Programming Refactored book
> (Danger of XP in fact)
>
>
> What puzzles me is why XPE was book about the answer rather than
> the method for finding the answer. (Maybe that would have been
> too short for a book?)

#107770 From: "Kent Beck" <kentb@...>
Date: Tue May 31, 2005 5:47 pm
Subject: RE: [XP] Does risk management clash with playing to win?
kentlbeck
Send Email Send Email
 
What if your customer really was your customer?

> -----Original Message-----
> From: extremeprogramming@yahoogroups.com
> [mailto:extremeprogramming@yahoogroups.com] On Behalf Of
> William Pietri
> Sent: Friday, May 27, 2005 2:41 PM
> To: extremeprogramming@yahoogroups.com
> Subject: Re: [XP] Does risk management clash with playing to win?
>
> On Fri, 2005-05-27 at 22:24 +0200, Paul Sinnett wrote:
> > Laurent Bossavit wrote:
> > >> I looked at XP and risk management some time ago and it
> > >> seems to me that XP is tailored towards an environment where
> > >> the customer takes on most of the risk.
> > >
> > > Which risk, or risks ? [...]
> >
> > By take on risk I mean bear the cost should the risk materialise.
> > For example, with a time & materials contract, the developers are
> > paid no matter the outcome of the project. They bear no risk
> > should the product not live up to expectation.
>
> I think is one of those situations where the XP term "Customer" is too
> easily confused with the real-world term "customer".
>
> I agree that XP works very well on a time-and-materials
> contract. But I
> think it works just as well on projects where the developers are in
> house, even in small companies where the developers are also
> substantial
> investors and therefore are taking on a lot of the risk.
>
> I'd also agree that fixed-bid situations are a challenge, but
> I'd still
> use XP. For a fixed-bid project, I'd appoint an internal XP Customer
> (which I'd call a product manager) whose responsibilities included
> syncing with the client and . In a fixed-bid situation, letting the
> real-world customer be the XP Customer would be dangerous, as
> it breaks
> the feedback loop between desires and costs.
>
> William
>
> --
> William Pietri <william@...>
>
>
>
> To Post a message, send it to:   extremeprogramming@eGroups.com
>
> To Unsubscribe, send a blank message to:
> extremeprogramming-unsubscribe@eGroups.com
>
> ad-free courtesy of objectmentor.com
> Yahoo! Groups Links
>
>
>
>
>
>
>
>

#107771 From: Elizabeth Keogh <ekeogh@...>
Date: Tue May 31, 2005 5:23 pm
Subject: Re: [XP] Zen Refactoring
deathbypeaches
Send Email Send Email
 
Hi Ron,

Many of our functional tests are 100+ line blocks of code. I programmed by
intention and the test is much more legible as a result.

It's quite hard to refactor things when there are no tests (or tests for
tests) to verify the refactoring, and much easier to write them in
manageable chunks to start with. Having a decent IDE also helps. Even so,
I've managed to break tests with refactoring and not known about it - ie:
the test has passed, but hasn't actually been testing the behaviour it was
meant to be testing any more. Putting "tset" instead of "test" at the
beginning of a method will do that.

I'm a big fan of legible tests.

Regards,
Liz.

Ron Jeffries wrote on 31/05/2005 10:45:15:

> Next time you feel one of those hundred-line blocks coming on, you
> might want to try programming it "by intention". Please let us know
> what happens, if you do.
>
> Regards,
>
> Ron Jeffries
> www.XProgramming.com
> I could be wrong, but I'm not.  --Eagles, Victim of Love

--
Elizabeth Keogh
ekeogh@...
http://www.livejournal.com/users/sirenian


[Non-text portions of this message have been removed]

#107772 From: Ron Jeffries <ronjeffries@...>
Date: Tue May 31, 2005 6:17 pm
Subject: Re: [XP] Zen Refactoring
RonaldEJeffries
Send Email Send Email
 
On Tuesday, May 31, 2005, at 1:23:51 PM, Elizabeth Keogh wrote:

> Many of our functional tests are 100+ line blocks of code. I programmed by
> intention and the test is much more legible as a result.

> It's quite hard to refactor things when there are no tests (or tests for
> tests) to verify the refactoring, and much easier to write them in
> manageable chunks to start with. Having a decent IDE also helps. Even so,
> I've managed to break tests with refactoring and not known about it - ie:
> the test has passed, but hasn't actually been testing the behaviour it was
> meant to be testing any more. Putting "tset" instead of "test" at the
> beginning of a method will do that.

> I'm a big fan of legible tests.

Interesting report ... and interesting yahoo ID as well.

I'm into legible myself. I usually answer, when people ask about
refactoring the tests without test-tests (quis custodiet ad
infinitum), that when we refactor tests, they tend to break. You've
come up with one way to call me a liar ... are there other common
ways to refactor tests so that they appear to run, but don't?

Ron Jeffries
www.XProgramming.com
Steering is more important than speed,
in driving and in software development.

#107773 From: "hammett" <hammett@...>
Date: Tue May 31, 2005 6:27 pm
Subject: Re: [XP] Zen Refactoring
hammett1233
Send Email Send Email
 
Of course, it's pretty confusing afterwards. No question about it. But again
I think the easier approach - given the circunstances - is to focus on the
problem at hand, then later focus on refactoring the code. Doing both may
have terrible results as someone here confirmed.

But allow me to express myself.

Given a non trivial problem at hand where you don't have a clear cut
solution up front, but let's get concrete. The last time it happened (last
sunday) I had to

- Visit AST nodes using breadth-first
- Upon MultipleVariableDeclarationStatement node
   - Convert it to one or more SingleDeclarationStatement
   - Check whether the identifier on the SingleDeclarationStatement was
already on the current naming scope
   - Check whether the identifier related to a local, instance of static
field
     - if instance or static, move the SingleDeclarationStatement to the
parent AST node
     - replace the SingleDeclarationStatement node by an AssignmentExpression

Well, I have never ever coded something similar, so I started from the
begining. Note that there are multiple concerns being resolved upon a single
MultipleVariableDeclarationStatement visit. My first approach was to focus
on the problem at hand and code them at the same method (a kind of brain
dump). After my test cases passed, I refactored them into three distinct
methods.

--
Cheers,
hammett
http://www.castleproject.org/~hammett


----- Original Message -----
From: "Kent Beck" <kentb@...>
To: <extremeprogramming@yahoogroups.com>
Sent: Tuesday, May 31, 2005 2:47 PM
Subject: RE: [XP] Zen Refactoring


> Hammet,
>
> Do you notice any negative effects from writing "long" methods?
>
> Kent Beck
> Three Rivers Institute

#107774 From: William Pietri <william@...>
Date: Tue May 31, 2005 6:39 pm
Subject: RE: [XP] Does risk management clash with playing to win?
william_pietri
Send Email Send Email
 
Hi, Kent!

On Tue, 2005-05-31 at 10:47 -0700, Kent Beck wrote:
> What if your customer really was your customer?

I didn't understand your question. I could parse this to mean

       * What would happen if in a fixed-bid situation a client filled
         the XP customer role?
       * What kind of contract would support the client filling the XP
         Customer role?
       * What would happen if the product's end purchaser, the real
         customer, filled the XP Customer role?

Was one of these akin to your question?

Thanks,

William

> > -----Original Message-----
> > From: extremeprogramming@yahoogroups.com
> > [mailto:extremeprogramming@yahoogroups.com] On Behalf Of
> > William Pietri
> > Sent: Friday, May 27, 2005 2:41 PM
> > To: extremeprogramming@yahoogroups.com
> > Subject: Re: [XP] Does risk management clash with playing to win?
> >
> > On Fri, 2005-05-27 at 22:24 +0200, Paul Sinnett wrote:
> > > Laurent Bossavit wrote:
> > > >> I looked at XP and risk management some time ago and it
> > > >> seems to me that XP is tailored towards an environment where
> > > >> the customer takes on most of the risk.
> > > >
> > > > Which risk, or risks ? [...]
> > >
> > > By take on risk I mean bear the cost should the risk materialise.
> > > For example, with a time & materials contract, the developers are
> > > paid no matter the outcome of the project. They bear no risk
> > > should the product not live up to expectation.
> >
> > I think is one of those situations where the XP term "Customer" is too
> > easily confused with the real-world term "customer".
> >
> > I agree that XP works very well on a time-and-materials
> > contract. But I
> > think it works just as well on projects where the developers are in
> > house, even in small companies where the developers are also
> > substantial
> > investors and therefore are taking on a lot of the risk.
> >
> > I'd also agree that fixed-bid situations are a challenge, but
> > I'd still
> > use XP. For a fixed-bid project, I'd appoint an internal XP Customer
> > (which I'd call a product manager) whose responsibilities included
> > syncing with the client and . In a fixed-bid situation, letting the
> > real-world customer be the XP Customer would be dangerous, as
> > it breaks
> > the feedback loop between desires and costs.
> >
> > William
> >
> > --
> > William Pietri <william@...>
> >
> >
> >
> > To Post a message, send it to:   extremeprogramming@eGroups.com
> >
> > To Unsubscribe, send a blank message to:
> > extremeprogramming-unsubscribe@eGroups.com
> >
> > ad-free courtesy of objectmentor.com
> > Yahoo! Groups Links
> >
> >
> >
> >
> >
> >
> >
> >
>
>
>
> To Post a message, send it to:   extremeprogramming@eGroups.com
>
> To Unsubscribe, send a blank message to:
extremeprogramming-unsubscribe@eGroups.com
>
> ad-free courtesy of objectmentor.com
> Yahoo! Groups Links
>
>
>
>
>
>
>
--
William Pietri <william@...>

#107775 From: yahoogroups@...
Date: Tue May 31, 2005 6:38 pm
Subject: Re: [XP] Zen Refactoring
jhrothjr
Send Email Send Email
 
From: "Elizabeth Keogh"
<ekeogh.at.thoughtworks.com@...>
To: "extremeprogramming@yahoogroups.com"
<extremeprogramming.at.yahoogroups.com@...>
Sent: Tuesday, May 31, 2005 11:23 AM
Subject: Re: [XP] Zen Refactoring


> Hi Ron,
>
> Many of our functional tests are 100+ line blocks of code. I programmed by
> intention and the test is much more legible as a result.
>
> It's quite hard to refactor things when there are no tests (or tests for
> tests) to verify the refactoring, and much easier to write them in
> manageable chunks to start with. Having a decent IDE also helps. Even so,
> I've managed to break tests with refactoring and not known about it - ie:
> the test has passed, but hasn't actually been testing the behaviour it was
> meant to be testing any more. Putting "tset" instead of "test" at the
> beginning of a method will do that.

I've done that a few times too many; now I keep track of the total number
of tests that were run, and if it isn't what I expected I check what I did
wrong. It isn't just misspelling test either; sometimes I find that I forget
to put a new test class into the suite. However, I saw a way of avoiding
that error a few days ago; I think I'll try it out.

John Roth

>
> I'm a big fan of legible tests.
>
> Regards,
> Liz.
>
> Ron Jeffries wrote on 31/05/2005 10:45:15:
>
>> Next time you feel one of those hundred-line blocks coming on, you
>> might want to try programming it "by intention". Please let us know
>> what happens, if you do.
>>
>> Regards,
>>
>> Ron Jeffries
>> www.XProgramming.com
>> I could be wrong, but I'm not.  --Eagles, Victim of Love
>
> --
> Elizabeth Keogh
> ekeogh@...
> http://www.livejournal.com/users/sirenian
>
>
> [Non-text portions of this message have been removed]
>
>
>
>
>
>
> To Post a message, send it to:   extremeprogramming@eGroups.com
>
> To Unsubscribe, send a blank message to:
> extremeprogramming-unsubscribe@eGroups.com
>
> ad-free courtesy of objectmentor.com
> Yahoo! Groups Links
>
>
>
>
>
>
>

#107776 From: Paul Sinnett <paul_sinnett@...>
Date: Tue May 31, 2005 6:54 pm
Subject: Re: [XP] Re: Extreme Programming Refactored book (Danger of XP in fact)
paul_sinnett
Send Email Send Email
 
Kent Beck wrote:
> Paul,
>
> Six or seven years ago I was uncomfortable with the idea of
> other people having different answers than mine. Since then
> I've learned, in no uncertain terms, that there are as many
> answers as there are people asking. The first edition of XPE
> is "the" answer (which is absurd but comforting for those who
> don't like ambiguity). The second edition is, as you say, a
> method for finding the answer with hints of
> previously-valuable directions for exploration.

I see. I haven't seen the second edition yet. I must look out for
a copy when I get back to England.


___________________________________________________________
How much free photo storage do you get? Store your holiday
snaps for FREE with Yahoo! Photos http://uk.photos.yahoo.com

#107777 From: "SirGilligan" <sirgilligan@...>
Date: Tue May 31, 2005 8:07 pm
Subject: [XP] Re: Extreme Programming Refactored book (Danger of XP in fact)
SirGilligan
Send Email Send Email
 
--- In extremeprogramming@yahoogroups.com, Paul Sinnett
<paul_sinnett@y...> wrote:
> Kent Beck wrote:
> > Paul,
> >
> > Six or seven years ago I was uncomfortable with the idea of
> > other people having different answers than mine. Since then
> > I've learned, in no uncertain terms, that there are as many
> > answers as there are people asking. The first edition of XPE
> > is "the" answer (which is absurd but comforting for those who
> > don't like ambiguity). The second edition is, as you say, a
> > method for finding the answer with hints of
> > previously-valuable directions for exploration.
>
> I see. I haven't seen the second edition yet. I must look out for
> a copy when I get back to England.
>

I find the second edition (XP2E) to be very valuable. I highly
recommend it to everyone. You can read it cover to cover, it flows
well, and is very cohesive.

#107778 From: Ian Collins <ian@...>
Date: Tue May 31, 2005 8:15 pm
Subject: Re: [XP] Zen Refactoring
masumanz
Send Email Send Email
 
Luiz Esmiralha wrote:

>In my oppinion, ProgrammingByIntention is the father of
>TestFirstProgramming. And it feels so natural that I wonder if I ever
>did program any other way.
>
>
>
I agree, it's a technique I'd been using for years before I discovered
TDD.  Maybe that's why I find TDD so natural.

I started doing it as a form of live pseudo code, getting my ideas on
the screen.  Why wast time putting pseudo code in a text file when it
can be live?  As a lazy bugger, I liked this as a great way of producing
self documenting code.

>Thanks for your example, Ron.
>
>
>
Indeed.

Ian

>On 5/31/05, Ron Jeffries <ronjeffries@...> wrote:
>
>
>>On Monday, May 30, 2005, at 10:11:41 PM, hammett wrote:
>>
>>
>>
>>>Sometimes I create methods with hundreds of lines - aware that it must be
>>>refactored.
>>>
>>>
>>>After testing and debugging the flow I extract the body into smaller
>>>methods. I'm not proud of it, but it's seems/feels faster than refactoring
>>>during code. Sometimes the code is not simple, so I use my energy to stay
>>>focused on the problem I'm trying to solve. After that I use my energy on
>>>the refactoring.
>>>
>>>
>>I do that sometimes, but far less often than I did. For me, it is
>>definitely not faster, beyond maybe ten or twenty lines, if then.
>>
>>When I'm working in that linear way, I'm always thinking, something
>>like:
>>
>>  OK, first I'll open the file ...
>>    bang out a few lines;
>>
>>  Now I'll loop reading it ...
>>    a few more, with a {}, position cursor inside;
>>
>>  Each line I'll check for "foo" ...
>>    an if statement;
>>
>>  And if I get it, parse the line ...
>>    a bunch of regexp;
>>
>>  And toss it in the output ...
>>    a couple of lines;
>>
>>I find that what works better for me is a technique that I learned
>>from Kent Beck, which I call "Programming by Intention" (because I
>>believe that's what he called it). It goes like this for the same
>>problem:
>>
>>    file := OpenFile("something");
>>    ProcessFile(file);
>>    close(file); /* did you notice I forgot? Neither did I! */
>>
>>  procedure ProcessFile(aFile)
>>    while (! aFile.EOF ) {
>>      ProcessLine(aFile.readLine)
>>    }
>>
>>  procedure ReadLine(aLine)
>>    if (aLine.contains("foo")) {
>>      resultLine = ParseLine(aLine);
>>      SaveLine(resultLine);
>>
>>
>>  function ParseLine(aLine)
>>    return regexp stuff;
>>
>>  procedure (SaveLine)
>>    output += SaveLine;
>>
>>When I work this way, my first draft of the program might not be
>>quite this highly factored, but often it is. When it's not, it might
>>look like this:
>>
>>  procedure ProcessFile(aFile)
>>    while (! aFile.EOF ) {
>>      line = aFile.ReadLine;
>>      if (line.contains("foo") {
>>        resultLine = ParseLine(line);
>>        output += resultLine;
>>    }
>>
>>Generally speaking, the sooner I express /what/ I'm doing, rather
>>than /how/ I'm doing it; the longer I leave off expressing /how/ I'm
>>doing it ... the better it works for me.
>>
>>Next time you feel one of those hundred-line blocks coming on, you
>>might want to try programming it "by intention". Please let us know
>>what happens, if you do.
>>
>>Regards,
>>
>>Ron Jeffries
>>www.XProgramming.com
>>I could be wrong, but I'm not.  --Eagles, Victim of Love
>>
>>
>>
>>To Post a message, send it to:   extremeprogramming@eGroups.com
>>
>>To Unsubscribe, send a blank message to:
extremeprogramming-unsubscribe@eGroups.com
>>
>>ad-free courtesy of objectmentor.com
>>Yahoo! Groups Links
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>
>
>To Post a message, send it to:   extremeprogramming@eGroups.com
>
>To Unsubscribe, send a blank message to:
extremeprogramming-unsubscribe@eGroups.com
>
>ad-free courtesy of objectmentor.com
>Yahoo! Groups Links
>
>
>
>
>
>
>
>
>
>

#107779 From: Ian Collins <ian@...>
Date: Tue May 31, 2005 8:21 pm
Subject: Re: [XP] Remote teams
masumanz
Send Email Send Email
 
John D. Mitchell wrote:

>>>>>>"PierG" == PierG  <piergiorgio_grossi@...> writes:
>>>>>>
>>>>>>
>[...]
>
>
>
>>Could you share with us: the worst problem you faced and the thing that
>>helped you more in this challenge?
>>
>>
>
>Poor and mis-communication.
>
>
>
Some recent threads here are great examples of this :)

>Developing "personal" relationships.  I.e., getting the separated teams /
>team members together (in-person) on a relatively regular basis for both
>work and non-work activities.
>
>
>
Vital.  We have run a couple of joint NZ/UK projects and they flew or
crashed entirely on the interpersonal relationships.

>Basically, remote teams suffer from the fact that, as in in-person groups,
>there's the official way things are supposed to get done and then there's
>the way that things actually get done.  This is one of the underlying
>flaws/benefits of how outsourcing (and offshoring) works.
>
>
>
They also have their own agendas and gaols (career progression etc..)
which can be extremely difficult to unify.

Ian

>Have fun,
> John
>
>
>To Post a message, send it to:   extremeprogramming@eGroups.com
>
>To Unsubscribe, send a blank message to:
extremeprogramming-unsubscribe@eGroups.com
>
>ad-free courtesy of objectmentor.com
>Yahoo! Groups Links
>
>
>
>
>
>
>
>
>
>

#107780 From: "Donald Roby" <droby@...>
Date: Tue May 31, 2005 10:20 pm
Subject: New England Agile Bazaar - Next Meeting June 16, 2005
donalroby
Send Email Send Email
 
* MEETING NOTICE *

           New England Agile Bazaar - Next Meeting June 16, 2005

TOPIC: Agile SCM

PRESENTER: Steve Berczuk, co-author of "Software Configuration
Management Patterns: Effective Teamwork, Practical Integration"

ABSTRACT: One of the most common roadblocks to effective team software
development is inappropriate or ineffective configuration management
practices.  Developers can't easily create workspaces, code with
errors is checked in, slowing down other team members, and integration
takes a long time at the end of the project. This tutorial will show
how to create an effective development environment that allows for
rapid change by using appropriate build, version management and
testing practices.

DATE: Thursday, June 16, 2005

TIME: 6:00 - 8:30pm;  (6-6:30 networking, announcements;
6:30-7:30 presentation; 7:30-8:30 food, networking)

LOCATION: Halligan Hall Room 111, Tufts University, 165 College Ave,
Medford MA.

COST: $10 (collected at the door, primarily covering food)

RSVP: Don Roby <droby@...>

DIRECTIONS:  Use the campus map at
http://www.tufts.edu/home/maps/medford/ to find Halligan Hall,
165 College Ave, Medford, MA.  This map can also  be used to find
nearby parking, including the main ($5 fee) parking garage at Dowling
Hall, 419 Boston Avenue, Medford, MA.


                   About New England Agile Bazaar

The New England Agile Bazaar is a group of software engineers,
software managers, and software test professionals who are now using
Agile software methodologies or who are considering using them. "Agile
methodologies" includes Scrum, Extreme Programming, DSDM, Crystal
Clear, to name a few. What they all have in common is an iterative,
flexible approach to software development that enables teams to
deliver on their commitments while using simple rules to balance
risks.

#107781 From: "John D. Mitchell" <johnm-extreme@...>
Date: Tue May 31, 2005 10:58 pm
Subject: Re: [XP] Remote teams
johnm-extreme@...
Send Email Send Email
 
>>>>> "Ian" == Ian Collins <ian@...> writes:
>>>>>> John D. Mitchell writes:
[...]

>> Poor and mis-communication.

> Some recent threads here are great examples of this :)

Indeed.


[...]
>> Basically, remote teams suffer from the fact that, as in in-person
>> groups, there's the official way things are supposed to get done and
>> then there's the way that things actually get done.  This is one of the
>> underlying flaws/benefits of how outsourcing (and offshoring) works.

> They also have their own agendas and gaols (career progression etc..)
> which can be extremely difficult to unify.

Indeed.

Sort of like the developers and the marketing people working in the same
building. :-)

And heck, NZs and UKers are a lot more similar than say an US east coast
hacker team and a Vietnamese job-shop "team" trying to work together.
Cultural differences (and their resulting poor/mis-communication, etc.)
induce if not outright cause a lot of problems for distributed teams.

Mindless fantasies of chimerical "cost reductions" lose touch with all of
these "soft" issues that drive most of the real costs and risks in such
abstract endeavors as technological development.

Take care,
	 John

#107782 From: Edmund Schweppe <schweppe@...>
Date: Wed Jun 1, 2005 12:54 am
Subject: Re: [XP] Extreme Programming Refactored book (Danger of XP in fact)
schweppe@...
Send Email Send Email
 
Ron Jeffries wrote:
> On Monday, May 30, 2005, at 8:19:01 PM, Edmund Schweppe wrote:
>> My extraordinarily limited understanding of both Ron and XP leads
>> me to believe that Ron might even go so far as to disavow the very
>> existence of an "XP spokesperson."
> I would not so disavow.

Thus proving by demonstration the limited nature of my understanding.
(Not that it was ever in question, mind you.)

>> However, my not-Ron-ness is the stuff of legends, and thus my
>> aforementioned belief should be taken with a particularly large
>> grain of metaphorical salt.
> Yum. Love metaphorical salt. Got any semantic popcorn? :)

Semantic popcorn? Is that kosher?

#107783 From: Ron Jeffries <ronjeffries@...>
Date: Wed Jun 1, 2005 1:21 am
Subject: Re: [XP] Zen Refactoring
RonaldEJeffries
Send Email Send Email
 
Hi Hammett,

Thanks for the cut at an example ... comments below.

Around Tuesday, May 31, 2005, 2:27:42 PM, hammett wrote:

> Of course, it's pretty confusing afterwards. No question about it. But again
> I think the easier approach - given the circunstances - is to focus on the
> problem at hand, then later focus on refactoring the code. Doing both may
> have terrible results as someone here confirmed.

> But allow me to express myself.

> Given a non trivial problem at hand where you don't have a clear cut
> solution up front, but let's get concrete. The last time it happened (last
> sunday) I had to

> - Visit AST nodes using breadth-first
> - Upon MultipleVariableDeclarationStatement node
>   - Convert it to one or more SingleDeclarationStatement
>   - Check whether the identifier on the SingleDeclarationStatement was
> already on the current naming scope
>   - Check whether the identifier related to a local, instance of static
> field
>     - if instance or static, move the
> SingleDeclarationStatement to the
> parent AST node
>     - replace the SingleDeclarationStatement node by an AssignmentExpression

> Well, I have never ever coded something similar, so I started from the
> begining. Note that there are multiple concerns being resolved upon a single
> MultipleVariableDeclarationStatement visit. My first approach was to focus
> on the problem at hand and code them at the same method (a kind of brain
> dump). After my test cases passed, I refactored them into three distinct
> methods.

Starting from the beginning is good. What I'm not so clear about is
whether it is preferable to write out the three bits "longhand" and
then extract them. For me, it's not. I have observed that I always
have in mind something like:

   I'll visit each node ...
   if it's a MultipleVariableDeclarationStatement ...
   convert it to one or more SingleDeclarationStatements ... then
   if the id is in the scope ...
     and it's instance or static ...
       move to the parent ...
       replace by an assignment expression
         (note that from your text I don't know where this goes in
         the if nest ... but I bet you did.)

Or maybe I just have ...

   I'll visit each node ...
   if it's a MultipleVariableDeclarationStatement ...
   convert it and move it ...

So I code something like

   foreach (ASTNode node in nodes.BreadthFirstList()) {
     ProcessMultipleVariableDeclarationStatements(node);
   }

Then code the Process...Statements() method ... and so on.

I find when I do this that the structure comes out nicer, I do less
post-hoc refactoring, and I go slower.

It might be seen that this is YAGNI ... except, of course that we
/do/ need to express all our ideas.

So ... I've tried both ways ... the more expressive way works better
for me. Sometimes I have the whole algorithm in my head and want to
just blurt it out. Sometimes I can resist doing that. It seems to me
that when I do resist, and go with the expressive version, it goes
more smoothly.

I don't know whether that would be true for anyone else ...

Ron Jeffries
www.XProgramming.com
Comments lie. Code doesn't.

#107784 From: "Jeff Grigg" <jeffgrigg@...>
Date: Wed Jun 1, 2005 2:59 am
Subject: Duplication vs Intention Revealing code (was: Zen Refactoring)
jeffgrigg63132
Send Email Send Email
 
---  Tony Byrne wrote:
> As a TDD kata, I recently implemented a small program to
> convert integers to a string representation in words.
> (e.g. 1 --> one, 55 --> fifty-five). For me, this problem
> contains one example of duplication which was easy to
> make disappear once the duplicated code was made similar,
> and one where no matter how I look at it, I can't make
> the code similar enough to make the duplication disappear.
> [...]

This seemed like an interesting diversion, so I gave it a shot this
evening:

Doing Test Driven Development, I write one test at a time (and then
a few at a time), and end up with this for the final test class:

import junit.framework.TestCase;

public class NumbersAsWordsTest extends TestCase {
	 public void testPositiveIntegerValues() {
		 assertEqualsAsWords("zero",  0);
		 assertEqualsAsWords("one",   1);
		 assertEqualsAsWords("two",   2);
		 assertEqualsAsWords("three", 3);
		 assertEqualsAsWords("four",  4);
		 assertEqualsAsWords("five",  5);
		 assertEqualsAsWords("six",   6);
		 assertEqualsAsWords("seven", 7);
		 assertEqualsAsWords("eight", 8);
		 assertEqualsAsWords("nine",  9);
		 assertEqualsAsWords("ten",   10);

		 assertEqualsAsWords("eleven",    11);
		 assertEqualsAsWords("twelve",    12);
		 assertEqualsAsWords("thirteen",  13);
		 assertEqualsAsWords("fourteen",  14);
		 assertEqualsAsWords("fifteen",   15);
		 assertEqualsAsWords("sixteen",   16);
		 assertEqualsAsWords("seventeen", 17);
		 assertEqualsAsWords("eighteen",  18);
		 assertEqualsAsWords("nineteen",  19);

		 assertEqualsAsWords("twenty",      20);
		 assertEqualsAsWords("twenty-one",  21);
		 assertEqualsAsWords("twenty-nine", 29);
		 assertEqualsAsWords("thirty",      30);
		 assertEqualsAsWords("thirty-one",  31);
		 assertEqualsAsWords("thirty-nine", 39);
		 assertEqualsAsWords("fourty",      40);
		 assertEqualsAsWords("fifty",       50);
		 assertEqualsAsWords("sixty",       60);
		 assertEqualsAsWords("seventy",     70);
		 assertEqualsAsWords("eighty",      80);
		 assertEqualsAsWords("ninety",      90);
		 assertEqualsAsWords("ninety-nine", 99);
	 }

	 private static void assertEqualsAsWords(final String words,
final int number) {
		 assertEquals(words, NumbersAsWords_Ver1.asWords
(number));
		 assertEquals(words, NumbersAsWords_Ver2.asWords
(number));
		 assertEquals(words, NumbersAsWords_Ver3.asWords
(number));
		 assertEquals(words, NumbersAsWords_Ver4.asWords
(number));
	 }
}

And I a nice simple implementation for two byte positive integers:

public class NumbersAsWords_Ver1 {
	 public static String asWords(final int value) {
		 if (value >= 20) {
			 final int tensDigit = value / 10;
			 final int onesDigit = value % 10;
			 final String[] digitPrefixes = new String[] {

	 "zero", "ten", "twenty", "thirty", "fourty", "fifty", "sixty"
, "seventy", "eighty", "ninety"
			 };
			 final String prefix = digitPrefixes
[tensDigit];
			 final String tensDigitName = prefix;
			 if (onesDigit == 0)
				 return tensDigitName;
			 else
				 return tensDigitName + '-' + asWords
(onesDigit);
		 } else {
			 final String[] smallIntegerNames = new String
[] {

	 "zero",  "one",    "two",    "three",    "four",     "five",
    "six",     "seven",     "eight",    "nine",

	 "ten",   "eleven", "twelve", "thirteen", "fourteen", "fifteen
", "sixteen", "seventeen", "eighteen", "nineteen",
			 };
			 return smallIntegerNames[value];
		 }
	 }
}

I can go on to bigger numbers, but I see duplication here:
  - The two "base 10" numbers, used to separate "tens" from "ones".
  - That "four" and "four-teen" and "four-ty" is duplication.

So I *VERY AGGRESSIVELY* eliminate duplication, and get this:

public class NumbersAsWords_Ver2 {
	 private static final int base = 10;
	 public static String asWords(final int value) {
		 if (value >= 20) {
			 final int tensDigit = value / base;
			 final int onesDigit = value % base;
			 final String tensDigitName = addDigitPostfix
(tensDigit, "ty");
			 if (onesDigit == 0)
				 return tensDigitName;
			 else
				 return tensDigitName + '-' + asWords
(onesDigit);
		 } else {
			 final String[] smallIntegerNames = new String
[] {

	 "zero", "one", "two", "three", "four", "five", "six", "seven"
, "eight", "nine",
				 "ten", "eleven", "twelve",
			 };
			 if (value < 13) {
				 return smallIntegerNames[value];
			 } else {
				 return addDigitPostfix(value -
base, "teen");
			 }
		 }
	 }
	 private static String addDigitPostfix(final int digit, final
String postfix) {
		 final String[] digitPrefixes = new String[]
{"twen", "thir", null, "fif"};
		 final String prefix = (digit == 4 || digit > 5) ?
asWords(digit) : digitPrefixes[digit - 2];
		 return concat(postfix, prefix);
	 }
	 private static String concat(final String postfix, final
String prefix) {
		 final char  lastCharOfPrefix  = prefix.charAt
(prefix.length() - 1);
		 final char firstCharOfPostfix = postfix.charAt(0);
		 if (lastCharOfPrefix == firstCharOfPostfix)
			 return prefix + postfix.substring(1);
		 else
			 return prefix + postfix;
	 }
}

Wow.  That's a mess.  But why stop there?  Since I'm on
an "eliminate duplicates at all costs" rampage, that "two"
and "twelve" are related is still bugging me.  After all, they both
start with "tw"!   ;->

So I'll go a level deeper into the mire, to get here:

public class NumbersAsWords_Ver3 {
	 private static final int base = 10;
	 public static String asWords(final int value) {
		 if (value >= 20) {
			 final int tensDigit = value / base;
			 final int onesDigit = value % base;
			 final String tensDigitName = addDigitPostfix
(tensDigit, "ty");
			 if (onesDigit == 0)
				 return tensDigitName;
			 else
				 return tensDigitName + '-' + asWords
(onesDigit);
		 } else {
			 final String[] smallIntegerNames = new String
[] {

	 "zero", "one", "o", "three", "four", "five", "six", "seven",
"eight", "nine",
				 "ten", "eleven", "elve",
			 };
			 if (value < 13) {
				 final String name = smallIntegerNames
[value];
				 if (value % base == 2)
					 return "tw" + name;
				 else
					 return name;
			 } else {
				 return addDigitPostfix(value -
base, "teen");
			 }
		 }
	 }
	 private static String addDigitPostfix(final int digit, final
String postfix) {
		 final String[] digitPrefixes = new String[]
{"twen", "thir", null, "fif"};
		 final String prefix = (digit == 4 || digit > 5) ?
asWords(digit) : digitPrefixes[digit - 2];
		 return concat(postfix, prefix);
	 }
	 private static String concat(final String postfix, final
String prefix) {
		 final char  lastCharOfPrefix  = prefix.charAt
(prefix.length() - 1);
		 final char firstCharOfPostfix = postfix.charAt(0);
		 if (lastCharOfPrefix == firstCharOfPostfix)
			 return prefix + postfix.substring(1);
		 else
			 return prefix + postfix;
	 }
}

OK, now that's painfully obscure.  I feel like I'm competing in some
obfuscated coding contest.  Since some of the constant strings are
getting well-neigh unreadable, or at least confusing, I think I'll
introduce tilde (~) characters in the constants, where parts of the
words are missing, to make them more readable.

public class NumbersAsWords_Ver4 {
	 private static final int base = 10;
	 public static String asWords(final int value) {
		 if (value >= 20) {
			 final int tensDigit = value / base;
			 final int onesDigit = value % base;
			 final String tensDigitName = addDigitPostfix
(tensDigit, "ty");
			 if (onesDigit == 0)
				 return tensDigitName;
			 else
				 return tensDigitName + '-' + asWords
(onesDigit);
		 } else {
			 final String[] smallIntegerNames = new String
[] {

	 "zero", "one", "~o", "three", "four", "five", "six", "seven",
  "eight", "nine",
				 "ten", "eleven", "~elve",
			 };
			 if (value < 13) {
				 final String name = smallIntegerNames
[value];
				 if (value % base == 2) {
					 final String nameSansTilde =
name.substring(1);
					 return "tw" + nameSansTilde;
				 } else {
					 return name;
				 }
			 } else {
				 return addDigitPostfix(value -
base, "teen");
			 }
		 }
	 }
	 private static String addDigitPostfix(final int digit, final
String postfix) {
		 final String prefix = getPrefix(digit);
		 return concat(postfix, prefix);
	 }
	 private static String getPrefix(final int digit) {
		 final String[] digitPrefixes = new String[]
{"twen~", "thir~", null, "fif~"};
		 if (digit == 4 || digit > 5) {
			 return asWords(digit);
		 } else {
			 final String prefix = digitPrefixes[digit -
2];
			 final String prefixSansTilde =
prefix.substring(0, prefix.length() - 1);
			 return prefixSansTilde;
		 }
	 }
	 private static String concat(final String postfix, final
String prefix) {
		 final char  lastCharOfPrefix  = prefix.charAt
(prefix.length() - 1);
		 final char firstCharOfPostfix = postfix.charAt(0);
		 if (lastCharOfPrefix == firstCharOfPostfix)
			 return prefix + postfix.substring(1);
		 else
			 return prefix + postfix;
	 }
}

There, now that's better.

Hey...  (Going just a little further over the edge, right into the
abyss...)  I see *fifteen* uses of the letter 'e' in the following
list!!!   ;->
	 final String[] smallIntegerNames = new String[] {

	 "zero", "one", "~o", "three", "four", "five", "six", "seven",
  "eight", "nine",
		 "ten", "eleven", "~elve",
	 };
Talk about *duplication*!!!    ;->

Well, except for that, I think I've eliminated all the duplication I
can.  But the program is now twice as long, and it's really not the
kind of code I'd want to look at right after eating dinner!  Ick!!!!


And yet, I was eliminating duplication.  Consider this:
    six   ->   six-teen ->   six-ty
    seven -> seven-teen -> seven-ty
    eight -> eight-teen -> eight-ty  [drop the extra 't']
    nine  ->  nine-teen ->  nine-ty
Isn't that duplication?!?  Shouldn't duplication be eliminated?


So...
I think we've hit an illustrative corner case where the
expressiveness rule trumps the no duplication rule.  It doesn't
happen very often, but I think it can happen from time to time that
you have to reverse Kent's rules 2 and 3:

1. Runs all tests.
2. No Duplication.
3. Expresses Intention.
4. Fewest Classes and Methods.

Sometimes, on rare occasion, it can be more important to write code
that expresses your intention well than it is to remove all
duplication.

(We hit this in the Bowling Game example, as I recall.  But this
seems like a more compelling example.)

Thoughts?  Comments?  Objections?

Thanks!
	 - jeff

#107785 From: yahoogroups@...
Date: Wed Jun 1, 2005 5:30 am
Subject: Re: [XP] Duplication vs Intention Revealing code (was: Zen Refactoring)
jhrothjr
Send Email Send Email
 
From: "Jeff Grigg" <jeffgrigg.at.charter.net@...>
To: "extremeprogramming@yahoogroups.com"
<extremeprogramming.at.yahoogroups.com@...>
Sent: Tuesday, May 31, 2005 8:59 PM
Subject: [XP] Duplication vs Intention Revealing code (was: Zen Refactoring)


> ---  Tony Byrne wrote:
>> As a TDD kata, I recently implemented a small program to
>> convert integers to a string representation in words.
>> (e.g. 1 --> one, 55 --> fifty-five). For me, this problem
>> contains one example of duplication which was easy to
>> make disappear once the duplicated code was made similar,
>> and one where no matter how I look at it, I can't make
>> the code similar enough to make the duplication disappear.
>> [...]
>
> This seemed like an interesting diversion, so I gave it a shot this
> evening:

---

I wind up with a very different result, I suspect because I started
with ones and then stopped to think. This is, of course, in
Python.

The tests are a bit obvious, so I'm going to skip them. The
first interesting result comes after tests for 0 to 9:

class ConvertNumbersToEnglish:
     def numberToEnglish(self, number):
         return self.digitsArray(number)

     digitArray = ["zero", "one", "two", "three", "four",
       "five", "six", "seven", "eight", "nine"]

It doesn't seem like it could get any simpler.

Looking at two digit numbers, it seems like a lot of them
follow a simple pattern: <digit>ty-<digit>.

So let's feed in, say 45 and 63 as test cases. I get this:

     def numberToEnglish(self, number):
         tens, digits = divmod(number, 10)
         if tens == 0:
             return self.digitArray[digits]
        else:
             return "%sty-%s" % (self.digitArray[tens],
self.digitArray[digits])

There's a bit of duplication,  but I don't see how to get rid of it right
now.

There still seem to be three different special cases. A units digit of zero,
a tens digit of one, and tens digits of 2, 3, and 8. Let's  tackle the units
digit of 0 first.

I feed in 40 and 60, and get this as a result:

     def numberToEnglish(self, number):
         tens, digits = divmod(number, 10)
         if tens == 0:
             return self.digitArray[digits]
         elif digits == 0:
             return "%sty" % digitArray[tens]
        else:
             return "%sty-%s" % (self.digitArray[tens],
self.digitArray[digits])

There's more duplication, but let's leave it for a while.

Let's hit twenty, thirty and eighty next. I happen to like arrays, so
we get this:

     def numberToEnglish(self, number):
         tens, digits = divmod(number, 10)
         if tens == 0:
             return self.digitArray[digits]
         elif digits == 0:
             return "%s" % tensArray[tens]
        else:
             return "%s-%s" % (self.tensArray[tens], self.digitArray[digits])

     tensArray = ["", "ten", "twenty", "thirty", "fourty", "fifty",
         "sixty", "seventy", "eighty", "ninety"]

     digitArray = ["zero", "one", "two", "three", "four",
       "five", "six", "seven", "eight", "nine"]

However, now we've definitely got some duplication between the
two arrays. If we use the digit array as a base, and go back to
applying the 'ty' in the routine, we can simply copy five of the
numbers from the digit array to the tens array. Now what we've got
is:

class ConvertNumbersToEnglish:
     def __init__(self):
         for i in range(10):
             if tensArray[i] == None:
                 tensArray[i] = digitArray[i]

     tensArray = ["", "ten", "twen", "thir", None, None,
         None, None, "eigh", None]

     digitArray = ["zero", "one", "two", "three", "four",
       "five", "six", "seven", "eight", "nine"]

     def numberToEnglish(self, number):
         tens, digits = divmod(number, 10)
         if tens == 0:
             return self.digitArray[digits]
         elif digits == 0:
             return "%sty" % tensArray[tens]
        else:
             return "%sty-%s" % (self.tensArray[tens],
self.digitArray[digits])

We've now got everything except a tens digit of one. So let's feed in
13, 16 and 18. We notice something really interesting...

     def numberToEnglish(self, number):
         tens, digits = divmod(number, 10)
         if tens == 0:
             return self.digitArray[digits]
         elif tens == 1:
             return "%steen" % self.tensArray[digits]
         elif digits == 0:
             return "%sty" % tensArray[tens]
        else:
             return "%sty-%s" % (self.tensArray[tens],
self.digitArray[digits])

Almost there. This will handle everything except 10, 11 and 12. We'll
get teen, oneteen and twoteen. So let's put in tests for those three and
we get (after reducing the if-elif to an array):

class ConvertNumbersToEnglish:
     def __init__(self):
         for i in range(10):
             if tensArray[i] == None:
                 tensArray[i] = digitArray[i]

     tensArray = ["", "ten", "twen", "thir", None, None,
         None, None, "eigh", None]

     digitArray = ["zero", "one", "two", "three", "four",
       "five", "six", "seven", "eight", "nine"]

    def numberToEnglish(self, number):
         tens, digits = divmod(number, 10)
         if tens == 0:
             return self.digitArray[digits]
         elif tens == 1:
             if digits < 3:
                  return self.teenArray[digits]
             else:
                  return "%steen" % self.tensArray[digits]
         elif digits == 0:
             return "%sty" % tensArray[tens]
        else:
             return "%sty-%s" % (self.tensArray[tens],
self.digitArray[digits])

     teenArray = ["ten", "eleven", "twelve"]

There's still some duplication here, but I don't think that
removing it will improve either clarity or modifiability.
Adding hundreds and thousands should be fairly
straightforward. So let's add hundreds. The first cut is:

    def numberToEnglish(self, number):
         tens, digits = divmod(number, 10)
         hundreds = divmod(tens, 10)
         if number == 0:
             return "zero"
         if tens == 0:
             result = self.digitArray[digits]
         elif tens == 1:
             if digits < 3:
                  result = self.teenArray[digits]
             else:
                  result = "%steen" % self.tensArray[digits]
         elif digits == 0:
             result = "%sty" % tensArray[tens]
         else:
             result = "%sty-%s" % (self.tensArray[tens],
self.digitArray[digits])
         if hundreds == 0:
             return result
         return "%s hundred and %s" % (self.digitArray[hundreds], result)

That turned out to be pretty easy. Thousands aren't going to be quite
so easy, but it's getting quite late, so I'm going to wrap it up.

John Roth

Messages 107756 - 107785 of 158671   Oldest  |  < Older  |  Newer >  |  Newest
Add to My Yahoo!      XML What's This?

Copyright © 2010 Yahoo! Inc. All rights reserved.
Privacy Policy - Terms of Service - Guidelines NEW - Help