Loading ...
Sorry, an error occurred while loading the content.

Re: [extremeperl] Refactorings?

Expand Messages
  • Rob Nagler
    ... Every refactoring can be implemented in reverse. This is an important part of design by refactoring. This is the art of refactoring imo. The goal is
    Message 1 of 14 , Jul 29, 2002
    View Source
    • 0 Attachment
      Ged Haywood writes:
      > > return undef unless defined($value);
      >
      > Notaroundhereitdoesn't! It becomes
      >
      > if(! defined($value) ) { return undef; }

      Every refactoring can be implemented in reverse. This is an important
      part of design by refactoring. This is the "art" of refactoring imo.
      The goal is eliminating redunancy in and adding clarity to the design.
      IMO, the extra braces are redundant. The negative test is less
      clear than a parenless unless. Some people like vi, others like emacs.

      Your choice of refactorings is a coding style issue. If your group
      hates unless, then don't use it. This doesn't invalidate the
      refactoring as a concept.

      > My view would be that undef would be an abnormal condition.
      > I usually like my variables to be def. If they aren't def,
      > then what's the point of creating them in the first place?

      Users sometimes don't enter anything. What's the integer value of the
      empty string? Many databases treat the empty string as NULL, which
      means you had better be consistent in your Perl for those databases
      that don't. :-(

      > Ergo, one would test for undef but expect the test to fail.

      The title of the example is "from_literal". You may or may not allow
      undef on a form field. This is a higher level application decision.
      The concept of undef is an important distinguishing factor from Java
      which does not allow undef for native types.

      > Ergo, the return statement should be on the right where it
      > doesn't get in the way when you're scanning down the left of
      > the page to try to figure out WTBHIGO.

      This again is a style issue, ex mea sententia. Some proponents of
      early exit recommend the exit be on the left and others recommend it
      on the right.

      > > This refactoring is controversial, if you aren't used to it.
      >
      > Er, run that by me again?

      If you are familiar with the refactoring, you might not consider it
      controversial. You might think: different strokes for for different
      folks. If you are unfamiliar with it, you might think: what a stupid
      idea. It's the Green Eggs and Ham thing. Try it, you'll like it, or
      at least respect its use by others.

      > > It's common to use return, last, die, etc. in Perl. Early exits limit
      > > the nesting depth.
      >
      > I'd have said early exits prevent program failures and may economize
      > on processor cycles, but there we are.

      This assumes reducing nesting depth prevents program failures. If I
      had made that leap of logic, I would have been blasted. ;-)

      > > Modifiers take this one step further by eliminating all nesting, if
      > > possible.
      >
      > If eliminating nesting makes it harder to read then give me nesting.

      I found Lisp hard to read until I programmed in it. Most people find
      Perl hard to read. Took me a while to get used to unless, but after
      seeing lots of Perl with and without it, my group and I now like it.

      > > The roots of programming are based in logic, not in cooking recipes.
      > [snip]
      > > This refactoring emulates the declarative style of Prolog.
      >
      > Argh++. Declarative is OK where it's OK. I feel it's not OK here.

      As I said, controversial.

      > > For example, this is the wrong way to use this refactoring:
      > >
      > > $x = 39, delete($z{$y}) if $is_tuesday; # WRONG USAGE
      >
      > Obviously. (But now you're being silly. :)

      Here's some code from another reviewer trying to correct what he
      thinks is an incorrect approach elsewhere in the book:

      if (/<[a-z]+[^>]*$/) { s/\n/ /; $_ .= <>};

      Looks quite similar to my example above, but maybe it's just a taste
      thing and mine is silly but this one is serious.

      Every refactoring has its limits. Its important to document where you
      think they are. Every limit has its exceptions. It's important to
      allow yourself to follow your own guidelines. In XP, just make sure
      everybody is in agreement about the limits and exceptions.

      Rob
    • chromatic
      ... I like this one, especially if you demonstrate that it s reversable. I only have one nitpick. ... if undef is intended to return a demonstrably false
      Message 2 of 14 , Jul 29, 2002
      View Source
      • 0 Attachment
        On Monday 29 July 2002 08:02, Rob Nagler wrote:

        > The following refactoring is a very simple one, but I consider it
        > useful to demonstrate how Perl statement modifiers can be used and to
        > introduce the mechanism by which a document refactorings. The format
        > is borrowed from Fowler's Refactoring book (which I highly recommend,
        > btw).

        I like this one, especially if you demonstrate that it's reversable. I only
        have one nitpick.

        > unless (defined($value)) {
        > return undef;
        > }
        >
        > becomes
        >
        > return undef unless defined($value);

        if 'undef' is intended to return a demonstrably false value, this code is a
        bit broken in list context.

        my @list = undef;
        print "True\n" if @list;

        It's very probably not germane to the example, but a book about good Perl
        development ought to mind context. I generally ask "Did you really mean
        this?" when I see it during code reviews.

        Best,
        -- c
      • Rob Nagler
        ... I hope to avoid showing the reverse of every refactoring. It maybe makes sense to show one or two explicitly. ... No, you need to check if it is undef.
        Message 3 of 14 , Jul 29, 2002
        View Source
        • 0 Attachment
          chromatic writes:
          > I like this one, especially if you demonstrate that it's reversable.

          I hope to avoid showing the reverse of every refactoring. It maybe
          makes sense to show one or two explicitly.

          > if 'undef' is intended to return a demonstrably false value, this code is a
          > bit broken in list context.
          >
          > my @list = undef;
          > print "True\n" if @list;

          No, you need to check if it is undef. However, I'm going to change
          the example to eliminate the "unless" and "undef" parts. They
          distract from the refactoring which is about statement modifiers.

          > It's very probably not germane to the example, but a book about good Perl
          > development ought to mind context. I generally ask "Did you really mean
          > this?" when I see it during code reviews.

          I think it is inefficient to write:

          return wantarray ? () : undef;

          when the routine returns a scalar. The caller should read the doc or
          code. If you are building large applications in Perl, you need to
          respect the declarations. The unit and acceptance tests will help
          protect against mistakes, but you can't give a kid Perl and say "go
          write an accounting system". Here's a better description of what I mean:

          Java was, as Gosling says in the first Java white paper, designed
          for average programmers. It's a perfectly legitimate goal to
          design a language for average programmers. (Or for that matter for
          small children, like Logo.) But it is also a legitimate, and very
          different, goal to design a language for good programmers.

          See http://www.paulgraham.com/arcll1.html and other articles by Paul
          Graham.

          I think Perl in-the-small is a fine language for just about anybody.
          Perl in-the-large is another beast entirely. You have to respect
          interfaces and have an agreed on coding style. I contend you will
          need OO. You need to build abstractions (e.g. lightweight languages)
          which map domain knowledge succinctly. The power of Perl in-the-large
          is that I can let domain experts program Perl in-the-small with
          "terms" (APIs) developed by Perl experts.

          Rob
        • chromatic
          ... That s fine. It s important to demonstrate that you don t always go in one direction. ... The bare return operator respects the calling context: sub false
          Message 4 of 14 , Jul 29, 2002
          View Source
          • 0 Attachment
            On Monday 29 July 2002 22:09, Rob Nagler wrote:

            > chromatic writes:
            > > I like this one, especially if you demonstrate that it's reversable.
            > I hope to avoid showing the reverse of every refactoring. It maybe
            > makes sense to show one or two explicitly.

            That's fine. It's important to demonstrate that you don't always go in one
            direction.

            > I think it is inefficient to write:
            >
            > return wantarray ? () : undef;
            >
            > when the routine returns a scalar. The caller should read the doc or
            > code.

            The bare return operator respects the calling context:

            sub false {
            return;
            }

            my @list = false;
            my $scalar = false;

            print "list true" if @list;
            print "scalar true" if $scalar;
            print scalar @list;

            Outside of this example, I do agree that explicit interfaces are important for
            large applications.

            > I'm going to change the example to eliminate the "unless" and "undef" parts.
            > They distract from the refactoring which is about statement modifiers.

            I think that's wise. They distracted two of us. ;)

            Regards,
            -- c
          • Ged Haywood
            Hi all, ... 73, Ged.
            Message 5 of 14 , Jul 30, 2002
            View Source
            • 0 Attachment
              Hi all,

              On Mon, 29 Jul 2002, chromatic wrote:

              > On Monday 29 July 2002 22:09, Rob Nagler wrote:
              >
              > > I'm going to change the example to eliminate the "unless" and "undef" parts.
              > > They distract from the refactoring which is about statement modifiers.
              >
              > I think that's wise. They distracted two of us. ;)

              :)

              73,
              Ged.
            • Rob Nagler
              ... Will do. ... Well, you learn something new everyday. :) Thanks! Rob
              Message 6 of 14 , Jul 30, 2002
              View Source
              • 0 Attachment
                chromatic writes:
                > That's fine. It's important to demonstrate that you don't always go in one
                > direction.

                Will do.

                > The bare return operator respects the calling context:

                Well, you learn something new everyday. :) Thanks!

                Rob
              • Stephen Nelson
                I ve got a few refactorings on my Perlmonks homenode: http://www.perlmonks.org/index.pl?node_id=2329 There are also references to other refactorings there. I d
                Message 7 of 14 , Jul 30, 2002
                View Source
                • 0 Attachment
                  I've got a few refactorings on my Perlmonks homenode:

                  http://www.perlmonks.org/index.pl?node_id=2329

                  There are also references to other refactorings there. I'd appreciate
                  any feedback.

                  Rob Nagler wrote:

                  > I'm trying to get an idea what people consider useful refactorings.
                  >
                  > The following refactoring is a very simple one, but I consider it
                  > useful to demonstrate how Perl statement modifiers can be used and to
                  > introduce the mechanism by which a document refactorings. The format
                  > is borrowed from Fowler's Refactoring book (which I highly recommend,
                  > btw).
                  >
                  > I've got a number of other refactorings in my book, but some have said
                  > they are too complicated. I'll send out a few refactorings later
                  > after I've got some feedback on the format and what your own
                  > refactorings.
                  >
                  > Thanks for the feedback.
                  >
                  > Rob
                  > ----------------------------------------------------------------
                  > TITLE: Replace Conditional with Modifier
                  >
                  > SYNOPSIS
                  >
                  > You have an if statement with a one-line then clause.
                  > Use a Perl statement modifier to keep data flow on the left.
                  >
                  > unless (defined($value)) {
                  > return undef;
                  > }
                  >
                  > becomes
                  >
                  > return undef unless defined($value);
                  >
                  >
                  > MOTIVATION
                  >
                  > This refactoring is controversial, if you aren't used to it.
                  > I find modifiers are a useful programming technique, when they are
                  > available. We use them in natural language prose where it makes
                  > sense. The preceding three sentences are completely normal in
                  > English even if they sound weird all in a row. The fact is on
                  > the left of a qualifying clause. It puts the action up front so
                  > you know what might happen, given a set of circumstances.
                  >
                  > It's common to use return, last, die, etc. in Perl. Early exits limit
                  > the nesting depth. This is a good thing. Modifiers take this one
                  > step further by eliminating all nesting, if possible. This keeps data
                  > flow on the left, which makes it easier to see the side effects, such
                  > as early exit.
                  >
                  > The roots of programming are based in logic, not in cooking recipes.
                  > It seems we often forget this. In mathematical theorems, statements
                  > are often followed by qualifying clauses such as such that and iff.
                  > Most functional languages put the conditional on the left, which is
                  > probably a historical artifact of Lisp, a prefix notation language.
                  > In Prolog, rules are expressed as a fact followed by a condition.
                  > This refactoring emulates the declarative style of Prolog.
                  >
                  > You shouldn't use this refactoring to slam as many separate statements
                  > into a single line as possible. For example, this is the wrong way to
                  > use this refactoring:
                  >
                  > $x = 39, delete($z{$y}) if $is_tuesday; # WRONG USAGE
                  >
                  > This line defeats the motivation of keeping the data flow on the left.
                  > Too much is happening in one line, and the data operations are
                  > complete unrelated. This example obfuscates the data flow instead of
                  > improving it.
                  >
                  > You can convert any if statement into a
                  > do-if, e.g.
                  >
                  > do { # WRONG USAGE
                  > $x = 39;
                  > delete($z{$y});
                  > } if $is_tuesday;
                  >
                  > This doesn't save nesting. There's more code than a simple if
                  > statement. We aren't trying to put all conditionals last. That's as
                  > unnatural as ending all conditional English statements with modifying
                  > clauses.
                  >
                  > MECHANICS
                  >
                  > 1. If the conditional part declares a temporary
                  > my variable, move the declaration part out.
                  >
                  > 2. Remove the braces from the statement and switch the conditional
                  > order. Do not change the conditional logic.
                  >
                  > EXAMPLE
                  >
                  > Here's a method with two one-line if statements:
                  >
                  > sub from_literal {
                  > my(undef, $value) = @_;
                  > unless (defined($value)) {
                  > return undef;
                  > }
                  > $value =~ s/^\s+|\s+$//g;
                  > unless (defined($value)) {
                  > return undef;
                  > }
                  > return $value;
                  > }
                  >
                  > We transform the two conditionals into modified statements:
                  >
                  > sub from_literal {
                  > my(undef, $value) = @_;
                  > return undef unless defined($value);
                  > $value =~ s/^\s+|\s+$//g;
                  > return undef unless length($value);
                  > return $value;
                  > }
                  >
                  >
                  >
                  > Yahoo! Groups Sponsor
                  > ADVERTISEMENT
                  > <http://rd.yahoo.com/M=228862.2128520.3581629.1829184/D=egroupweb/S=1705007181:HM/A=1155069/R=0/*http://adfarm.mediaplex.com/ad/ck/990-1736-1039-302>
                  >
                  >
                  >
                  > To unsubscribe from this group, send an email to:
                  > extremeperl-unsubscribe@yahoogroups.com
                  >
                  >
                  >
                  > Your use of Yahoo! Groups is subject to the Yahoo! Terms of Service
                  > <http://docs.yahoo.com/info/terms/> .
                  > .




                  [Non-text portions of this message have been removed]
                • Adrian Howard
                  ... [snip] Okay... here s one. (I don t have my Fowler to hand, so please excuse me if I wander off the standard format :-) ... TITLE: HashBecomesObject
                  Message 8 of 14 , Jul 30, 2002
                  View Source
                  • 0 Attachment
                    On Monday, July 29, 2002, at 04:02 pm, Rob Nagler wrote:

                    > I'm trying to get an idea what people consider useful refactorings.
                    [snip]

                    Okay... here's one.

                    (I don't have my Fowler to hand, so please excuse me if I wander off
                    the "standard" format :-)

                    ---

                    TITLE: HashBecomesObject

                    SYNOPSIS:

                    Turn a hash that represents a separate entity into an blessed object
                    that reflects it's purpose.

                    $Tests->{$class}->{$method}->{num_tests} = 4;
                    $Tests->{$class}->{$method}->{type}->{setup} = 1;
                    $Tests->{$class}->{$method}->{type}->{teardown} = 1;

                    becomes:

                    my $info = bless {}, 'Test::MethodInfo';
                    $info->{num_tests} = 4;
                    $info->{type}->{setup} = 1;
                    $info->{type}->{teardown}=1;
                    $Tests->{$class}->{$method} = $info;

                    MOTIVATION:

                    Perl lets you quickly create complex data-structures out of
                    hashes-of-hashes, often acting as simple collections.

                    These can quickly become hard to comprehend, use and maintain.

                    If a part of a hash-of-hashes (or a hash all by it's lonesome) makes
                    sense as a separate entity, turn it into an blessed hash.

                    This acts as a precursor to things like ExtractClass and allows
                    HashAccessBecomesMethodCall for your new object (I'll leave
                    HashAccessBecomesMethodCall, and the obvious ObjectBecomesHash as
                    exercises for the reader :-)

                    ----

                    I'm tempted to stick up a perl refactoring wiki (or is there one
                    already hiding in a corner somewhere?)... Anybody second the
                    suggestion?

                    Adrian
                    --
                    Adrian Howard <adrianh@...>
                    phone: 01929 550720 fax: 0870 131 3033 www.quietstars.com
                  • Stephen Nelson
                    Seconded.... I ve been planning on doing that for way too long. ... [Non-text portions of this message have been removed]
                    Message 9 of 14 , Jul 30, 2002
                    View Source
                    • 0 Attachment
                      Seconded.... I've been planning on doing that for way too long.

                      Adrian Howard wrote:

                      > On Monday, July 29, 2002, at 04:02 pm, Rob Nagler wrote:
                      >
                      > > I'm trying to get an idea what people consider useful refactorings.
                      > [snip]
                      >
                      > Okay... here's one.
                      >
                      > (I don't have my Fowler to hand, so please excuse me if I wander off
                      > the "standard" format :-)
                      >
                      > ---
                      >
                      > TITLE: HashBecomesObject
                      >
                      > SYNOPSIS:
                      >
                      > Turn a hash that represents a separate entity into an blessed object
                      > that reflects it's purpose.
                      >
                      > $Tests->{$class}->{$method}->{num_tests} = 4;
                      > $Tests->{$class}->{$method}->{type}->{setup} = 1;
                      > $Tests->{$class}->{$method}->{type}->{teardown} = 1;
                      >
                      > becomes:
                      >
                      > my $info = bless {}, 'Test::MethodInfo';
                      > $info->{num_tests} = 4;
                      > $info->{type}->{setup} = 1;
                      > $info->{type}->{teardown}=1;
                      > $Tests->{$class}->{$method} = $info;
                      >
                      > MOTIVATION:
                      >
                      > Perl lets you quickly create complex data-structures out of
                      > hashes-of-hashes, often acting as simple collections.
                      >
                      > These can quickly become hard to comprehend, use and maintain.
                      >
                      > If a part of a hash-of-hashes (or a hash all by it's lonesome) makes
                      > sense as a separate entity, turn it into an blessed hash.
                      >
                      > This acts as a precursor to things like ExtractClass and allows
                      > HashAccessBecomesMethodCall for your new object (I'll leave
                      > HashAccessBecomesMethodCall, and the obvious ObjectBecomesHash as
                      > exercises for the reader :-)
                      >
                      > ----
                      >
                      > I'm tempted to stick up a perl refactoring wiki (or is there one
                      > already hiding in a corner somewhere?)... Anybody second the
                      > suggestion?
                      >
                      > Adrian
                      > --
                      > Adrian Howard <adrianh@...>
                      > phone: 01929 550720 fax: 0870 131 3033 www.quietstars.com
                      >
                      >
                      > Yahoo! Groups Sponsor
                      > ADVERTISEMENT
                      > <http://rd.yahoo.com/M=228862.2128520.3581629.1829184/D=egroupweb/S=1705007181:HM/A=1155070/R=0/*http://adfarm.mediaplex.com/ad/ck/990-1736-1039-302>
                      >
                      >
                      >
                      > To unsubscribe from this group, send an email to:
                      > extremeperl-unsubscribe@yahoogroups.com
                      >
                      >
                      >
                      > Your use of Yahoo! Groups is subject to the Yahoo! Terms of Service
                      > <http://docs.yahoo.com/info/terms/> .
                      > .




                      [Non-text portions of this message have been removed]
                    Your message has been successfully submitted and would be delivered to recipients shortly.