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


           
    2007.Dec.08 Sat

    Jame Shore on What's the value of functional testing?

    James Shore lightening talk (video) transcript quotes:

    [...] it's about getting up in front of a whiteboard with your experts and saying, "let's talk about some examples of your domain. Let's look at what goes on." Whenever I've done this with customers, there's been this great "ah ha" of "oh my goodness, we didn't realize that we misunderstood each other so much." And this always happens before we start talking about Fit. This happens while we're actually at the whiteboard talking about examples. Fit is actually secondary to this process.

    (Nowadays I describe Fit as providing a way of automating your examples. But you know what, you don't need Fit to do that. You get the power without using Fit. But if you use Fit without examples, it won't be that useful.)

    So, to answer these questions: does it work, are we done, is it right, and minimize waste, I think we can use TDD, perhaps with exploratory testing to tell us if it works; involved customers to tell us if it's done; concrete examples to tell us if its right, and we might automate those examples.

    Thus it seems to me that there's no need for [functional] testing; we can eliminate waste and keep it light.

    Check it out

    [/docs] permanent link

    Elisabeth Hendrickson on Why Automated Acceptance Tests are Crucial

    Elisabeth Hendrickson’s lightening talk (video).

    "Automated Acceptance Tests are absolutely crucial to make sure that we know, we get the feedback right away, if we have violated an expectation that the customer had [...]. Furthermore, Customers don't want to have to repeat their expectations: [...] 'I have these expectations of the system, now it's the programmers problem to figure out how to automate those expectations to get that feedback.'"

    [/docs] permanent link

    2007.Nov.26 Mon

    Industrial Logic's Greatest Hits

    Industrial Logic has a new home page, where you can browse and purchase eLearning products for C++, Java, and C# on the subjects of Code Smells, Refactoring, and Microtesting.

    The front page also lets you Take a Tour and experience the Welcome Album, which includes blooper videos. Joshua Kerievsky, Mike Hill, and Gil Broza are the authors of this self-paced training material, as well as the instructors who use the same materials in Industrial Logic's in-person workshops.

    Check it out.

    [/docs] permanent link

    2007.Nov.25 Sun

    Return of the Blog: Pairwise testing

    I haven't been blogging much lately, but it's time to spill. Miscellaneous subjects follow.

    Via Michael Bolton, a paper (pdf) "Pairwise Testing: A Best Practice That Isn't", by James Bach and Patrick J. Schroeder Quotes:

    This article is about another apparent best practice that turns out to be less than it seems: pairwise testing. Pairwise testing can be helpful, or it can create false confidence. On the whole, we believe that this technique is over promoted and poorly understood. To apply it wisely, we think it’s important to put pairwise testing into a sensible perspective. [...]

    Pairwise testing fails when you don’t select the right values to test with. [...]

    Pairwise testing fails when you don’t have a good enough oracle. [...]

    Pairwise testing fails when highly probable combinations get too little attention. [...]

    Pairwise testing fails when you don’t know how the variables interact. [...]

    The pairwise story is one that all testers would like to believe: a small cleverly constructed set of test cases can do the work of thousands or millions of test cases. As appealing as the story is, it is not going to be true in many situations. Practitioners must realize that pairwise testing does not protect them from all faults caused by the interaction of 1 or 2 fields.

    [/docs] permanent link

    2007.Oct.12 Fri

    What's the point of tests that pass all the time?

    When I'm doing Test Driven Development, my tests (almost) always fail - at least once.

    This is because I write a test and run it before I write the code to make the test pass. It should fail because the functionality isn't implemented yet.

    I could design my code without using the tests to guide me, but then I find that I spend a lot of time debugging manually, and afterwards, I don't have tests to find regressions. I define regressions as bugs for already-implemented features which can get injected into the code during refactoring or when adding new features. So the tests in TDD are serving two purposes: guiding my design, and guarding against regressions.

    However, I don't check into source-code-control when tests are failing, and I hope my team-mates do the same thing. So from the viewpoint of the team's continuous integration server, the programmer tests used for TDD should never fail.

    Sometimes they do, because we make mistakes: we forget to check in something, or the tests are poorly written -- for example, a test might be accessing a live external server that isn't running all the time, or has inconsistent time-outs or other 'flaky' behavior.

    The skills for TDD and writing reliable tests are more subtle than they ways of wizards, but they can be learned. [I've been watching Lord of Rings again.]

    [/docs] permanent link

    2007.Oct.05 Fri

    Const Assurance in C++

    "splogs" is inspired to use 'const' more in C++ after exposure to Haskell. Quote:

    [...] When a software developer is debugging a program (as s/he often is), just knowing that one "thing" will not change after creation decreases the scope of required knowledge for that session by one. If all things are immutable, that significantly reduces the probability that bugs are present in dynamic logic. Thus, by being "const-ipated" with your code (by using const wherever possible), you can kill bugs before they even appear!

    An anonymous commenter responded:

    I've found that striving for immutability in class design (also rubbing off from the functional versions where data types are immutable) also makes concurrency a lot easier and faster. For infrequently mutation, reconstructing parts of the object graph (to preserve immutability) can be a lot cheaper in the long run if it obviates the need for a lock in hot code paths.

    Consider this bit of code:

    Results aFunction(SomeClass& anObject)
    {
        someval = anObject.SomeMethod();
        // later...
        someotherval = anObject.SomeOtherMethod();
        // etc.
        return results;
    }
    

    Given that anObject is not const, you'd have to assume that SomeMethod and SomeOtherMethod could be modifying the state of the object. If you changed the order of calls, or called one of those methods more than once, you could break the desired behavior. The only way to know for sure would be to look at the source-code and/or documentation for SomeClass's methods. Now with const-ness:

    Results aFunction(const SomeClass& anObject)
    {
        someval = anObject.SomeMethod();
        // later...
        someotherval = anObject.SomeOtherMethod();
        // etc.
        return results;
    }
    

    The simple act of declaring anObject to be const also implies that SomeMethod and SomeOtherMethod are const methods. (The compiler will complain if that's not true). This assumes the programmer for SomeClass was following the rules (that is, he's not 'faking' const-ness) and SomeClass isn't modifying some external state that we care about. In this case with a const reference and const methods, we could be pretty sure that we could change the order of method calls, and the number of times the methods are called, with no effect on the correct behavior.

    Unfortunately, even with 'const' we can't always be sure the behavior is correct, so writing micro-tests helps enforce the intended behavior. A test like...

    TEST(aFunctionDoesWhatWeWant)
    {
        SomeClass anObject; // set up how we want
        Results fResults = aFunction(anObject);
        AssertEqual(expectedState, anObject.GetState());
        AssertEqual(expectedResults, fResults);
    }
    

    ... would help us verify that the following changes are okay, if it still passes after changing the order and number of calls.

    Results aFunction(const SomeClass& anObject)
    {
        someval = anObject.SomeMethod();
        someotherval = anObject.SomeOtherMethod();
        // later...
        someotherval2 = anObject.SomeOtherMethod();
        someval2 = anObject.SomeMethod();
        // etc.
        return results;
    }
    

    Declaring a function parameter const also helps tell other programmers that the function isn't going to try to change the object's value. Tests will help document the function's desired behavior.

    [/docs] permanent link

    2007.Sep.20 Thu

    Some C++ Code Quality Metrics

    Purity metric: the ratio of pure virtual methods over the total number of methods of a class. Purity of 1.0 is good for an abstract base class. Purity of 0.1 might be ok for a class implementing the Template Method Design Pattern. Purity of 0.5 is likely to be bad because the class is going to be confusing. It is likely to be an abuser of "inheritance for implementation". Note that Template Method relies on subclassing from a class with a partially-concrete implementation, and might be better replaced by the something like the Strategy Design Pattern, which has a concrete class parameterized by injection of pluggable strategy objects (whose parent class is purely abstract).

    Public Interface metric: the ratio of public methods over the total number of methods of a class. A measure of 1.0 is probably good: all public methods, and no private methods (at least it's testable). A Public Interface number of 0.1 is likely to be bad - the class is consisting of mostly private or protected methods, and thus hard to test. A low number is a sign of the Iceberg Class , often indicating that the class is too large and should be broken up into several smaller, collaborating classes (after the break-up, maybe only one class is still part of the public API, but the other classes who now have public methods would be testable.)

    Static Cling metric: the number of static variables in a class, including static variables in the class's implementation file, whether file-scope or function-scope.

    Anti-Polymorphic metric: number of static functions and non-virtual functions in a class, plus the number of file-local functions in the class's implementation file.

    [/docs] permanent link

    2007.Sep.10 Mon

    ABC's of Micro-Testing

    Here are three basic kinds of micro-tests, a.k.a. "programmer tests" such as used in test-driven design/TDD.

    Testing the return value of a side-effect-free function.

    A lot of simple examples of TDD do this. Simple return-values, scalars instead of lists, for example, are generally simpler to test.

    result = some_function(some_input);
    assert_equals(expected_result, result);
    

    Testing the state of an object after creation and/or calling one or more methods on it.

    In other words, testing the post-conditions of an object. The fewer methods called, the simpler the test; and, the simpler the state being checked, also the simpler the test.

    an_object = new some_object(maybe_some_input);
    an_object. some_method(maybe_some_more_input);
    assert_equal(expected_object_state, an_object); // or ...
    assert_equal(expected_object_state, an_object.get_state());
    

    Testing the collaboration of an object with another.

    In other words, checking how it calls methods in another object using some kind of mock object. The fewer the objects and methods involved, the simpler the test.

    an_object = new some_object();
    collaborator = new some_kind_of_test_double();
    an_object. some_method(collaborator);
    assert_true(collaborator.expected_method_called_correctly());
    

    The further away that you get from these simple basics, the harder the tests are and the more complex the code's design is. In particular, testing state gets more difficult if the state-changes are not localized to a single object under test -- global variables, modified input-variables, the file-system, networked client-server or peer-to-peer interactions, and databases are some places where non-local state changes can make things difficult.

    [/docs] permanent link

    2007.Jul.29 Sun

    Three A's and an E

    William Wake described the essence of an automated test as Arrange, Act, Assert. I've added "Erase", to account for the clean-up that some tests have to do. You might ask why "Erase" added to "Arrange, Act, Assert" and not some word starting with "A". I think starting with "eh?" is close enough. :-)


    "The thing about elves is they've got no ... begins with m," Granny snapped her fingers irritably."

    "Manners?"

    "Hah! Right, but no."

    "Muscle? Mucus? Mystery?"

    "No. No. No. Means like ... seein' the other person's point of view."

    Verence tried to see the world from a Granny Weatherwax perspective, and suspicion dawned.

    "Empathy?"

    "Right. None at all. Even a hunter, a good hunter, can feel for the quarry. That's what makes 'em a good hunter. Elves aren't like that. They're cruel for fun [...]"

    —Terry Pratchett, Lords and Ladies


    In C++, with certain test frameworks, a test might be specified in a manner something like the following in C++.

    TEST(TestBlurImageFilter)
    {
        // Arrange
        string outfileName = NewTempFileName("TestImageFilter");
        Image* sourceImage = new Image("lena.png");
    
        // Act
        ImageFilter* filter = new BlurImageFilter();
        filter->ProcessToFile(sourceImage, outfileName);
    
        // Assert
        AssertImagesEqual("expected_lena_blurred.png", outfileName);
    
        // Erase
        DeleteTempFile(outfileName);
        delete filter;
        delete sourceImage;
    }
    

    Note: generally you don't want to deal with files in unit tests; working in-memory would be much faster. Also, if this is one of those frameworks that throws an exception, or otherwise aborts the test if an assertion fails, then the "Erase" portion of the test won't get executed if AssertImagesEqual failed. Let's assume that's not a problem for the moment.

    Let's imagine that you then write a another test like so:

    TEST(TestUnblurImageFilter)
    {
        // Arrange
        string outfileName = NewTempFileName("TestImageFilter");
        Image* sourceImage = new Image("lena.png");
    
        // Act
        ImageFilter* filter = new UnblurImageFilter();
        filter->ProcessToFile(sourceImage, outfileName);
    
        // Assert
        AssertImagesEqual("expected_lena_unblurred.png", outfileName);
    
        // Erase
        DeleteTempFile(outfileName);
        delete filter;
        delete sourceImage;
    }
    

    Now you've got duplicated "Arrange" and "Erase" sections. And duplicated logic in tests can be just as bad it would be in production code. Fortunately, most test frameworks already have support for extracting "Arrange" and "Erase" to methods in a "test fixture". The above code could be refactored to something like the following:

    class ImageFilterTests : public TestFixture
    {
    public:
        ImageFilterTests()
            : sourceImage(NULL), filter(NULL)
        {
        }
    
        string outfileName;
        Image* sourceImage;
        ImageFilter* filter;
    
        virtual void SetUp()
        {
            // Arrange
            outfileName = NewTempFileName("TestImageFilter");
            sourceImage = new Image("lena.png");
        }
        virtual void TearDown()
        {
            // Erase
            DeleteTempFile(outfileName);
            delete filter;
            delete sourceImage;
        }
    };
    
    TEST_USING_FIXTURE(ImageFilterTests, TestBlurImageFilter)
    {
        // Act
        filter = new BlurImageFilter();
        filter->ProcessToFile(sourceImage, outfileName);
    
        // Assert
        AssertImagesEqual("expected_lena_blurred.png", outfileName);
    }
    
    TEST_USING_FIXTURE(ImageFilterTests, TestUnblurImageFilter)
    {
        // Act
        filter = new UnblurImageFilter();
        filter->ProcessToFile(sourceImage, outfileName);
    
        // Assert
        AssertImagesEqual("expected_lena_unblurred.png", outfileName);
    }
    

    Not only has this eliminated the duplicated logic, most unit test frameworks will also guarantee running the TearDown method even if the test fails, so you don't have to write your own try/catch blocks or other contortions for exception-safe "erase".

    You'll see that I also added a constructor to insure that the pointer variables have valid NULL values so we don't delete garbage pointers if the Image or Filter objects were not allocated successfully. (You should consider using boost::shared_ptr and/or boost::scoped_ptr if you're dealing with object pointers in C++ code and tests, by the way.)

    In those C++ test frameworks where the test-fixture creation and deletion is done just before and after executing the test, the SetUp and TearDown methods can (almost always) be replaced with a constructor and destructor instead. Using that and boost::scoped_ptr to insure exception-safe object deletion would allow us to write the following code:

    class ImageFilterTests : public TestFixture
    {
    public:
        ImageFilterTests()
            : outfileName(NewTempFileName("TestImageFilter")),
              sourceImage(new Image("lena.png"))
        {
            // Arrange
        }
    
        virtual ~ImageFilterTests()
        {
            // Erase
            DeleteTempFile(outfileName);
        }
    
        string outfileName;
        boost::scoped_ptr<Image> sourceImage;
        boost::scoped_ptr<ImageFilter> filter;
    };
    
    TEST_USING_FIXTURE(ImageFilterTests, TestBlurImageFilter)
    {
        // Act
        filter.reset(new BlurImageFilter());
        filter->ProcessToFile(sourceImage.get(), outfileName);
    
        // Assert
        AssertImagesEqual("expected_lena_blurred.png", outfileName);
    }
    
    TEST_USING_FIXTURE(ImageFilterTests, TestUnblurImageFilter)
    {
        // Act
        filter.reset(new UnblurImageFilter());
        filter->ProcessToFile(sourceImage.get(), outfileName);
    
        // Assert
        AssertImagesEqual("expected_lena_unblurred.png", outfileName);
    }
    

    [/docs] permanent link

    2007.Jul.17 Tue

    The Paradox of Choice

    It's easier for me to write a review of a book I'm still in the process of reading it, than it is for me to write a review after I have finished reading the book. Why is that? Once I've finished the book, I move onto the next thing. Writing a review would be "going backwards". So I'm writing this book review while I'm still reading the book.

    The book is Paradox of Choice by Barry Schwartz. It's got a lot of interesting stuff in it: maximizers and satisficers, sunk costs, how verbalizing the reasons for a choice sometimes causes us make worse choices, how a disappointment often leads us to consider counterfactuals that increase our regrets, and so on.

    A friend of mine tends to compare himself to his more successful cousin, increasing his regrets. He could compare himself to one of his less successful cousin, but doesn't. Why not? The Olympic winner of a silver medal is less happy than the winner of a bronze medal. Why? Because the silver winner compares his or her reality against the winner of the gold medal and regrets whatever choices might have preventing winning the gold, while the bronze winner compares his or her reality against not winning a medal at all, and so appreciates reality more.

    This may be the one of the most "practical" books available for increasing your happiness, and it's based on science. (Insert appreciative sound here.) Science may not be able to explain why we cause ourselves so much mental suffering in all cases, but it does help explain that it's not our fault for many cases. Some of our behavior is very likely built into our neurology, and some of it may come from the influence of society. But we can make an effort to overcome our natural inclinations towards thoughts that cause us suffering.

    [/docs] permanent link

    2007.Jul.09 Mon

    GUI Test Driven Development in Smalltalk

    Check out this tutorial of developing a graphical game application in Squeak Smalltalk, that uses test-driven development. Lots of screen-captures so you can follow along. A Development Example for Squeak 3.9.

    [/docs] permanent link

    2007.Jul.06 Fri

    What is Writing Software Like?

    I think writing software in small groups is very much like the writing done for TV shows, which is also often done in small groups. We complain about the failures rates of software projects, and the lack of quality, but how many TV shows are good versus bad? Or great?

    Isn't typings words into a script easy? TV requirements seeem pretty simple - use the actors you've got (or not, in some situations), don't write scripts that require spending a lot money on sets or special effects, don't offend the advertisers, attract and keep an audience. And "be dramatic" or "be funny", depending on the show.

    Some shows are wonderful but get canceled quickly because they're in the wrong time-slot, or too expensive, or the TV Executives are idiots. Some software projects are too ambitious, or too expensive, or managed by Dilbert's boss. Other TV shows, like various soap operas whose quality I cannnot comment on, survive for decades with a large and loyal audience, not unlike various makers of operating-systems and office-oriented software.

    We rarely write the exact same piece of software twice (bowling game exercises are the exception), and TV show writers aren't allowed to repeat themselves too obviously, either.

    Most of the constraints of a TV show or a piece of software are self-imposed. In the case of software, the system is usually constrained by the person(s) willing to pay for features but also constrained by the skills of the people involved.

    [/docs] permanent link

    2007.Jun.23 Sat

    Standish Group 2006 (2004?) Top Ten Success Factors

    Quotes from an infoq interview with Jim Johnson of the Standish Group:

    Top Ten Success Factors

    1. User Involvement
    2. Executive Management Support
    3. Clear Business Objectives
    4. Optimizing Scope
    5. Agile Process
    6. Project Manager Expertise
    7. Financial Management
    8. Skilled Resources
    9. Formal Methodology
    10. Standard Tools and Infrastructure

    and

    InfoQ: Agile must bring in new issues: how do you say when "planned" scope is accomplished, for a project using adaptive planning?

    JJ: That's a good question. With companies like Webex, Google, Amazon, eBay, it's a challenge - they're doing something called "pipelining" instead of releases. "Whatever is done in 2 weeks, we'll put that up." They're successful because users only get small, incremental changes. And their implementation is proven - remember, some projects only fail after the coding is finished, at the implementation step.

    [...]

    JJ: People think Agile is 'loosey goosey'... If people really looked at it, they'd see it's just as stringent as waterfall or anything James Martin could put together. To say there has not been major improvements is the last dozen years is just plain foolishness. We have made great progress.

    [/docs] permanent link

    2007.Jun.19 Tue

    Fortune
    You can change tomorrow's yesterday only if you make a change today.

    [/docs] permanent link

    2007.May.16 Wed

    Testing is an Integral Part of Development

    Johanna Rothman:

    Effective testing is not a service. Effective testing is an integral part of development.

    Say it, sister!

    [/docs] permanent link

    2007.May.02 Wed

    Requirements

    Requirements exist, whether or not they are written down." -- Elisabeth Hendrickson

    [/docs] permanent link

    2007.Apr.09 Mon

    Refactoring is like Steering a Car

    Won't continual merciless refactoring slow the team down?

    This question is like asking, "Isn't all that messing with steering wheel going to slow your car down? Why don't you just pick a direction for your car, lock your steering wheel in place, and stick to it?"

    Refactoring takes care of unplanned as well planned design changes. Unplanned changes may include noticing duplicated code or other code smells. Planned changes include those changes necessary to implement a new story or feature. Similarly, in driving, we have unplanned course changes, such as avoiding accidents, slow drivers, potholes, and pedestrians, and planned course changes.

    Like all analogies, there's a nugget of truth here, but don't take the analogy too far.

    [/docs] permanent link

    2007.Apr.04 Wed

    Technical Debt and Bankruptcy

    If you don't pay down your Technical Debt as soon as it you incur it, ... it's like never paying down the balance on your credit cards. Soon you'll have so much interest and penalty debt on your credit cards that you can't pay them off at all. Technical Debt consists of refactorings and bug-fixes that don't get done (or get deferred), slowing down present and future development.

    When a programming team says they can't make progress with the current software and that it needs to be rewritten "from the ground up", that's declaring Technical Bankruptcy.

    [/docs] permanent link

    2007.Mar.28 Wed

    How to Estimate with Story Points

    Pick a very small, easy, story "User can do X".

    Set its story-point value to 1.

    Compare that to another story "User can do Y"... is that just as difficult as the previous story? two times harder? three times harder? or easier than the 1-point story?

    If 2-times harder then it's story point value is 2.

    If 3-times harder, then its story point value is 3.

    If it is easier, call it 1/2 a point or use the "Y" story as the new 1-point story and evaluate the "X" story against it.

    If the "Y" story is more than 3 times harder, find a way to split the story into two or more smaller stories.

    Story points are a relative measure used for estimation, and they are not based on line count.

    [/docs] permanent link

    2007.Mar.27 Tue

    Focus - Asking and Answering

    Sometimes people new to Test Driven Development (Behavior Driven Design) focus on testing accessors, or testing constructors, or other details a little too much. In TDD/BDD, we're not testing, we're designing. When writing a executable example (aka "spec" or "test"), we're asking the questions:

    1. What do we want X to do?

    2. How do we want to tell X to do it?

    3. How will we know when X has done it?

    In answering these questions, we use (possibly not-implemented-yet) constructors, methods, accessors, etc. We then compile and run the example to see it fail; and then write code to make the example pass. And sometimes while all examples are passing, we refactor to improve the design.

    When writing code to make the spec pass, we ask and answer the question:

    4. How does X do it?

    And when refactoring we ask and answer the question:

    5. Is this the best design at this time?

    To focus on "testing accessors" and "testing constructors" is to get a little too focused on the mechanics of "how does X do it?", which isn't even in the top 3 questions.

    [/docs] permanent link

    2007.Mar.24 Sat

    Work-Arounds for C++'s Lacking Block Syntax

    Doing a simple operation on each item in container...

    In Smalltalk, an arbitrary block of code can be passed to a method of a container. In the example below, "[" and "]" delimit a block of code, which is passed to the method named "do:" of the class List.

    testDo
        | alist aLocal |
        alist := List new.
        "...add Item instances, etc. to alist skipped."
        alist do: [ | item | item doSomething ].
    

    In Ruby, a block of code can be passed to a method using "{" and "}" to delimit the code, or "do" and "end". The method in this case is named "each" and belongs to the List class.

    def testEach
       alist = List.new
       # add Item instances, etc. to alist skipped.
       alist.each { | item | item.doSomething }
    end
    

    In C++ the are no code-blocks that can be passed around like other objects. There are several alternatives which involve writing a function or a class and then... Passing the class as a type-specialization of a template, or passing an instance of a class to have a member function invoked, or passing a function name as a specialization of a template, or passing a function pointer or a passing a pointer-to-a-member-function and a pointer to an object. The first two examples here are using a function and a functor class with the for_each template function.

    #include <vector>
    #include <algorithm>
    
    class Item
    {
    public:
        // etc...
        void doSomething();
    };
    
    void doSomething(Item& anItem)
    {
        anItem.doSomething();
    }
    
    struct Functor
    {
        void operator()(Item& anItem)
        {
            anItem.doSomething();
        }
    };
    
    void testForEachWithFunctionAndFunctor()
    {
        vector<Item> alist; 
        // add Item instances, etc. skipped.
        for_each(alist.begin(), alist.end(), doSomething);
        for_each(alist.begin(), alist.end(), Functor());
    }
    

    One of the drawbacks of the function or functor approach is you can't easily refer to local variables, like the Smalltalk and Ruby examples can do. (Not shown above to keep everything simple.) And the function tends to end up at an inconvenient distance away from the code that uses it do the iteration. An alternative is to use a static function declared in a class, which you can define inside your function, but accessing local variables is still inconvenient. (And for some reason, a functor class defined inside a function doesn't compile. Anyone know why?)

    #include <vector>
    #include <algorithm>
    
    class Item { ... };
    
    void testForEachWithClassStatic()
    {
        vector<Item> alist; 
        // add Item instances, etc...
    
        class Function
        {
            static void doSomething(Item& anItem)
            {
                anItem.doSomething();
            }
        };
        for_each(alist.begin(), alist.end(), Function::doSomething);
    }
    /*
    void testDoesntCompile()
    {
        struct FunctorInternal
        {
            void operator()(Item& anItem) 
            {
                anItem.doSomething();
            }
        };
        for_each(alist.begin(), alist.end(), FunctorInternal()); // error
    }
    */
    

    So if you want to refer to local variables easily, and have the code where you expect it, there's the old for-loop:

    #include <vector>
    #include <algorithm>
    
    class Item { ... };
    
    void testForLoop()
    {
        vector<Item> alist; 
        // add Item instances, etc...
        for (vector<Item>::iterator it = alist.begin();
             it != alist.end(); ++it )
        {
            it->doSomething();
        }
    }
    

    However, that can get verbose if the types and variables involved have long names. The last alternative to simulate passing a bit of code around is to get the preprocessor involved. In these examples, a macro can avoid the explicit 'for' loop as long as the action to do in the loop is simple enough. (And you can still access local variables.)

    #define APPLY4(vectorType,vectorName,iteratorName,Action)            \
        for ( vectorType::iterator iteratorName = vectorName.begin();    \
            iteratorName != vectorName.end(); ++iteratorName)            \
        {                                                                \
            (Action);                                                    \
        }
    
    
    #define APPLY3(vectorName,iteratorName,Action)                    \
        {                                                             \
            typedef typeof(vectorName) vectorType;                    \
            typedef vectorType::iterator itType;                      \
            for ( itType iteratorName = vectorName.begin();           \
                iteratorName != vectorName.end(); ++iteratorName)     \
            {                                                         \
                (Action);                                             \
            }                                                         \
        }
    // NOTE: "typeof" used above is non-standard/non-portable. 
    // (it's in the version of gcc C++ that I'm using on MacOS X.)
    
    void testApplyMacros()
    {
        vector<Item> alist; 
        // add Item instances, etc...
    
        APPLY4(vector<Item>, alist, each, each->doSomething);
    
        APPLY3(alist, each, each->doSomething);
    }
    

    By the way, the APPLY macros work on more than just vectors -- any container that implements "iterator". Making a APPLY_CONST macro that works with "const_iterator" should be trivial.

    [/docs] permanent link

    2007.Mar.22 Thu

    Code Smell: Duplicated Code

    The Worse Than Failure site (formerly "The Daily WTF") usually highlights terribly buggy code. Today's example is of the Code Smell "Duplicated Code". Three different versions of a visual basic function to return the numeric part of a string — from the same source file! Check it out.

    [/docs] permanent link

    2007.Mar.06 Tue

    Dot-Com Boom == Gold-Rush

    To the tune of "The Best Things in Life" from the movie musical Paint Your Wagon, set in the California gold-rush of 1848-1855: (Imagine that a self-important programmer in a dot-com startup has been lecturing that crappy, quickly-written code is the most important thing for the start-up's programmers to write.)

    This code is pure muck. (Muck's a good thing.)
    And oozing with bugs. (Bugs are just fine.)
    It's a big ball of mud. (Mud is good luck.)
    It's stuffed full of faults. (Faults are good signs.)

    The poor, they got hope;
    The rich can buy SOAP.

    The VCs bank-rolled our start-up,
    We'll cash out or we will pile-up,
    Some customers we will round-up,

    Just wanting to buy,
    our site they will try,
    Here's mud in your eye!

    The best code today is dirty,
    Advancing our dream is everything.

    The best code today is filthy dirty,
    Hunks of code, code, code.

    There's more than just code (Code is enough.)
    For our IPO (Bountiful code.)
    There's customer needs (Buckets of code.)
    We should try to meet. (Investable code.)

    A man has his creed,
    And mine is all greed.

    We will debug that code when we ship it,
    And code endless amounts of shit, it
    won't matter much 'til the stock split.

    Just code in the cache
    That turns in a flash
    To dirty ol' cash.

    The best code today is dirty,
    The worst thing today is—
    Writing code clean, now that is obscene.

    The best code today is filthy dirty
    Hunks of code, code, code,
    The best code today is filthy dirty
    The best thing today is
    Being hell-bent on making a cent.

    The best code today is filthy dirty
    Hunks of code, code, code, code
    Stinking, rotten, chunks of
    Grimy, slimy, lousy, lovely

    Code.

    Words by yours, truly, C. Keith Ray. (Note: I do not recommend writing crappy code in a startup situation, because that will slow you down more than writing good code would do.)

    [/docs] permanent link

    2007.Feb.21 Wed

    Worst Code Analogy Ever

    We've compared code to spaghetti, lava flows, architecture, and a big ball of mud, but this is the worst:

    "Software design is like cat pee. Cat's mark their territory by peeing on it, so when other cats come along they can smell that it belongs to someone already. Developers like to "pee" on the code to mark out their territory - and this means making their mark on the design." -- Jason Gorman

    I'm not saying this analogy is wrong -- all analogies are both right and wrong -- just that I'd rather focus on something positive. Kent Beck and others in describing XP, say that if a "design disagreement" goes on for more than 10 minutes, both parties should actually implement the bones of their designs and have the team compare the implementations, rather than continue to argue.

    By the way, check out the piano-playing cat:

    [/docs] permanent link

    2007.Feb.12 Mon

    On Test Driven Development

    I like to say that there's all sorts of ways to "do design". TDD happens to be a way that leaves behind a suite of regression tests -- which you would NOT get if you did design another way.

    For some people that's an "aha!" idea.

    For others, they shrug and say "well I can write the tests after" -- but very few people do. If you *always* write the tests after, then maybe you don't need TDD.

    The other aspect is that TDD helps force you to pay attention to design issues - object setup and interactions, code smells, decoupling and cohesion. This is perhaps more helpful to inexperienced "junior" developers. And helps scatter-brained senior developers (like me) focus on doing one thing at time instead of trying to do too much at once.

    If you're solo coding (not part of a team), and working on very small projects, and/or your code is throw-away-after-one-use, then TDD may not be necessary. In that context, you may not need TDD's (1) focused test/code/design process and (2) safety-net tests that TDD provides.

    [/docs] permanent link

    2007.Feb.06 Tue

    Make Test Automation a Priority If You Don't Already Have It.
    Johanna writes:

    "Notice that Guy assigned five of his top engieners and architects to the automated test framework. Testing in-process is hard work. If you don't have the ability to develop and maintain an automated test framework for your project, put your best people on it, as Guy did. You won't regret it."
    Check it out.

    [/docs] permanent link

    2007.Jan.31 Wed

    Test-Driving C++

    In most languages, when I'm using Test Driven Development to create a class, I only put into that class those methods or fields that I needed to pass a test. C++ has some exceptions to that, given how the compiler will generate aspects of a "canonical c++ class" for you.

    I should explain the idea of a "Canonical C++" class. Imagine that I have this code:

    class Buddy
    {
    public:
       Icon* myIcon;
       std::string myName;
    };
    

    Now, I didn't write a constructor, destructor, nor an assignment-operator, but the compiler did create those for me. It's as if I really wrote the following code:

    class Buddy
    {
    public:
        Icon* myIcon;
        std::string myName;
    
        Buddy() // default constructor
            : myName() // invokes std::string's default constructor
        { // myIcon is not initialized, it probably has a garbage value here.
        }
    
        Buddy(const Buddy& other) // copy constructor
            : myIcon( other.myIcon ) // copy the variable's value
            , myName( other.myName ) // invokes std::string's copy constructor
        { 
        }
    
        ~Buddy() // destructor
        {
        } // invokes std::string's destructor for myName.
    
        Buddy& operator=(const Buddy& other)
        { // assignment operator
            myIcon = other.myIcon; // copy the variable's value
            myName = other.myName; // call std::string's assignment operator
        }
    };
    

    A "canonical" C++ class has default constructor (and/or other constructors), copy constructor, destructor, and assignment-operator. These may be defined by the programmer or created by the compiler.

    And this invisible compiler-generated code can be wrong, particularly if ownership of pointers or other resources is involved. Let's say that I test-drive a default constructor that sets up myIcon to point to a newly-created Icon object, and write the corresponding destructor code to delete the Icon object. It's hard to verify the "state" of an object after its destructor is called ('cuz it's GONE), but there are a few tricks to verify the behavior of a destructor that I won't get into here.

    class Buddy
    {
    public:
        Icon* myIcon;
        std::string myName;
    
        Buddy()
            : myIcon( NULL )
            , myName( "no name" )
        {
            myIcon = new Icon(Icon::DEFAULT_ICON);
        }
    
        ~Buddy()
        {
            delete myIcon;
        }
    };
    
    SPECIFY_(Context,BuddyHasDefaultNameAndIcon)
    {
        Buddy* aBud = new Buddy;
        VALUE( aBud->myName ).SHOULD_EQUAL( "no name" );
        VALUE( aBud->myIcon ).SHOULD_NOT_EQUAL( NULL );
        delete aBud;
    }
    

    This test will pass. (by the way, I'm using "ckr_spec" here, a Behavior-Driven-Design framework I've written in C++ in my spare time. I'll publish more about ckr_spec one of these days.) However, this test doesn't exercise the compiler-created copy-constructor and assignment operators. AND THOSE ARE WRONG. Nothing (besides self-discipline) prevents anyone from writing the following (crashing) code:

    void crashingCode()
    {
        Buddy keith;
        Buddy keithClone(keith); // calls compiler-created copy constructor
        Buddy anotherKeith;
        anotherKeith = keith; // calls compiler-created assignment operator
    
    // destructors are called invisibly here - crash deleting the same Icon
    // object 3 times. (Also leaks an Icon object, too.)
    }
    

    The compiler-created copy constructors just copy the pointer to the Icon object. They don't create a NEW Icon object. So in "crashingCode" above, the Icon object created in the constructor of "keith" gets deleted three times, when the destructors for the "keith", "keithClone", and "anotherKeith" objects get called at the end of the function.

    Therefore, when I'm test-driving a C++ class, very early on, I make a decision. Is this a "value" class that is going support the copy-constructor and assignment-operator, or an "entity" class that should never be copied because the instance represents something with a persistent identity? (These are some over-simplified ideas from Domain-Driven Design.) I can change my mind later, of course.

    If my class is going to allow "value" semantics, then I'll need to write some tests to assure that the copy-constructor and assignment operator function correctly, whether I've written them, or the compiler has generated them.

    If I'm not going to allow "value" semantics, then I need to signal to the compiler and to my fellow programmer not to generate or use the copy-constructor and assignment-operator. Declaring them private and unimplemented is how to do that.

    class Buddy
    {
    public:
        Icon* myIcon;
        std::string myName;
    
        Buddy()
            : myIcon( NULL )
            , myName( "no name" )
        {
            myIcon = new Icon(Icon::DEFAULT_ICON);
        }
    
        ~Buddy()
        {
            delete myIcon;
        }
    
    private:
        Buddy(const Buddy& other); 
            // don't implement copy constructor
    
        Buddy& operator=(const Buddy& other);
            // don't implement assignment operator
    };
    // the crashingCode example will not compile now.
    

    For entity objects, quite often I don't want to allow the default constructor either, so I would declare that private and unimplemented as well.

    The moral of the story is that in C++, sometimes you have to write code to prevent the compiler from writing the code for you. Just add that to your TDD/BDD development process.

    [/docs] permanent link

    2007.Jan.29 Mon

    It's around here somewhere

    Late night, driving in unfamiliar territory. "It's around here somewhere; we just need to keep going in this direction." "Are you sure you didn't miss it?"

    In the age of GPS receivers, this conversation is going to become less and less frequent. I've been on a few software projects that had a similar feeling. One in particular was initially estimated as being a six-month project and ended up taking over a year (and it felt like two years.)

    The problem with that project was a lack of measurement - we could not objectively measure how much was left to be done. Also, false measurements - we were told the code was "working" when we started... and "just" needed to be ported.

    Kent Beck wrote: "Testing. You have to know when you're done. The tests tell you this. If you're smart, you'll write them first so you'll know the instant you're done. Otherwise, you're stuck thinking you maybe might be done, but knowing you're probably not, but you're not sure how close you are."

    [/docs] permanent link

    Does anyone Remember Binary Coded Decimal

    I learned about Binary Coded Decimal (BCD) in the 80's. (1980's!) Some CPUs had hardware support for it. The Motorola 680x0 series for sure, and I think the Z80/8080 processors. BCD represents decimal digits, one per 4 bits, like so: 978 = 0x0978. The PowerPC processor did not have it, but some versions of it supported "vector math" (aka "Altivec") which could do a kind of BCD with one decimal digit per 8 bit... 978 = 0x00090708.

    The only languages that supported BCD directly were COBOL, and (I think) the kitchen-sink language PL/1. People used to program in "subsets" of PL/1 kind of like many do today with C++ (that is, C++ without exceptions, or C++ without templates). Probably some versions of some databases will use BCD support if its available. But I digress.

    Somewhere, I read a breathless piece of prose saying that the "first ever" hardware support of decimal math was coming out soon. It's not the first ever. Of course, I don't have a link to that bit of misinformation, though I'm not sure I'd link to if I did have it.

    [/docs] permanent link

    2007.Jan.26 Fri

    Google Testing Blog

    Check out the Google Testing Blog. I particularly like the logo, which has an unhappy red light-bulb under "Debugging sucks" and a happy green light-bulb above "Testing rocks."

    The Google Testing Blog also introduces Testing on the Toilet. Quote:

    We write flyers about everything from dependency injection to code coverage, and then regularly plaster the bathrooms all over Google with each episode, almost 500 stalls worldwide. We've received a lot of feedback about it. Some favorable ("This is great because I'm always forgetting to bring my copy of Linux Nerd 2000 to the bathroom!") and some not ("I'm trying to use the bathroom, can you folks please just LEAVE ME ALONE?"). Even the Washington Post noticed.

    One comment on the Testing on the Toilet entry deserves a response. Joe#302 wrote "My point is that QA needs to have a bright line between it and development. [...] But the two should remain separate. Go to any mature industry's engineering department, and ask how much of the release testing is done or defined by the actual development engineers. [...] This is a sign of the immaturity of the software development industry."

    There are many successful projects where the testers and developers are members of the same team. There are also many unsuccessful projects where the testers and developers are not on the same team. The auto industry is pretty mature, and yet the dominant player has this to say in one of their web pages:

    The cornerstone of Toyota's quality control system is the role of the team members in the production process. The principles on which Toyota was founded are employed at the Georgetown plant.

    Toyota involves its team members by:

    • encouraging an active role in quality control,
    • utilizing employee ideas and opinions in production processes,
    • and practicing "kaizen" — striving for constant improvement.

    Toyota team members treat the next person on the production line as their customer and will not pass a defective part on to that customer.

    The Toilet entry has a number of comments employing certain metaphors. One them is in response to Joe#302. Major Tom wrote:

    To respond to Joe #302

    You're wrong. I'm a developer in a fortune 500 company and I test everything I do. By the time it goes to Alpha test, only field anomalies break my code. So to say "SDEs are not QAEs, and the distinction should not be blurred, if you want to maintain true quality." you're, well, full of crap. Your statements should be flushed. [...] I have 3000 sites with my software for over three years and have had 2 bugs related to errors on my part. Proper Software Engineering includes heavy testing during development.

    I also know of one company that spends Billions (Microsoft) on everything you stated, and well, let their end product speak for itself.

    [/docs] permanent link

    2007.Jan.23 Tue

    Groupware Bad

    Chris Hanson pointed to a nice little rant about the dangers of writing software to appeal to buyers (managers) rather than users. Groupware Bad by Jamie Zawinski. (warning: some profanity)

    [...] "So we've got this big pile of code we're going to release, and we're going to build an open source groupware system! It's going to be awesome!"

    "[...] what are you thinking! Do not strap the 'Groupware' albatross around your neck! That's what killed Netscape, are you insane?" [...]

    If you want to do something that's going to change the world, build software that people want to use instead of software that managers want to buy.

    When words like "groupware" and "enterprise" start getting tossed around, you're doing the latter. You start adding features to satisfy line-items on some checklist that was constructed by interminable committee meetings among bureaucrats, [...] that maybe some company will want to buy a hundred "seats" of, but that nobody will ever love. With that kind of motivation, nobody will ever find it sexy. It won't make anyone happy.

    So I said, narrow the focus. Your "use case" should be, there's a 22 year old college student living in the dorms. How will this software get him laid?

    [...] "Social software" is about making it easy for people to do other things that make them happy: meeting, communicating, and hooking up.

    Check it out.

    [/docs] permanent link

    2007.Jan.17 Wed

    Comet McNaught

    I keep forgetting to go outside and look for the very bright Comet McNaught. Check out this photo gallery.

    [/docs] permanent link

    Not Just Standing Up

    Check out Jason Yip's It's Not Just Standing Up: Patterns of Daily Stand-up Meetings. Quotes:

    More so than artificial “team-building” exercises, effective teams are built by regularly communicating, working, and helping each other. This is also strongly tied with team members helping each other with shared obstacles. [...]

    What do we talk about during the daily stand-up? [...]

    If we reconsider this in light of a focus on commitment, the questions might be re-worded as follows:

    • Was I able to fulfill what I committed to?
    • What am I comfortable committing to today?
    • What is obstructing me in meeting my commitments?

    [...] I tend to add a fourth question: “What might help or hinder others in meeting their commitments?”

    [...] maintain an information radiator [Cockburn, 2001] (aka Big Visible Chart) showing the iteration and release status and hold the stand-up near it.

    Blockage Board

    Post raised obstacles to a Blockage Board. This is a publicly visible whiteboard or chart that identifies raised obstacles and tracks the progress of their resolution. A Blockage Board can be updated outside of stand-ups and serves as a more immediate and perhaps less confronting way to initially raise obstacles.

    [/docs] permanent link

    2007.Jan.09 Tue

    Stickyness

    Guy Kawasaki interviews the authors of Made to Stick: Check it out.

    [/docs] permanent link