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

Re: [TDD] The simplest thing doesn't work

Expand Messages
  • Keith Ray
    ... Let s forget about simple code (which sounds like it was simplistic , which is different.) You have legacy code. Legacy code will make adding new
    Message 1 of 108 , Aug 22, 2009
    • 0 Attachment
      Going back to the original post:

      > In short, because we wrote simple code in the beginning and didn't think deeply enough about
      > what the needs were, a significant amount of redesign ends up being required, resulting in a
      > lengthy turnaround time for implementing a simple feature. The nice part is that our tests tell
      > us what stuff needs to change. The lousy part is that so many things need to change. This
      > seems to be a frequent occurrence here where something comes up requiring a day's detour
      > to redesign something (and everything around it) that previously seemed just fine.
      > I'm thinking the solution is BDUF, but that's a bad word here. Is there a better solution?

      Let's forget about "simple" code (which sounds like it was
      "simplistic", which is different.)
      You have legacy code. Legacy code will make adding new features incur
      amounts of work because the existing code is not well-factored. To
      quote Joe Rainsberger:

      "In systems with high technical debt, the cost of repaying that
      technical debt dominates the cost of a story."

      To make the code more well-factored (paying down the technical debt),
      whenever you need to integrate a new feature into it, you should pay
      close attention to code smells in both the new code and the old code
      and consider refactoring to deal with each smell as you recognize it.

      You can do refactorings in small safe steps (even in C++) manually.
      Very closely follow the instructions in Fowler's book on Refactoring
      until you learn them by heart. Eclipse with gcc has a few refactorings
      that actually work: Extract Method and Rename. Rename understands
      scope, so it is safer than search-and-replace. Extract Method and the
      other refactorings in Ecipse might be buggy, so be careful when you
      use them. For things like changing a function signature, "lean on the
      compiler" to show where changes have to be made.

      You also need tests to make sure the refactorings are not damaging the
      existing features. Feather's book on working with legacy code has lots
      of techniques for adding tests to legacy code.

      On a higher level, code smells are violations of good design
      principles. For example, the Single Responsibility Principle (SRP)
      says there should one purpose for every class / method / module. There
      are principles about coupling and cohesion and managing dependencies,
      etc. It's often easier to detect a code smell than it is to apply
      these abstract principles. "Large Class" and "Large Method" are
      remedied by "Extract Class" and "Extract Method/Move Method", though
      knowing SRP helps in deciding what parts of a class or method should
      be extracted.

      Perhaps the most important design principle is "Tell, don't ask": keep
      functionality and data together.... bad code often has the
      functionality in one place, and gets the data it needs from other
      places, creating problems with dependencies and lack of locality --
      symptomized by "adding a new feature requires changing lots of code".
      The code smells "Shotgun Surgery", "Feature Envy", "Long Parameter
      List" are applicable here.

      Getting fast feedback will allow more refactoring, which will
      (eventually) allow faster development of new features. Try to get
      parallel builds happening (distributed compilation). Try to get
      smaller source files and smaller header files. Reduce the complexity
      of header files - use forward declarations, avoid inline code, try to
      keep only one class per header file / source file. Using the "pimpl"
      idiom widely can decrease compile time by 10%, but it can also
      disguise the "Large Class" and "Feature Envy" code smells.

      The advantage of refactoring instead of rewriting, is that you always
      have working code. If your manual and automated tests are good, then
      you should be able to ship the code, even if it is a half-way state
      between a bad design and a good design.

      I wrote an article on refactoring legacy C++ code here:

      I'm also one of the authors of Industrial Logic's elearning
      (particularly the C++ content). We have albums and workshops available
      in C++ on Code Smells, Refactoring, TDD and microtesting legacy code.

      C. Keith Ray, IXP Coach, Industrial Logic, Inc.
      http://industriallogic.com      866-540-8336 (toll free)
      Groove with our Agile Greatest Hits: http://www.industriallogic.com/elearning/
    • George Dinwiddie
      ... What does not possible mean in this context? - George -- ... * George Dinwiddie * http://blog.gdinwiddie.com Software Development
      Message 108 of 108 , Oct 10, 2009
      • 0 Attachment
        Alan Baljeu wrote:
        > As far as I understand things, it is not possible to swap out the
        > VC++ compiler for another.

        What does "not possible" mean in this context?

        - George

        * George Dinwiddie * http://blog.gdinwiddie.com
        Software Development http://www.idiacomputing.com
        Consultant and Coach http://www.agilemaryland.org
      Your message has been successfully submitted and would be delivered to recipients shortly.