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

DRY vs. KISS

Expand Messages
  • Shlomi Fish
    Hi all! First of all - DRY is http://en.wikipedia.org/wiki/Don%27t_repeat_yourself - the principle of software design where one assumes they should avoid
    Message 1 of 4 , Nov 12, 2009
    • 0 Attachment
      Hi all!

      First of all - DRY is http://en.wikipedia.org/wiki/Don%27t_repeat_yourself -
      the principle of software design where one assumes they should avoid duplicate
      code and repeating various stuff. Likewise - KISS is
      http://en.wikipedia.org/wiki/KISS_principle - "Keep it simple, stupid" - the
      principle of software design (or whatever) where you should try to avoid being
      too clever or doing too much.

      Lately, I've often been thinking that some places where I tried to avoid
      repeating myself (and violate the DRY principle) have caused the code to
      become too clever and as result hard to get into, at least for the uninitiated
      (and thus violate the KISS principle). For example, in
      http://web-cpan.berlios.de/modules/Test-Run/ , I created a small abstraction
      to run several methods, one after the other in a sequence, after breaking
      several methods into shorter ones. So:

      sub myfunc
      {
      # $self is the object handle, $args are the other argument
      my ($self, $args) = @_;

      $self->one($args);
      $self->two($args);
      $self->three($args);

      # Return nothing because this is a procedure
      return;
      }

      Becomes something like

      <<<<<<<<<<<
      __PACKAGE__->add_seq_func( [ "myfunc" ] );

      sub _myfunc__list
      {
      return [ "one", "two", "three", ];
      }
      >>>>>>>>>>>

      And add_seq_func will generate this method by using run-time code-generation
      (not necessarily string eval, but also possibly using closures, etc.). I gave
      the syntax in Perl out of convenience but such hackery is possibly in Ruby and
      other languages.

      Now I think the second version, while being more modular, is very non-KISS,
      and will likely confuse people.

      Today I ran into another example. In:

      http://www.shlomifish.org/open-source/projects/XML-Grammar/Fiction/

      (and XML-Grammar-Screenplay from which it was derived) I had something like
      that:

      <<<<<<<<<<<<<<<<<<<

      $self->_with_curr_line(
      sub {

      my $l = shift;

      # Use a regex on the string pointed to by $l

      ${$l} =~ m{\G([^\<\[\]\&]*)}cgms;


      >>>>>>>>>>>>>>>>>>>

      What happens here is that _with_curr_line is a method that accepts a
      subroutine reference (that can be a closure), which in turn gets passed a
      reference (which is the Perl idea of a pointer) to the current line in the
      parser, which I can use while being able to modify it. Eventually I changed
      all the code there to:

      <<<<<<<<<<<<<<<<<<
      my $l = $self->_curr_line_ref();

      # Do something with ${$l} and be happy.
      >>>>>>>>>>>>>>>>>>

      Arguably, I now have duplicate "my $l = $self->_curr_line_ref();" calls all
      over the code but the code is simpler this way. I'm not an anti-closure
      purist, and think they have many legitimate uses, but felt that the old
      version was confusing, and created another pattern in the code (and possibly
      an anti-pattern) that wasn't much better than what I had.

      So the question to you is: do you think DRY and KISS can sometimes contradict
      one another? If so, which one is more important, or that you should just use
      your reason. I should also note that I've been feeling that less expressive
      languages sometimes result in being unable to avoid duplicate code or
      undesirable "patterns" in the code (in accordance to DRY). Possibly the only
      family of languages that completely avoids duplicate code is Lisp.

      Regards,

      Shlomi Fish



      --
      -----------------------------------------------------------------
      Shlomi Fish http://www.shlomifish.org/
      Interview with Ben Collins-Sussman - http://shlom.in/sussman

      Chuck Norris read the entire English Wikipedia in 24 hours. Twice.
    • Omer Zak
      On Thu, 2009-11-12 at 19:24 +0200, Shlomi Fish wrote: [... an example was snipped ...] ... I think that more important than DRY, KISS or whatever is the
      Message 2 of 4 , Nov 12, 2009
      • 0 Attachment
        On Thu, 2009-11-12 at 19:24 +0200, Shlomi Fish wrote:
        [... an example was snipped ...]
        > So the question to you is: do you think DRY and KISS can sometimes contradict
        > one another? If so, which one is more important, or that you should just use
        > your reason. I should also note that I've been feeling that less expressive
        > languages sometimes result in being unable to avoid duplicate code or
        > undesirable "patterns" in the code (in accordance to DRY). Possibly the only
        > family of languages that completely avoids duplicate code is Lisp.

        I think that more important than DRY, KISS or whatever is the principle
        of not overloading the memory of whomever is going to read the software.

        You overload his memory if he has to look up elsewhere for definitions
        of variables, functions, closures or whatever constructs you are using.
        According to this criteria, LISP can be very bad.

        If you define another function in order to avoid code repetition at 3
        places in your project, then whomever is reading the code needs to look
        up the new function definition. If it's the only function in the
        statement - OK. But if the statement already invokes 7 functions to
        compute values, return a function pointer to be invoked, and the address
        of the variable to receive the result, then adding 8th function would
        already overflow the reader's short term memory.

        And sometimes when you need to modify all copies of an expression in
        your project, egrep can do good enough work - so no need to make them a
        function to enable code modification at one place. In a way it would be
        "virtual DRY" - the entity which you don't repeat is the egrep pattern.

        Those are vague ideas. I hope that someone would continue the
        conversation and can distill those ideas and find the hidden principle -
        it surely would be a gem!
        --- Omer
        --
        Eli Marmor's Law: netiquette forbids people from replying "I agree with
        you" to messages in mailing lists, skewing discussions in favor of the
        troublemaker type of dissenters.
        My own blog is at http://www.zak.co.il/tddpirate/

        My opinions, as expressed in this E-mail message, are mine alone.
        They do not represent the official policy of any organization with which
        I may be affiliated in any way.
        WARNING TO SPAMMERS: at http://www.zak.co.il/spamwarning.html
      • Shlomi Fish
        ... Interesting. Of course, part of the reason why we have functions is so we can encapsulate a potentially complex function in an easy to digest thing that we
        Message 3 of 4 , Nov 13, 2009
        • 0 Attachment
          On Thursday 12 Nov 2009 20:41:09 Omer Zak wrote:
          > On Thu, 2009-11-12 at 19:24 +0200, Shlomi Fish wrote:
          > [... an example was snipped ...]
          >
          > > So the question to you is: do you think DRY and KISS can sometimes
          > > contradict one another? If so, which one is more important, or that you
          > > should just use your reason. I should also note that I've been feeling
          > > that less expressive languages sometimes result in being unable to avoid
          > > duplicate code or undesirable "patterns" in the code (in accordance to
          > > DRY). Possibly the only family of languages that completely avoids
          > > duplicate code is Lisp.
          >
          > I think that more important than DRY, KISS or whatever is the principle
          > of not overloading the memory of whomever is going to read the software.
          >
          > You overload his memory if he has to look up elsewhere for definitions
          > of variables, functions, closures or whatever constructs you are using.
          > According to this criteria, LISP can be very bad.

          Interesting. Of course, part of the reason why we have functions is so we can
          encapsulate a potentially complex function in an easy to digest thing that we
          know what it does.

          Of course, this may result in a http://en.wikipedia.org/wiki/Leaky_abstraction
          which will require us to understand what the function does and how it does it
          before we can proceed, which will also overload the memory during reading the
          code.

          >
          > If you define another function in order to avoid code repetition at 3
          > places in your project, then whomever is reading the code needs to look
          > up the new function definition. If it's the only function in the
          > statement - OK. But if the statement already invokes 7 functions to
          > compute values, return a function pointer to be invoked, and the address
          > of the variable to receive the result, then adding 8th function would
          > already overflow the reader's short term memory.

          Well, in his book "Refactoring", Martin Fowler advocates very short methods of
          very few statements with simple expressions each, while extracting the more
          complex evaluations to helper methods, and many people seem to agree with him
          (including me to a large extent[Practice]). Of course, this in turn causes
          understanding the code or tracing a bug be more difficult because you have to
          delve several methods deep (which in turn causes a memory overload).

          {{{{{{
          [Practice] - while I agree with it, but often my code, including my open-
          source code does not exhibit this. It's just that I'm too anxious to write
          functional code, that I don't make sure it's properly factored. Normally, I
          only give an external API and do not support any internal APIs, including not
          class-inheriting API, so it's not that critical.
          }}}}}}

          > And sometimes when you need to modify all copies of an expression in
          > your project, egrep can do good enough work - so no need to make them a
          > function to enable code modification at one place. In a way it would be
          > "virtual DRY" - the entity which you don't repeat is the egrep pattern.

          What if someone who is not intimately familiar with the code changes one place
          and not all other places? What if you forget to change them? That's the danger
          of duplicate code.

          Some people may argue that syntactical patterns in the language are not really
          duplicate code, but Lisp purists may disagree.

          >
          > Those are vague ideas. I hope that someone would continue the
          > conversation and can distill those ideas and find the hidden principle -
          > it surely would be a gem!
          > --- Omer
          >

          Regards,

          Shlomi Fish

          --
          -----------------------------------------------------------------
          Shlomi Fish http://www.shlomifish.org/
          My Aphorisms - http://www.shlomifish.org/humour.html

          Chuck Norris read the entire English Wikipedia in 24 hours. Twice.
        • Shlomi Fish
          ... Now that I think of it, it s possible that not overloading memory is one aspect of KISS ( Keep is Simple and Stupid ). But I m not sure of that. Regards,
          Message 4 of 4 , Dec 20, 2009
          • 0 Attachment
            On Thursday 12 Nov 2009 20:41:09 Omer Zak wrote:
            > On Thu, 2009-11-12 at 19:24 +0200, Shlomi Fish wrote:
            > [... an example was snipped ...]
            >
            > > So the question to you is: do you think DRY and KISS can sometimes
            > > contradict one another? If so, which one is more important, or that you
            > > should just use your reason. I should also note that I've been feeling
            > > that less expressive languages sometimes result in being unable to avoid
            > > duplicate code or undesirable "patterns" in the code (in accordance to
            > > DRY). Possibly the only family of languages that completely avoids
            > > duplicate code is Lisp.
            >
            > I think that more important than DRY, KISS or whatever is the principle
            > of not overloading the memory of whomever is going to read the software.
            >
            > You overload his memory if he has to look up elsewhere for definitions
            > of variables, functions, closures or whatever constructs you are using.
            > According to this criteria, LISP can be very bad.
            >

            Now that I think of it, it's possible that not overloading memory is one
            aspect of KISS ("Keep is Simple and Stupid"). But I'm not sure of that.

            Regards,

            Shlomi Fish

            --
            -----------------------------------------------------------------
            Shlomi Fish http://www.shlomifish.org/
            What does "Zionism" mean? - http://shlom.in/def-zionism

            Bzr is slower than Subversion in combination with Sourceforge.
            ( By: http://dazjorz.com/ )
          Your message has been successfully submitted and would be delivered to recipients shortly.