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

Catch 22: Unit Testing vs. Refactoring

Expand Messages
  • Alistair A. Israel
    Hello, list. I m a software developer from the Philippines, currently managing a medium-sized group of developers working on enterprise applications in Java.
    Message 1 of 9 , May 31, 2004
      Hello, list.

      I'm a software developer from the Philippines, currently managing a
      medium-sized group of developers working on enterprise applications in
      Java. We have a fair amount of legacy production code that it would be
      impractical to start from scratch in "the XP way".

      So, while I'm not about to introduce 'canonical' XP into our
      organization (the subject of another post soon to come), I am keen on
      introducing certain Agile practices - of course, the primary ones
      (ones that we feel will yield the most visible returns with the
      smallest changes) we're looking at are Unit Testing/TDD and methodical
      Refactoring.

      The thing is, here's a rule I'm sure most of us would be familiar
      with: "Any Refactoring must pass all Unit Tests before being committed."

      This presumes an existing set of unit tests to check the code against.
      However, since unit testing is new to this organization, we first have
      "Start creating Unit Tests."

      Now here's the catch 22: some legacy code was written in such a way as
      to preclude or hinder the creation or running of 'proper' Unit Tests.
      To use a concrete example, one class may have a static method (which
      should be trivial to test). But, that class also has a static
      initializer which basically loads a framework and initializes it with
      properties that are set in a separate installation program.

      (Obviously, several design issues there - but that's the point.)

      So now what do we do? To create a 'proper' Unit Test (one that
      executes quickly with minimal external fixtures), we first need to
      refactor the code.

      But do NOT allow ourselves to do any refactoring without unit tests
      (for our own confidence and sanity).

      Has anybody had any similar experience to share? Can anybody provide
      wisdom on the matter?

      Thanks in advance,

      - A. Israel
    • Ron Jeffries
      ... If the problem is as you describe, no progress is possible: We need to refactor to add our first test; but we cannot refactor without tests; therefore we
      Message 2 of 9 , May 31, 2004
        On Monday, May 31, 2004, at 7:03:18 AM, Alistair A. Israel wrote:

        > So now what do we do? To create a 'proper' Unit Test (one that
        > executes quickly with minimal external fixtures), we first need to
        > refactor the code.

        > But do NOT allow ourselves to do any refactoring without unit tests
        > (for our own confidence and sanity).

        > Has anybody had any similar experience to share? Can anybody provide
        > wisdom on the matter?

        If the problem is as you describe, no progress is possible:

        We need to refactor to add our first test; but we cannot refactor without
        tests; therefore we cannot refactor.

        Therefore we have to change the problem. Fortunately, no real problem is
        quite so stringent, so that:

        1. We can add tests that are too granular but still effective, e.g.
        acceptance-style tests;

        2. We can refactor with an IDE that includes refactoring facilities that we
        trust;

        3. We can refactor very very carefully.

        4. ...

        Ron Jeffries
        www.XProgramming.com
        Do, or do not. There is no try. --Yoda
      • Michael Feathers
        Hello Alistair, Monday, May 31, 2004, 7:03:18 AM, you wrote: AAI Hello, list. AAI I m a software developer from the Philippines, currently managing a AAI
        Message 3 of 9 , May 31, 2004
          Hello Alistair,

          Monday, May 31, 2004, 7:03:18 AM, you wrote:

          AAI> Hello, list.

          AAI> I'm a software developer from the Philippines, currently managing a
          AAI> medium-sized group of developers working on enterprise applications in
          AAI> Java. We have a fair amount of legacy production code that it would be
          AAI> impractical to start from scratch in "the XP way".

          AAI> So, while I'm not about to introduce 'canonical' XP into our
          AAI> organization (the subject of another post soon to come), I am keen on
          AAI> introducing certain Agile practices - of course, the primary ones
          AAI> (ones that we feel will yield the most visible returns with the
          AAI> smallest changes) we're looking at are Unit Testing/TDD and methodical
          AAI> Refactoring.

          AAI> The thing is, here's a rule I'm sure most of us would be familiar
          AAI> with: "Any Refactoring must pass all Unit Tests before being committed."

          AAI> This presumes an existing set of unit tests to check the code against.
          AAI> However, since unit testing is new to this organization, we first have
          AAI> "Start creating Unit Tests."

          AAI> Now here's the catch 22: some legacy code was written in such a way as
          AAI> to preclude or hinder the creation or running of 'proper' Unit Tests.
          AAI> To use a concrete example, one class may have a static method (which
          AAI> should be trivial to test). But, that class also has a static
          AAI> initializer which basically loads a framework and initializes it with
          AAI> properties that are set in a separate installation program.

          AAI> (Obviously, several design issues there - but that's the point.)

          AAI> So now what do we do? To create a 'proper' Unit Test (one that
          AAI> executes quickly with minimal external fixtures), we first need to
          AAI> refactor the code.

          AAI> But do NOT allow ourselves to do any refactoring without unit tests
          AAI> (for our own confidence and sanity).

          AAI> Has anybody had any similar experience to share? Can anybody provide
          AAI> wisdom on the matter?

          First try testing at a higher level, if you can't and you need to break
          dependencies to test, you can but you just have to be very conservative
          about it. Refactoring without tests is risky business. You have to
          suspend your sense of aesthetics a bit. Some of the refactorings you
          do to get tests in place may make your code uglier. That's okay. Get
          it under test and then make it cleaner.

          I've just finished writing a book about this called Working
          Effectively with Legacy Code. It should be out in October. It has a
          catalog of twenty-three dependency breaking techniques (refactorings)
          that you can do without tests to get tests in place. They are not
          completely risk-free but the steps are written with advice that you
          can use to minimize the risk involved.

          I can pass along more advice, but a lot of it depends on whether you
          have a refactoring tool or not? Do you?

          I have this older paper which gives an intro to this topic also:
          http://www.objectmentor.com/resources/articles/WorkingEffectivelyWithLegacyCode.pdf

          Michael Feathers
          www.objectmentor.com
        • Phlip
          ... Introduce Frequent Releases, sitting together, and light pair programming first. Retrofitting tests will cause a lapse in productivity, against the promise
          Message 4 of 9 , May 31, 2004
            > AAI> So, while I'm not about to introduce
            > AAI> 'canonical' XP into our
            > AAI> organization (the subject of another post soon
            > AAI> to come), I am keen on
            > AAI> introducing certain Agile practices - of
            > AAI> course, the primary ones
            > AAI> (ones that we feel will yield the most visible
            > AAI> returns with the
            > AAI> smallest changes) we're looking at are Unit
            > AAI> Testing/TDD and methodical
            > AAI> Refactoring.

            Introduce Frequent Releases, sitting together, and
            light pair programming first.

            Retrofitting tests will cause a lapse in productivity,
            against the promise of a lowered bug rate, amortized
            far out in the future. But those support practices
            lower the bug rate immediately, and provide a good
            support for TDD as it starts.


            =====
            Phlip
            http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces




            __________________________________
            Do you Yahoo!?
            Friends. Fun. Try the all-new Yahoo! Messenger.
            http://messenger.yahoo.com/
          • Phlip
            ... Whose proper unit test definition are you addressing? Use Mike Feather s /in vivo/ test pattern. Get inside main(), get past the framework stuff, and
            Message 5 of 9 , May 31, 2004
              Alistair A. Israel wrote:

              > Now here's the catch 22: some legacy code was
              > written in such a way as
              > to preclude or hinder the creation or running of
              > 'proper' Unit Tests.
              > To use a concrete example, one class may have a
              > static method (which
              > should be trivial to test). But, that class also has
              > a static
              > initializer which basically loads a framework and
              > initializes it with
              > properties that are set in a separate installation
              > program.
              >
              > (Obviously, several design issues there - but that's
              > the point.)
              >
              > So now what do we do? To create a 'proper' Unit Test
              > (one that
              > executes quickly with minimal external fixtures), we
              > first need to
              > refactor the code.

              Whose "proper" unit test definition are you
              addressing?

              Use Mike Feather's /in vivo/ test pattern. Get inside
              main(), get past the framework stuff, and then
              conditionally compile a "runTests()" method. Your
              Programmer Tests will execute slowly, with maximal
              external coupling.

              Long term, they will indeed help address the design.
              Short term, their only requirement is they test!


              =====
              Phlip
              http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces




              __________________________________
              Do you Yahoo!?
              Friends. Fun. Try the all-new Yahoo! Messenger.
              http://messenger.yahoo.com/
            • Alistair A. Israel
              Thanks for the responses, Ron, Michael and Phlip. Let me try to summarize your points (and my replies) below. 1. Ron and Michael mention high-level or granular
              Message 6 of 9 , Jun 1, 2004
                Thanks for the responses, Ron, Michael and Phlip. Let me try to
                summarize your points (and my replies) below.

                1. Ron and Michael mention high-level or granular (e.g., acceptance)
                tests. I think is currently being covered by manual, 'QA' tests before
                shipping. It does not, however, encourage the tight feedback loop so
                necessary for refactoring.

                2. Again, both Ron and Michael suggest the use of a refactoring tool
                or IDE. I don't know whether Eclipse, IDEA or JBuilder's refactoring
                capabilities are up to the entire task (I've been using NetBeans
                myself, just started on Eclipse - I know, the entire team should try
                one IDE but the choice isn't entirely personal, it's business-driven).

                We'll certainly explore this technique for all it can do for us - but
                what happens when you really have to break, say, a core object into
                various model, persistence and helper objects?

                3. As for refactoring "very, very carefully", I think to a certain
                extent this is possible - just as writing retrofitted unit tests on
                simple or trivial classes (just to increase test coverage) is very
                possible. But since we're also trying to refactor/test the code that's
                giving us the most problems - unfortunately, this means focusing
                effort on core objects used heavily in production.

                4. Phlip suggested introducing Frequent Releases, sitting together,
                and light pair programming first. I think that's largely the 'de
                facto' environment, so that should help. The various teams sit side by
                side. There are hardly any individual cubes (though it's not an
                entirely open workspace). Everybody is free to move around, it doesn't
                take much effort to get up to the next guy (or to me, or to the PM) to
                ask a question, and some people _do_ work in pairs naturally.

                Thanks for all your suggestions. I guess what's left really is just
                the actual work of carefully adding tests and refactoring one small
                step at a time - though I'm really curious about your tips and your
                book, Michael, as to how we can do all that is the most efficient and
                safe manner. "Patterns in Retro-testing/Refactoring Legacy Code", anyone?

                - A. Israel
              • John Brewer
                On Tue, 01 Jun 2004 11:19:15 -0000, Alistair A. Israel ... As far as I know, only IntelliJ IDEA and Eclipse have refactoring tools good enough to be worth
                Message 7 of 9 , Jun 1, 2004
                  On Tue, 01 Jun 2004 11:19:15 -0000, Alistair A. Israel
                  <aisrael@...> wrote:
                  > 2. Again, both Ron and Michael suggest the use of a refactoring tool
                  > or IDE. I don't know whether Eclipse, IDEA or JBuilder's refactoring
                  > capabilities are up to the entire task (I've been using NetBeans
                  > myself, just started on Eclipse - I know, the entire team should try
                  > one IDE but the choice isn't entirely personal, it's business-driven).

                  As far as I know, only IntelliJ IDEA and Eclipse have refactoring
                  tools good enough to be worth using.

                  I don't think standardizing on one IDE is terribly important. If the
                  Ant build runs, I don't care if you coded it using cat. Your pair
                  partner might, but that's between you and him.

                  John Brewer

                  Extreme Programming FAQ: http://www.jera.com/techinfo/xpfaq.html
                • J. B. Rainsberger
                  ... Yes. There are two options: 1. Write tests /of some kind/ to support refactoring, then refactor the code to make it more object testable, then write object
                  Message 8 of 9 , Jun 1, 2004
                    Alistair A. Israel wrote:

                    > Has anybody had any similar experience to share? Can anybody provide
                    > wisdom on the matter?

                    Yes. There are two options:

                    1. Write tests /of some kind/ to support refactoring, then refactor the
                    code to make it more object testable, then write object tests ("true
                    unit tests").

                    2. Refactor without a safety net, then hope.

                    It depends which you feel more comfortable doing. Try them both and see
                    what different kinds of pain you feel. Do what makes you feel most like
                    you're making progress.
                    --
                    J. B. Rainsberger,
                    Diaspar Software Services
                    http://www.diasparsoftware.com :: +1 416 791-8603
                    Let's write software that people understand
                  • Amir Kolsky
                    The C# s Resharper (also from jetbrains) is getting there.... Amir Kolsky XP& Software ]-----Original Message----- ]From: John Brewer
                    Message 9 of 9 , Jun 18, 2004
                      The C#'s Resharper (also from jetbrains) is getting there....

                      Amir Kolsky
                      XP& Software


                      ]-----Original Message-----
                      ]From: John Brewer [mailto:jbrewer@...]
                      ]Sent: Tuesday, June 01, 2004 11:39 PM
                      ]To: extremeprogramming@yahoogroups.com
                      ]Subject: Re: [XP] Re: Catch 22: Unit Testing vs. Refactoring
                      ]
                      ]On Tue, 01 Jun 2004 11:19:15 -0000, Alistair A. Israel
                      ]<aisrael@...> wrote:
                      ]> 2. Again, both Ron and Michael suggest the use of a refactoring tool
                      ]> or IDE. I don't know whether Eclipse, IDEA or JBuilder's refactoring
                      ]> capabilities are up to the entire task (I've been using NetBeans
                      ]> myself, just started on Eclipse - I know, the entire team should try
                      ]> one IDE but the choice isn't entirely personal, it's
                      ]business-driven).
                      ]
                      ]As far as I know, only IntelliJ IDEA and Eclipse have
                      ]refactoring tools good enough to be worth using.
                      ]
                      ]I don't think standardizing on one IDE is terribly important.
                      ]If the Ant build runs, I don't care if you coded it using cat.
                      ] Your pair partner might, but that's between you and him.
                      ]
                      ]John Brewer
                      ]
                      ]Extreme Programming FAQ: http://www.jera.com/techinfo/xpfaq.html
                      ]
                      ]
                      ]To Post a message, send it to: extremeprogramming@...
                      ]
                      ]To Unsubscribe, send a blank message to:
                      ]extremeprogramming-unsubscribe@...
                      ]
                      ]ad-free courtesy of objectmentor.com
                      ]Yahoo! Groups Links
                      ]
                      ]
                      ]
                      ]
                      ]
                      ]
                    Your message has been successfully submitted and would be delivered to recipients shortly.