Exploring Solution Spaces © Copyright 2003-2006, by C. Keith Ray
   


About
Exploring Solution Spaces, Keith Ray's blog on Software development and other topics.

Send comments to:
keithray@mac.com

For Agile Training, eLearning, or Coaching contact:
Industrial Logic, Inc.
866-540-8336 (toll free)
510-540-8336 (Berkeley, California)

Links
xpminifaq
Résumé
“Adopting XP” Article 2002 (pdf)
“ Refactoring” Article 2006
AYE Conference
Lucien W. Dupont
Elisabeth Hendrickson
Johanna Rothman's Managing Product Development
Brian Marick's Exploration Through Example
Esther Derby's Insights You Can Use
Laurent Bossavit's Incipient(thoughts)
Dale Emery's Conversations with Dale
Martin Fowler's Bliki
Creating Passionate Users

Archives

  • 2003
  • 2004
  • 2005
  • 2006
  • 2007
  • 2008
  • Subscribe
    RSS Exploring Solution Spaces XML


           
    2005.Sep.28 Wed

    Filters

    I once needed to make three "filters" works. They each took an image file and several parameters as input, and produced an output PDF file. For most manual tests for various parameter settings, they did not produce correct output. So I refactored the big filter function to do the filtering in two steps (two subroutine calls).

    The first subroutine works on the parameters to compute the values needed to be passed into the image processing library, and the second subroutine calls the image processing library with the input image, those computed values, and produces the output image.

    Then I wrote a parameterized unit test that took all the parameters as input to the first subroutine, also took into expected output values, and asserted that the actual output values were equal to the expected output values.

    Then I wrote 900 one-line unit tests to this parameterized unit test with the various permutations of the input parameters and expected output values. (I actually worked in a spreadsheet for a while and copied-pasted from the spreadsheet to the unit test source code.) The test would also generate the output PDF file, which I could visually examine

    About 80% of the tests failed.

    Then I started working on the first subroutine to fix its problems. I got to where only 60% of the tests failed, then only 50%, 30%, 25%, 10%, the only 2 failures, and then 100% passing. Sometimes a change causes more tests to fail than before, and I could examine my latest modification and fix it, or undo it to try something else.

    That was the first of the three filters.

    The other two were similar, but with fewer parameters and options, each of those only needed about 600 one-line unit tests. Note that I didn't test EVERY combinations of options and settings. That would have required several billion test cases. By making an intelligent selection of the "input space" I could exercise the filter algorithm along all of its dimensions with a minimum of effort.

    Fixing all three filters with the aid of automated tests only took a few days each. Trying to make the algorithm work with manual testing would have taken months or years.

    [/docs] permanent link

    Blocks

    Ruby, calling a method with a block argument:

    
        anObject.methodTakingBlock { someObj.doSomethingHere }
    
    

    or

    
        anObject.methodTakingBlock do
            someObj.doSomethingHere
        end
    
    

    Smalltalk, calling a method with a block argument:

    
        anObject methodTakingBlock: [ someObj doSomethingHere ].
    
    

    Ruby, implementing a method that takes a block argument (the lack of a named block variable and the "yield" keyword are a bit confusing, particularly if you associate "yield" with threads, which are not in play here.)

    
        def methodTakingBlock
            yield
        end
    
    

    Smalltalk, implementing a method that takes a block argument.

    
        methodTakingBlock: aBlock
            aBlock value.
    
    

    Ruby, calling a method with a block argument that takes two argument itself:

    
        anObject.methodTakingBlock { 
            |aVar, bVar| someObj.doSomethingHere(aVar, bVar) }
    
    

    or

    
        anObject.methodTakingBlock do |aVar, bVar|
            someObj.doSomethingHere(aVar, bVar)
        end
    
    

    Smalltalk, calling a method with a block argument that takes two arguments itself:

    
        anObject methodTakingBlock: [ :aVar :bVar | 
            someObj doSomethingHere: aVar andHere: bVar ].
    
    

    Ruby, implementing a method that takes a block argument, giving the block the values 12 and 13 for the block's own arguments.

    
        def methodTakingBlock
            yield 12, 13
        end
    
    

    An Ruby alternative syntax where the block argument is converted to a Proc object and is accessible via a named parameter:

    
        def methodTakingBlock(&aProc)
            aProc.call(12,13)
        end
    
    

    Smalltalk, implementing a method that takes a block argument, giving the block values 12 and 13 for its own arguments.

    
        methodTakingBlock: aBlock
            aBlock value: 12 value: 13.
    
    

    [/docs] permanent link