Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Refactoring Redux...

by hsmyers (Canon)
on Dec 16, 2002 at 17:56 UTC ( [id://220285]=perlmeditation: print w/replies, xml ) Need Help??

or, how to rewrite your code all over again. And again. Like a lot of words, 'refactoring' gets tossed around quite a bit these days. Mostly without any particular regard to whether or not it is understood. At least I know that I'm probably guilty of this particular assumption. In the environment that I currently inhabit, I'm typically the most senior programmer and I know from the glazed-over expressions I get from time to time that I'm not always as 'clear' as I would like.

I thought what I would do is take a fairly short piece of code and walk it through the normal process that I use when coding---except this time, take a series of 'snapshots' of it along the way. Creating a kind of record over time of how the code evolved. The code in question has already been posted, (see Perl, Chess, Lies, Dam Lies and Statistics) so think of this as a map of how I got there.

Typically I like to start (no claim to great wisdom here...) with something that works! In fact, I'll take just about any piece of code that fits this loose description. In this case, what I did was a nearly complete copy of a working SVG page. The first pass code looks like this:

my $y = 0; my @list; print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n +"; print "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"; print " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10. +dtd\" >\n"; print "<svg height=\"200\" width=\"200\">\n"; print " <line x1=\"0\" y1=\"0\" x2=\"80\" y2=\"0\"/>\n"; print " <polyline\n"; print " points=\""; foreach (@scores) { if ($_) { push(@list,$y++); push(@list,$_ * -1.0); } } print join(",",@list); print "\"\n"; print " style=\"stroke: black; width: 1px; fill: none;\"/>\n"; print "</svg>\n";
Mostly print statements. Nothing too fancy, just enough to serve as a kind of proof of concept. It also provides a 'minimal' metric---each successive iteration should work at least this well, otherwise the changes are heading in the wrong direction!

It shouldn't take much staring at this code to provoke at least one or two sub routines! And if that doesn't provide the inspiration, reading the fine manual on SVG should. Whatever the cause, the next thing that I wrote was a sub called hline---itself a combination of the desire to remove the print statement with the line command and the knowledge that I would need more horizontal lines! So now the code looks like:

my $y = 0; my @list; print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n +"; print "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"; print " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10. +dtd\" >\n"; print "<svg height=\"200\" width=\"200\">\n"; print " ",hline(0,80,0); print " <line x1=\"0\" y1=\"0\" x2=\"80\" y2=\"0\"/>\n"; print " <polyline\n"; print " points=\""; foreach (@scores) { if ($_) { push(@list,$y++); push(@list,$_ * -1.0); } } print join(",",@list); print "\"\n"; print " style=\"stroke: black; width: 1px; fill: none;\"/>\n"; print "</svg>\n"; sub hline { my $x1 = shift; my $x2 = shift; my $y1 = shift; my $y2 = $y1; print " <line x1=\"$x1\" y1=\"$y1\" x2=\"$x2\" y2=\"$y2\"/>\n"; }
And using hline as a template, we create vline and before you know we have pretty much filled in around the original simple line graph.
my $y = 0; my @list; print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n +"; print "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"; print " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10. +dtd\" >\n"; print "<svg height=\"200\" width=\"200\">\n"; foreach (-15..15) { print hline(0,80,$_); } foreach (0..80) { print vline(-15,15,$_); } print " <polyline\n"; print " points=\""; foreach (@scores) { if ($_) { push(@list,$y++); push(@list,$_ * -1.0); } } print join(",",@list); print "\"\n"; print " style=\"stroke: black; width: 1px; fill: none;\"/>\n"; print "</svg>\n"; sub hline { my $x1 = shift; my $x2 = shift; my $y1 = shift; my $y2 = $y1; return " <line x1=\"$x1\" y1=\"$y1\" x2=\"$x2\" y2=\"$y2\"/>\n"; } sub vline { my $y1 = shift; my $y2 = shift; my $x1 = shift; my $x2 = $x1; return " <line x1=\"$x1\" y1=\"$y1\" x2=\"$x2\" y2=\"$y2\"/>\n"; }

After a little review of SVG, hline and vline both undergo some changes, first to add functionality (I wanted to change color), second to simplify the code (single 'my' statement) and third change from 'line' to path (both an improvement and a simplification, all SVG line commands wind up as path commands anyway, why not go direct). Still nothing tricky, although hline was extended in a way that did not break my previous usage---new parameter added to the end of the list keeps the old approach working.

my $y = 0; my @list; print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n +"; print "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"; print " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10. +dtd\" >\n"; print "<svg height=\"400\" width=\"400\" viewbox=\"0,0,400,400\">\n"; print "<g transform=\"translate(0,15) scale(1,-1)\">\n"; print "<g transform=\"scale(4)\">\n"; foreach (-15..15) { print hline(0,80,$_); } foreach (0..80) { print vline(-15,15,$_); } print hline(0,80,0,'red'); print " <polyline\n"; print " points=\""; foreach (@scores) { if ($_) { push(@list,$y++); push(@list,$_); } } print join(",",@list); print "\"\n"; print " style=\"stroke: black; width: 1px; fill: none;\"/>\n"; print "</g>\n"; print "</g>\n"; print "</svg>\n"; sub hline { my ($x1,$x2,$y1,$color) = @_; if ($color) { return " <path d=\"M $x1,$y1 H $x2\" style=\"stroke: $color;\ +"/>\n"; } else { return " <path d=\"M $x1,$y1 H $x2\"/>\n"; } } sub vline { my ($y1,$y2,$x1,$color) = @_; if ($color) { return " <path d=\"M $x1,$y1 V $y2\" style=\"stroke: $color;\ +"/>\n"; } else { return " <path d=\"M $x1,$y1 V $y2\"/>\n"; } }

So what next? Well, there are still too many 'print' statements in the main line, and we have yet to graph the other two 'lines' of data. So with that as a target, we refactor into this:

my $y = 0; my @list; print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n +"; print "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"; print " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10. +dtd\" >\n"; print "<svg height=\"450\" width=\"450\" viewbox=\"0,0,450,450\">\n"; print "<g transform=\"translate(10,85) scale(1,-1)\">\n"; print "<g transform=\"scale(5)\">\n"; foreach (-15..15) { print hline(0,80,$_); } foreach (0..80) { print vline(-15,15,$_); } print " <path d=\"M -1 0 H 81\" style=\"stroke: red; stroke-opacity: +.25; stroke-width: .1\"/>\n"; polyline('black',0.1,@scores); polyline('green',0.1,@bestblack); polyline('red',0.1,@bestwhite); print "</g>\n"; print "</g>\n"; print "</svg>\n"; sub hline { my ($x1,$x2,$y1,$color) = @_; if ($color) { return " <path d=\"M $x1,$y1 H $x2\" style=\"stroke: $color;\ +"/>\n"; } else { return " <path d=\"M $x1,$y1 H $x2\"/>\n"; } } sub vline { my ($y1,$y2,$x1,$color) = @_; if ($color) { return " <path d=\"M $x1,$y1 V $y2\" style=\"stroke: $color;\ +"/>\n"; } else { return " <path d=\"M $x1,$y1 V $y2\"/>\n"; } } sub polyline { my $color = shift; my $width = shift; my @values = @_; my @list; my $y = 0; print " <polyline\n"; print " points=\""; foreach (@values) { if ($_) { push(@list,$y); push(@list,$_); } $y++; } print join(",",@list); print "\"\n"; print " style=\"stroke: $color; stroke-width: $width; fill: non +e;\"/>\n"; }
That didn't do much for the 'print' population, but it did add some useful functionality and avoided repeating the original 'polyline' with the loop and embedded 'join' in the middle. One of the best reasons to refactor is code that repeats essentially the same thing. Generalize this kind of code as a sub as soon as you can.

So at this point I've accumulated 3 subs and I've still got a lot of print statements. All things considered, there will always be 'some' print statements, but I should at least be able to tidy up the main line a bit more. Regards this last, I can easily predict that 'openSVG' and 'closeSVG' are both pretty likely candidates for the sub list---but before I coded the obvious, I spent some time thinking about what I'd already done and what I might want or need later. Without too much deep thought, anyone familiar with tag-based languages should be able to see a pattern here. Each SVG command typically consists of a key-word ('path', 'line' etc.) and some attributes ( 'style', 'd' etc.) Maybe what I needed is a little bit of 'meta' code. A sort of half step back and one step to the side kind of code. More to the point, code that I can use to re-write the other SVG calls. Actually to tell the truth, I didn't make this connection until I was about half way through writing a variety of 'open' subs---the process itself was the same kind of repetition as I was trying to eliminate! Luckily it didn't take too much typing before I was struck by the less than subtle pattern involved. At any rate, enter a new sub entitled 'openTAG' paired with 'closeTAG'. Armed with this, we can pretty much rewrite into the final state:

openSVG( 450, 450 ); openG( transform => 'translate(10,85) scale(1,-1)' ); openG( transform => 'scale(5)' ); openG( style => "font-size: .75pt", transform => "scale(1,-1)"); my $n = 1; foreach ( 0 .. 79 ) { openTAG( 'text', x => $_ + .25, y => 16, style => "font-weight: bold;", ); print ">",$_ % 10; closeTAG('text'); if ($_ and ($_ % 10 == 0)) { openTAG( 'text', x => $_ + .25, y => 17, style => "font-weight: bold;", ); print ">",$n++; closeTAG('text'); } } closeG(); foreach ( -15 .. 15 ) { hline( 0, 80, $_ ); } foreach ( 0 .. 80 ) { vline( -15, 15, $_ ); } path( d => 'M -1 0 H 81', style => 'stroke: red; stroke-opacity: .25; stroke-width: .1' ); graphline( 'black', 0.1, @scores ); graphline( 'green', 0.1, @bestblack ); graphline( 'red', 0.1, @bestwhite ); closeG(); closeG(); closeSVG(); sub path { openTAG( 'path', @_ ); closeTAG(); } sub openTAG { my $tag = shift; my %attributes = @_; print "<$tag"; foreach ( keys %attributes ) { print " $_=\"$attributes{$_}\""; } } sub closeTAG { my $s = shift; if ($s) { print "</$s>\n"; } else { print "/>\n"; } } sub openG { openTAG( 'g', @_ ); print ">\n"; } sub closeG { closeTAG('g'); } sub openSVG { my $height = shift; my $width = shift; print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" +?>\n"; print "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"; print " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dt +d\">\n"; print "<svg height=\"$height\" width=\"$width\" viewbox=\"0,0,$width,$height +\">\n"; } sub closeSVG { closeTAG('svg'); } sub hline { my ( $x1, $x2, $y1, $color ) = @_; if ($color) { path( d => "M $x1,$y1 H $x2", style => "stroke: $color;" ); } else { path( d => "M $x1,$y1 H $x2" ); } } sub vline { my ( $y1, $y2, $x1, $color ) = @_; if ($color) { path( d => "M $x1,$y1 V $y2", style => "stroke: $color;" ); } else { path( d => "M $x1,$y1 V $y2" ); } } sub graphline { my $color = shift; my $width = shift; my @values = @_; my @list; my $y = 0; foreach (@values) { if ($_) { push ( @list, $y ); push ( @list, $_ ); } $y++; } openTAG( 'polyline', points => join ( ',', @list ), style => "stroke: $color; stroke-width: $width; fill: none;", ); closeTAG(); }

This is where the code is today (it might even be evolved a bit further than the previous nodes listing), which is not to say that this is the end of the process. It's not! It is just the current at rest state. Further refactoring fuel is provided by the shortcomings of the current version...whatever that version may be! At a guess, I'll probably remove the code surrounding the drawing of the axis and the graph paper into it's own sub at some point. Clearly 'openSVG' could stand a bit more parameterize and so on. This is not a process that comes neatly to a halt. In fact if there is a problem with refactoring, it is that it is something that could go on pretty much forever---certainly longer than any given deadline. Part of managing either yourself or other programmers is in knowing when to bring this to a halt.

So this is my definition of 'Refactoring', or at least one of them. Is this all I mean? No, it's a pretty big subject and it certainly deserves a lot more than what I've given it here! Still this is at least the basis for what I mean when I talk about 'Refactoring'---I'm still convinced the eye glazing thing has to do with all of the damn doughnuts lying around...

Bibliography

@book{fowler:2,
  author = {Martin Fowler and Kent Beck and John Brant and William Opdyke and Don Roberts},
  title = {Refactoring: Improving the Design of Existing Code},
  publisher = {Addison-Wesley},
  address = {Boston, MA},
  edition = {First},
  year = {2000},
  isbn = {ISBN 0201485672},
}

@book{eisenberg:1,
  author = {J. David Eisenberg},
  title = {SVG Essentials},
  publisher = {O'Reilly},
  address = {Sebastopol, CA},
  edition = {First},
  year = {2002},
  isbn = {ISBN 0596002238},
}

--hsm

"Never try to teach a pig to sing...it wastes your time and it annoys the pig."

Replies are listed 'Best First'.
Re: Refactoring Redux...
by mojotoad (Monsignor) on Dec 16, 2002 at 20:40 UTC
    Perhaps I'm being pedantic, but you seem to also be adding functionality along with your 'refactoring' -- the end result has different output from the original. My understanding of traditional refactoring is that the resulting code performs the identical function of the original.

    So you have two knobs here: the refactoring knob and the 'do more stuff with the increased functionality, modularity, and clarity' knob. By turning both at the same time you risk introducing unknown errors that might slip by your test suite (you have a test suite, right? :)

    As I said, I'm probably being overly pedantic. It's always interesting to see snapshots of code evolution, but in this case the code is evolving over at least two directions.

    Matt

      That's not overly pedantic. I thought the same thing, but didn't say anything as I'm grumpy today.

      Refactoring is much like simplifying an algebraic (or chemical) equation: at each stage, it must be equivalent. Adding features changes that, and it's a little tricky. It's much harder to reverse a refactoring (and every refactoring is reversable!) if you have added a new feature in between.

      Yet another reason to do this sort of thing in public---if your notion is fuzzy, some kind soul will come along and sharpen it for you! I just took another look in Fowler and you are correct. So what do we call refactoring with modification (improvements?)...

      --hsm

      "Never try to teach a pig to sing...it wastes your time and it annoys the pig."
        Code Sculpting? :)

        I don't know what to call it. To be honest, though, it's the approach I usually end up taking on my first pass at a coding problem. As I code I gain a better understanding of the problem I'm solving -- this in turn affects how I partition my code as my solution becomes more robust. It's a feedback cycle, and one that causes many software architects to quake in their boots.

        I don't advocate the method for a large-scale design project.

        Matt

        So what do we call refactoring with modification (improvements?)...

        The wrong way to do it.

        If you read about refactoring, especially Fowler's book, it specifically admonishes you to only refactor and not extend your code while refactoring. As someone else pointed out you are creating a lot more possibility for broken code.

        You refactor, then you extend, then you refactor again -- etc.

Re: Refactoring Redux...
by princepawn (Parson) on Dec 16, 2002 at 18:35 UTC
    I haven't read this post closely, but, I kept noticing the escaping of double-quotes throughout each stage of transformation :
    print "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n";
    I just recently started paying attention to qq and think I would clean this up as so:
    print qq(<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"\n);

    Carter's compass: I know I'm on the right track when by deleting something, I'm adding functionality

      Your are probably right---too many years of doing everything with double quotes I guess (plus a macro that does most of this for me<g>)...

      --hsm

      "Never try to teach a pig to sing...it wastes your time and it annoys the pig."
        Here is the example:
        my $x = 'hi there'; print qq(Ok now if you would only say "$x", I might acknowledge you \n +);

        Carter's compass: I know I'm on the right track when by deleting something, I'm adding functionality

Re: Refactoring Redux...
by talexb (Chancellor) on Dec 17, 2002 at 17:30 UTC

    Starting with your code:

    my $y = 0; my @list; print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n +"; print "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"; print " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10. +dtd\" >\n"; print "<svg height=\"200\" width=\"200\">\n"; print " <line x1=\"0\" y1=\"0\" x2=\"80\" y2=\"0\"/>\n"; print " <polyline\n"; print " points=\""; foreach (@scores) { if ($_) { push(@list,$y++); push(@list,$_ * -1.0); } } print join(",",@list); print "\"\n"; print " style=\"stroke: black; width: 1px; fill: none;\"/>\n"; print "</svg>\n";

    My first inclination would be to clean up some of the escaped double quotes with heredocs:

    my $y = 0; my @list; print <<PAGE_HEADER; <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> PAGEHEADER print <<SVG_HEADER; <svg height="200" width="200"> <line x1="0" y1="0" x2="80" y2="0" /> SVG_HEADER print " <polyline\n"; print " points=\""; foreach (@scores) { if ($_) { push(@list,$y++); push(@list,$_ * -1.0); } } print join(",",@list); print "\"\n"; print " style=\"stroke: black; width: 1px; fill: none;\"/>\n"; print <<SVG_FOOTER; </svg> SVG_FOOTER

    Next I would move the variable declarations down to where they are used -- otherwise it looks too much like C code. I put all of the print statements together since they are all working to priduce this one complicated line. I also explicitly test for non-zero-ness.

    print <<PAGE_HEADER; <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> PAGEHEADER print <<SVG_HEADER; <svg height="200" width="200"> <line x1="0" y1="0" x2="80" y2="0" /> SVG_HEADER my $y = 0; my @list; foreach (@scores) { if ($_ != 0) { push(@list,$y++); push(@list,$_ * -1.0); } } print " <polyline\n"; print " points=\""; print join(",",@list); print "\"\n"; print " style=\"stroke: black; width: 1px; fill: none;\"/>\n"; print <<SVG_FOOTER; </svg> SVG_FOOTER

    Then I clean up the polyline piece and use another heredoc:

    print <<PAGE_HEADER; <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> PAGEHEADER print <<SVG_HEADER; <svg height="200" width="200"> <line x1="0" y1="0" x2="80" y2="0" /> SVG_HEADER my $y = 0; my @list; foreach (@scores) { if ($_ != 0) { push(@list,$y++); push(@list,$_ * -1.0); } } my $list = join(",",@list); print <<SVG_BODY; <polyline points="$list" style="stroke: black; width: 1px; fill: none;"/> SVG_BODY print <<SVG_FOOTER; </svg> SVG_FOOTER

    Now that I can see clearly, I can collapse the last two heredocs into one.

    print <<PAGE_HEADER; <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> PAGEHEADER print <<SVG_HEADER; <svg height="200" width="200"> <line x1="0" y1="0" x2="80" y2="0" /> SVG_HEADER my $y = 0; my @list; foreach (@scores) { if ($_ != 0) { push(@list,$y++); push(@list,$_ * -1.0); } } my $list = join(",",@list); print <<SVG_BODY; <polyline points="$list" style="stroke: black; width: 1px; fill: none;"/> </svg> SVG_BODY

    That's it .. I haven't added any subroutines (perhaps more code would have suggested this would have been a good route to take). Now you can see what's going on without having to fight your way through a maze of escaped double quotes.

    --t. alex
    but my friends call me T.

    Update: Jeepers, and I forgot to collapse the two push statements into one .. well, that's left as an exercise for the reader. :)

      Unquoted heredoc terminators in the << are not nice. And you can add another step:
      my $y = 0; my @list; foreach (@scores) { if ($_ != 0) { push(@list, $y++, @list, $_ * -1.0); } } my $list = join(",",@list); print << "SVG"; <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg height="200" width="200"> <line x1="0" y1="0" x2="80" y2="0"/> <polyline points="$list" style="stroke: black; width: 1px; fill: non +e;"/> </svg> SVG
      And now we're moving in the right direction - separate the application logic from the output logic. Let's go another step towards it:
      my $y = 0; my @list; foreach (@scores) { if ($_ != 0) { push(@list, $y++, @list, $_ * -1.0); } } print << "SVG"; <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg height="200" width="200"> <line x1="0" y1="0" x2="80" y2="0"/> <polyline points="@{[ join(",", @list) ]}" style="stroke: black; width: 1px; fill: none;"/> </svg> SVG
      Finally we wrap up by collapsing the application logic:
      my @list = map { $scores[$_] != 0 ? ($_, $scores[$_] * -1.0) : () } 0 .. $#scores;

      No extra temporary variables, no scattered output, application logic minimized. The next step, assuming this is part of a larger app, would be Template Toolkit.

      Actually, thinking about it, it's debatable whether the != 0 distinction is part of the application logic or part of the display logic. One might just as well do

      my @l_list = map [ $_, $scores[$_] * -1.0 ], 0 .. $#scores; print << "SVG"; ... @{[ join ",", map @$_, grep $_->[0] != 0, @l_list; ]} ...

      Which leads me to question my term "application logic" - one might just as well consider the pairing of data points and coordinates display logic and shift it all into the template. That depends on the specific situation at hand.

      At any rate, this is a very important distinction to make, and to make consciously. I see failure to do so all the time even though it's just as important everywhere else as in web related programming. Maintainability and clarity is best achieved if you do exactly one cleanly defined thing at a time in every piece of your code. Be careful not to mix up activities. Of course the entire concept hinges on the idea of clean data structure design and in a way, that means clean interfaces between parts of your code. All of these matters are interrelated, and mastering them is what makes one a great software engineer.

      Makeshifts last the longest.

Re: Refactoring Redux...
by Anonymous Monk on Dec 16, 2002 at 22:53 UTC

    I wouldn't employ you.

    You took 16 lines of somewhat ugly but reasonably efficient code and refactored it into a hundred lines of grossly inefficent, badly structured code.

    redux is short for reduce, simplify, clarify?

    Who frontpages stuff like this?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://220285]
Approved by Mr. Muskrat
Front-paged by diotalevi
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2024-04-19 11:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found