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


           
    2004.Dec.24 Fri

    The Story of the Graphing Calculator

    http://www.pacifict.com/Story/

    ... I used to be a contractor for Apple, working on a secret project. Unfortunately, the computer we were building never saw the light of day. The project was so plagued by politics and ego that when the engineers requested technical oversight, our manager hired a psychologist instead. In August 1993, the project was canceled. A year of my work evaporated, my contract ended, and I was unemployed.

    I was frustrated by all the wasted effort, so I decided to uncancel my small part of the project. I had been paid to do a job, and I wanted to finish it. My electronic badge still opened Apple's doors, so I just kept showing up. ...

    ... After a demo to outside developers, one person called Apple claiming that we infringed his patent, causing a fire drill until I could show prior art. Another company, the makers of Mathematica™, simply demanded that our product be pulled. Apple very politely declined. One week we were evading security, the next week Apple is rising to our defense...

    ... I view the events as an experiment in subverting power structures. I had none of the traditional power over others that is inherent to the structure of corporations and bureaucracies. I had neither budget nor headcount. I answered to no one, and no one had to do anything I asked. Dozens of people collaborated spontaneously, motivated by loyalty, friendship, or the love of craftsmanship. We were hackers, creating something for the sheer joy of making it work.

    [/docs] permanent link

    2004.Dec.18 Sat

    Kent Beck Test Talk

    Developer testing as driver of good design / "healthy software", and as a measure of accountability. http://www.itconversations.com/shows/detail301.html

    This presentation was recorded at the Developer Testing Forum held in Palo Alto, California, November 17th, 2004. Thanks to Agitar Software and the SDForum, the producers of the event.

    [/docs] permanent link

    2004.Dec.17 Fri

    Fitnesse Python

    I'm catching on reading the Fitnesse mailing list. Here's a page describing writing automated acceptance tests in PyFit: http://agiletesting.blogspot.com/2004/11/writing-fitnesse-tests-in-python.html

    [/docs] permanent link

    2004.Dec.10 Fri

    BayXP meeting Dec 15, Foster City CA

    Our guest speaker will be III (pronounced "three"), an authority on Chartering. Project Chartering is one of the practices of Industrial XP. III advocates chartering for providing a good beginning for a any project. He will present examples from chartering done at HP for their XP-SIG. Check out the paper he wrote on chartering here: http://industriallogic.com/papers/Chartering.pdf

    Project Chartering helps people answer questions like: Is the idea for the project worthwhile? How does the project further the organization's vision/mission? How would we know if the project is a success? Who is part of the project's Project Community?

    Badging is required, so please try to arrive early.

    Meeting Location:

    Offices of Electronics for Imaging, Inc.
    303 Velocity Way
    Foster City CA 94404

    Time: November 17th 7:00 PM mixing; 7:30 PM - 9:30 PM presentation

    [/docs] permanent link

    2004.Nov.24 Wed

    Reading Software

    We programmers read software much more often than we write it, but do we write for readability? Do we teach programmers how to read software?

    [/docs] permanent link

    Learning, Doing, Articulating

    Some people learn by doing. Some people (like me) learn by reading. I've been doing C++ for a long time, but I would say that I learned it by reading the C/C++ Users Journal and various books and other documentation. The parts of C++ that I learned "by doing" have to do with compiler limitations and library bugs.

    While the syntax and usage of a C++ is a fairly limited set of knowledge; good object-oriented design is much less limited. No set of books can cover everything, particularly not the compromises that often occur in real-world projects. So I've been learning OO by doing as well as by reading.

    The third stage is taking the implicit / tacit knowledge acquired by doing, and articulating it. Not just to teach other people, nor to prove to others that you've acquired this knowledge, but to examine and re-examine what you think you know.

    When asked questions about object-oriented design, I sometimes find it difficult to articulate everything that could or should be said... not because I don't know it, but often because something is so obvious to me that I would not think that I would need to mention that aspect.

    For example, many people avoid multiple-inheritance in C++, but when asked why, they just say it's "bad" or "dangerous". While there can be problems with "diamond" inheritance (where multiple parents of a class have a common parent), multiple inheritance isn't all bad. Being able to "mix-in" Observer/Observable functionality into specific "child" classes in your class hierarchy might be an appropriate use of multiple inheritance. An aspect of multiple-inheritance that I would consider too obvious to mention (but I'll mention here) is that it can't be changed at run-time... it's inflexible (and 'abusive' to the concept) if you're trying to use inheritance to implement aggregation. You're not going to decide at run-time whether to add Observable behavior to some object, but you may want to change or add other behaviors at run-time: appropriate patterns for that would be Decorator, Composite, Delegation, Strategy, etc...

    Because not everyone is at the "articulating" stage of knowledge, use auditions to evaluate programmers: pair-design and pair-program with the candidate on real-world problems, for example, keeping in mind that really good insights on various problems will take more than an hour or two...

    [/docs] permanent link

    2004.Nov.17 Wed

    BayXP

    The next meeting of BayXP will be Wednesday Nov. 17, 2004 (a week early to avoid Thanksgiving vacations). Jeff McKenna of www.netobjectives.com will be speaking informally on the planning game and retrospectives -- how they work together.

    Badging is required, so please try to arrive early.

    Time: November 17th 7:00 PM mixing; 7:30 PM - 9:30 PM presentation

    Meeting Location:

    Offices of Electronics for Imaging, Inc.

    303 Velocity Way

    Foster City CA 94404

    [/docs] permanent link

    2004.Nov.11 Thu

    Really Optimized Memory Allocation

    Travis Griggs tested memory allocation and freeing in C (no garbage collection versus automatic garbage collection) and Smalltalk. His test generates and frees 20,000,000 small objects, with only 1,000 of them being "live" at any time. His results:

    9.5 seconds: plain C allocing but never freeing [no gc]

    9.5 seconds: plain C with Boehm Garbage Collector

    1.0 seconds: Cincom VisualWorks Smalltalk

    This goes to show that 20 years of people improving Smalltalk's performance does add up. Unfortunately for C programmers, the fast algorithms used in "Generation Scavenging"(pdf) involve periodically copying small live objects from "new space" to "old space" -- this requires "fixing up" pointers to point to the new location, or the use of "handles" (pointers to pointers). The Boehm garbage collector is not going to fix up pointers, because it must assume that some piece of memory that looks like a pointer might actually be something else. [And C programmers have been known to copy pointers into int variables, etc.] A Java or Smalltalk environment can distinguish between object pointers and other things that may have the same bit-pattern as a pointer, so fixing up object pointers is safe.

    The speed of "Generation Scavenging" comes from the simplicity of allocating objects in "new space" -- just increment the pointer that marks the division between the used and un-used part of the "new space" heap (it's more like a stack that never has to be decremented.) In some systems (Sun's HotSpot Java VM?) there's one "new space" per thread to avoid having to synchronize heap access across multiple threads. When the "new space" is filled up, do garbage collection and move "live" objects to "old space" heap (fixing up pointers or handles as needed). Most objects in Smalltalk have short lifetimes, so very few objects are copied. Then reset the "new space" pointer to clear the "new space" heap. Less often, do garbage collection to free up objects in the "old space" heap.

    By the way, when I worked at Apple, I improved the performance of malloc/calloc/free in the standard-C library that shipped with (and was used by) the MPW environment and the MrC and MrCpp compilers. Simplifying the code and tuning how it did allocations of small objects improved the speed of the compilers by 5% or more. The changes I made to that library are still shipping in "Classic" MacOS.

    [/docs] permanent link

    2004.Nov.09 Tue

    Debate instead of Dialog 2

    More advice for dealing software people: if you offer an idea or suggestion to "debaters" (see previous blog entry), and they poke a dozen holes in it, that means that they're interested in it. Try to imagine that they are trying to help you, because many times this is their way of doing that.

    To move from debate into dialog, ask them to how to resolve one of the problems they just brought up. This will (if they are interested) switch their mode to "problem-solver", which is one of their favorite modes.

    [/docs] permanent link

    Debate Instead of Dialog

    Many people in the software biz respond to an attempt at conversation with a rebuttal. This isn't dialog, it's debate. It's one of the reasons software developers have developed a reputation for poor social skills. Do you do this? Here's a symptom: your replies to someone else often start with the word "but". Examples:

    Dialogger: "It was raining this morning."

    Debater: "But it's not raining now."


    Dialogger: "We could have found this bug a long time ago if we had written a unit test for [some condition]."

    Debater: "But unit tests can't find all bugs."


    By starting with "but", you don't give credit to the other person for their idea, even if you agree with it. Try restating their ideas before responding with your ideas or disagreements.

    [/docs] permanent link

    2004.Nov.02 Tue

    Hard to be re-usable?

    There is a meme going around that it is "an order of magnitude more difficult" to write a class that is "re-usable". That didn't seem right to me, so I decided to list the rules one could follow to write re-usable classes. Once I got up to about nine or ten rules, I decided that it might not be as simple as I thought. Still, compared to all the rules one must know to write safe C++ code, these rules are not that hard. The following list isn't numbered the way I originally wrote them -- it's 7 rules here, but at some point you get into the rules of good design, the rules for using C++ or Java or whatever robustly, etc. so you could go further and make the list longer.

    By the way, writing code test-first tends to make code much more re-usable, because the code is "used" at least twice - one or more times in the tests, and one or more times in the production code. Note: the previous statement is an understatement. If you as the 're-user' have access to the source code, and can refactor code as needed, then you don't have to follow all these rules initially. For example Rule 6 below doesn't need to be followed unless you determine that you need to do this to make re-use work, then you can refactor to make it work.

    One obstacle to re-use is class dependencies and package dependencies. Once upon a time, I wanted to use a particular Java class, but it used so many other classes in the same package, that I was forced to add the entire package to my project. But that package used classes in a bunch of other packages. In order to use that single class, I would have had to include at least six packages and a hundred classes in my project. So...

    Re-use Rule 1: Write your class to avoiding depending on other classes (etc). Obviously that can't always be done. Rule 1a: Try to use only the "basic" classes that everyone uses. More rules to come also address problems that contribute to being forced to grab a lot of classes just to use one class. Rule 1b: avoid writing "too-big" classes and "too-big" packages.

    Re-use Rule 2: a class should have one responsibility, delegating other responsibilities to other classes. Ditto for packages. Symptoms of having too many responsibilities are groups of methods that each only deal with isolated member variables, and having lots of private (or protected) methods. Symptoms of too-big packages are classes that don't depend on other classes within the package. Classes that are unrelated to whatever "concept" the other classes implement. Packages named "misc". Just because a bunch of classes implement an interface or subclass from a certain class, it doesn't necessarily mean that they belong together in the same package, or even belong in the package in which the interface or parent class resides.

    Re-use Rule 3: a class should not depend on other concrete classes [except the most basic types like String]. By using interfaces or abstract classes as the "type" of member variables / return values / arguments to methods and constructors, we enable easier re-use (and testing): instead of the passing in the concrete types that were expected, we can pass in new concrete types useful in the new "re-use" context. Take advantage of the power of polymorphism and all that (or at least don't prevent others from doing so). Dynamic languages like Python, Smalltalk, Ruby and so on, which don't declare the types of variables, don't have this problem.

    Re-use Rule 4: To implement rule 3 and to avoid circular package-dependencies (and to allow re-use without dragging in lots of packages), the interface, the class using that interface, and the concrete classes that implement that interface, probably need to reside in three different (and fairly small) packages. Package design regarding interfaces and concrete classes isn't discussed in many places, but it is discussed in Robert Martin's book "Agile Software Development".

    Re-use Rule 4: to further allow substitution of concrete types, avoid using "new ConcreteClass" within your class -- particularly the constructors. If you do need to create objects of particular types (instead of having those objects passed into methods and constructors), put the "new" call into a "creation method". This allows the re-user of that class to override that method to instantiate a different kind of object. This is useful for creating Mock objects in unit-tests.

    Re-use Rule 5: the user of your class may want to subclass-and-override. Make that possible by avoiding static, final, or non-virtual methods, and private methods. Private methods either need to be declared protected, or should be moved to another class and made public, with the original class using an instance of that other class.

    Re-use Rule 6: You can make member variables protected, or make member variables private. If you make them private, you should implement protected (or, if absolutely necessary, public) accessor methods to get/set the member variables. A subclass can override those accessor methods to extend or modify behavior associated with getting/setting, including returning different objects. If you go this route, then no method or constructor should ever access those private variables directly except the accessor methods themselves.

    Re-use Rule 7: In event that re-use of your class would involve overriding ALL of the methods, and ignoring ALL of the member variables, declare an interface and make your class implement that interface. Now instead of overriding every method in your class, the re-user can make their own implementation of your interface.

    C++ makes following some of these rules difficult. For example, in a constructor, method calls to virtual functions act like the method is not declared virtual. In the constructor of class "Parent", calls to virtual accessor methods to set member variables will not invoke overriding accessor methods implemented in class "Child." In this case, you would need to do the work of setting member variables via virtual accessor methods in an "Initialize" method, which must NOT be called from the constructor. For example: "Parent* obj = new Child; obj->Initialize();". Don't forget to declare destructors virtual. C++ allows declaring argument types "by value" as well as "reference" and "pointer". "By value" doesn't allow polymorphism because it creates a new object of the declared type on the stack, possibly copying only a subset of the members from a sub-class object passed into that method call.

    Following all of these rules all of the time may create ugly code. Make classes re-usable "as needed". Develop test-first so that you can later refactor classes for re-use at any time, protected from unintended bugs by suites of unit tests. There is a concept for class hierarchies of "Object-Oriented Normal Form" in Michael Feather's book "Working with Legacy Code" summed up by the rule: "No child class's methods override any parent class's concrete methods." Any time you would be tempted to do that, you instead restructure the inheritance hierarchy, adding abstract classes or interfaces so that you only override unimplemented abstract/interface methods ("pure virtual" methods in C++.)

    Here's an example of following these rules in C++:

    
    class Region   // the "not very re-usable" version of this class
    {
    public:
        Region();
        Region( Rect shape ); // "by value" argument  
        ~Region();  // not virtual, making subclassing dangerous
        void Clear(); // not virtual, can't be overridden.
        void Union( Rect anotherShape );
        void Intersect( Rect anotherShape );
        Bitmap ConvertToBitmap();
    private:
        Bitmap myBitmap;
    };
    
    // Now the more re-usable version...
    
    class RegionInterface
    {
    public:
        virtual ~RegionInterface();
        virtual void Clear();
        virtual void Union( const RectInterface& );
        virtual void Intersect( const RectInterface& );
        virtual BitmapPtr ConvertToBitmap();
    };
    
    //BitmapPtr is a smart pointer declared something like this:
    //typedef std::auto_ptr < BitmapInterface > BitmapPtr;
    
    class Region : public RegionInterface
    {
    public:
        Region(); 
        virtual ~Region(); // "virtual" necessary for "delete (RegionSubclass*) obj" to work right.
        virtual void Initialize( const RectInterface & ); // because we can't call virtuals in the ctor
        virtual void Clear();
        virtual void Union( const RectInterface& );
        virtual void Intersect( const RectInterface& );
        virtual BitmapPtr ConvertToBitmap();
    protected:
        BitmapPtr GetBitmap() const;
        void SetBitmap( BitmapPtr );
    private:
        BitmapPtr myBitmap;
    };
    
    

    Note that doing

        Region* reg = new Region;
        reg->Initialize( aRect );
    

    more than once in the code-base is repeated code [a bad thing], so you would want to put those two lines into a creation-function (probably a static method in class Region). I've also left out copy constructors and assignment operators.

    One last aside... look above at how much "overhead" C++ requires. In dynamic languages like Smalltalk, the only difference between the "less re-usable" class and the "more re-usable" class would be the addition of the accessor methods (which I understand Smalltalkers do by habit already.) Here's the same example in a dynamic "c-ish/pascal-ish" language I just made up:

    class Region   // the "not very re-usable" version of this class
    {
    public:
        ctor Region();
        ctor Region( shape );
        proc Clear(); // not virtual, can't be overridden.
        proc Union( anotherShape );
        proc Intersect( anotherShape );
        func ConvertToBitmap();
    private:
        var myBitmap;
    };
    
    class Region // more re-useable version 
    {
    public:
        ctor Region();
        ctor Region( shape );
        proc Clear(); // not virtual, can't be overridden.
        proc Union( anotherShape );
        proc Intersect( anotherShape );
        func ConvertToBitmap();
    protected:
        func GetBitmap() const;
        proc SetBitmap( aBitmap );
    private:
        var myBitmap;
    };
    
    

    If you developed test-first, you would have pretty much the same set of tests for this class in a dynamic language as you would in a static language, but much less overhead text.

    [/docs] permanent link

    2004.Oct.15 Fri

    Presidents and Stock Market

    Is there a pattern to stock market activity relative to who is president? I got year-end Dow Jones numbers from this web-site (http://www.cfainstitute.org/pressroom/overview/cfa40yr_timeline.html) and graphed them. The only pattern I've noticed is that for most presidents (Nixon, Ford, Carter, Reagan, GWBush), the Dow ends lower after their first year in office. The numbers and graphs are here: http://homepage.mac.com/keithray/dowJonesPresidents.xls.pdf

    [/docs] permanent link

    2004.Oct.12 Tue

    Books To Read

    I've gotten a back-log of books to read, with more arriving Real Soon Now. If you're developing software in Java, C++, C#, or some other object oriented language, you need to buy these books for your professional toolkit.

    Refactoring to Patterns by Joshua Kerievsky

    Working Effectively with Legacy Code by Michael Feathers

    JUnit Recipes: Practical Methods for Programmer Testing by J.B. Rainsberger and Scott Stirling

    Pragmatic Version Control Using CVS by Dave Thomas and Andy Hunt

    Pragmatic Project Automation: How to Build, Deploy, and Monitor Java Apps by Mike Clark

    Pragmatic Unit Testing in Java with JUnit by Dave Thomas and Andy Hunt

    Pragmatic Unit Testing in C# with NUnit by Dave Thomas and Andy Hunt

    Extreme Programming Adventures in C# by Ron Jeffries

    In a completely different area, I recommend this as well: Moral Politics : How Liberals and Conservatives Think by the cognitive linguist George Lakoff.

    [/docs] permanent link

    2004.Oct.09 Sat

    Knowledge Creation Activity

    Writing software to do something that hasn't been done before is a knowledge creation activity. In many respects, it is like artistic creation. And therein lies the rub. Artistic creation is a messy activity involving trying some things and throwing away the things that don't work. Inspiration does not respect age or seniority. Sparks fly from collaborative agreement and disagreement, but not from command-and-control.

    Can you imagine a group of people composing music in an hierarchical chain of command: a chief composer, with middle-manager-composers, and squads of junior composers? "Sorry boss, we tried to make the eighth-note triplets work like your plan, but the rhythm's off." The boss replies: "You gotta make them work. We have a schedule, and the base line needs to be integrated with your part by the end of this week -- and we don't have time to do it over."

    Of course, writing software isn't just like writing music, nor is it just like anything else that isn't writing software. In some environments, doing things that are very similar to what has been done before, a team can create or customize software predictably and without much fuss. Still, even on those projects, on the level of an individual's or pair's effort for any one hour, there will probably be some creativity, some trying things, some throwing away of ideas that don't work, some sparks and inspiration.

    [/docs] permanent link

    2004.Sep.30 Thu

    Paper on Dynamic Languages

    Good paper - Dynamic Languages-ready for the next challenges, by design by David Ascher. Note that Smalltalk is one of the first dynamic languages, and lives on in multiple commercial and open-source versions. And don't forget Objective-C, which was initially commercial but now is open-sourced. [Aside: why don't the maintainers of gcc take the changes that Apple made to support their blend of Objective-C and C++? Apple made the changes available, but the gcc people didn't integrate them.]

    [/docs] permanent link

    2004.Sep.23 Thu

    Reasons to do Unit Testing / TDD / Automated acceptance tests

    1. There are studies/statistics that say unit testing finds 70% of the defects.

    2. A unit test provides an example of what a piece of code is supposed to do. Going through the code in the debugger only tells you what it is doing, not what it is supposed to do.

    3. You can run hundreds of unit tests in the same amount of time it takes to go through one function in the debugger.

    4. Unit tests as change-detectors - you've changed one line of code in a million-line system. Did you break anything? Run the automated unit and acceptance tests and find out. (If you've done strict TDD, your tests have nearly 100% code coverage.)

    5. Unit tests as documentation -- multiple examples of what the code is supposed to do, and how it should handle failures.

    6. Test-driven development is a thinking/designing process that happens to leave you with a bunch of tests. You can do the same thinking/designing process without TDD, but you don't end up with any tests.

    7. Exploration. You can try out an unfamiliar API in a test, preserving a record of what that API does (and notifying you later if the API's behavior changes.)

    8. Making code testable improves its design - making it more modular and encouraging you to make it more cohesive.

    Given all these points (especially points 1 and 4), why would any company that is trying develop software to satisfy customers demands allow its programmers to NOT do unit testing and automated acceptance testing?

    [/docs] permanent link

    2004.Sep.18 Sat

    Links - Advice To Managers, Lean Development

    Jerry Weinberg's Advice for Software Development Managers.

    Mary Poppendieck on increasing productivity [profits], quality and speed archived web-interview and slides.

    [/docs] permanent link

    2004.Sep.17 Fri

    Project Censored

    Top 25 new stories of 2003-2004 that you didn't see: Project Censored.

    (#4) High Uranium Levels Found in Troops and Civilians quotes:

    Uranium is a chemically and radiologically toxic element, clinically proven to be a cause of various types of cancer and congenital malformations (birth defects). Internal contamination of uranium is responsible for variety of systemic and organ system problems [...].

    Most American weapons (missiles, smart bombs, dumb bombs, bullets, tank shells, cruise missiles, etc.) contain high amounts of radioactive uranium. Depleted or non-depleted, these types of weapons, on detonation, release a radioactive dust which, when inhaled, goes into the body and stays there.[...]

    [...] because radioactive contaminants from uranium weapons travel through air, water, and food sources, the effects of U.S. deployment in Afghanistan will be felt in Iran, Pakistan, Turkey, Turkmenistan, Uzbekistan, Russia, Georgia, Azerbaijan, Kazakhstan, China and India. Countries affected by the use of uranium weapons in Iraq include Saudi Arabia, Syria, Lebanon, Palestine, Israel, Turkey, and Iran.

    Uranium is preferred over all other "ballistic" metals [...] because it offers a set of unique metallurgical properties: it is extremely dense yet ductile metal[...] uranium dust burns spontaneously at room temperature [...]. Uranium metal has a very unusual property not available in any other metal; it is "self-sharpening", meaning that when it hits a target at high velocities (1 km/sec) it erodes and breaks in such a way as to continuously re-sharpen its point[...].

    In 2003 scientists from the Uranium Medical Research Center (UMRC) studied urine samples of Afghan civilians and found that 100% of the samples taken had levels of non-depleted uranium (NDU) 400% to 2000% higher than normal levels. The UMRC research team studied six sites, two in Kabul and others in the Jalalabad area. The civilians were tested four months after the attacks in Afghanistan by the United States and its allies.

    NDU is more radioactive than depleted uranium (DU), which itself is charged with causing many cancers and severe birth defects in the Iraqi population–especially children–over the past ten years. Four million pounds of radioactive uranium was dropped on Iraq in 2003 alone. Uranium dust will be in the bodies of our returning armed forces. Nine soldiers from the 442nd Military Police serving in Iraq were tested for DU contamination in December 2003. [...] the test found that four of the nine men were contaminated with high levels of DU, likely caused by inhaling dust from depleted uranium shells fired by U.S. troops. [...].

    Sgt. Hector Vega, Sgt. Ray Ramos, Sgt. Agustin Matos and Cpl. Anthony Yonnone from New York's 442nd Guard Unit—they are the first confirmed cases of inhaled uranium oxide exposure from the current Iraq conflict. Dr. Asaf Durokovic, professor of Nuclear Medicine at the Uranium Medical Research Centre http://www.umrc.net/ conducted the diagnostic tests. The story was released April 3, 2004 in the New York Daily News. There is no treatment and there is no cure. [...]

    [...] Today, more than 240,000 Gulf War veterans are on permanent medical disability and more than 11,000 are dead. They have been denied testing, medical care, and compensation for depleted uranium exposure and related illnesses since 1991.

    [...] Even worse, they brought it home in their bodies. In some families, the children born before the Gulf War are the only healthy members. Wives and female partners of Gulf War veterans [...] are now internally contaminated from depleted uranium carried in the semen of exposed veterans. Many are reporting reproductive illnesses such as endometriosis. In a U.S. government study, conducted by the Department of Veterans Affairs on post-Gulf War babies, 67% were found to have serious birth defects or serious illnesses. They were born without eyes (anophthalmos), ears, had missing organs, missing legs and arms, fused fingers, thyroid or other organ malformations.

    [/docs] permanent link

    2004.Aug.29 Sun

    Jigsaw Puzzle Exercise

    To illustrate to managers/executives the differences between waterfall, code-n-fix, and iterative/incremental development...

    Prepare for the demonstration by buying three small jigsaw puzzles. Assemble two of them, and turn them over (while still assembled.) For the puzzles that represent waterfall and iterative/incremental development, find groups of three connected puzzle pieces and label them as follows: "requirements 1", "code 1", and "tests 1" for the first set of three. "Requirements 2", "code 2", and "tests 2", and so on for an adjacent set of three pieces, and so on. Make sure that not all of "requirements" pieces are directly connected to other "requirements" pieces, etc. Now it should be easier to put together these puzzle again... but that's not all.

    To dissemble the puzzles... For the "waterfall" puzzle: put all of the "requirements" pieces in one bag, all of the "code" pieces in a second bag, and all of the "test" pieces in the the third bag. For the "iterative/incremental development puzzle" you'll need lots of little bags, one for the "1" pieces, one for the "2" pieces, and so on. Label each of the bags (or use little little tiny ziplock bags that you can see through).

    Now for the exercise with the managers/executives. Divide them into three groups. Their assignments are to put together a puzzle within a time limit (say 20 minutes). The group that gets done first is the winner, or the group that has the most contiguous pieces assembled.

    For the "waterfall group", give them all of the "requirements pieces" immediately, wait 5 minutes, and then give them the "code" pieces, wait another 5 minutes, and then give them all the "test" pieces.

    For the "iterative/incremental development group," give them the first bag immediately, give them the second bag as soon as they've assembled the pieces from the first bag, and so on.

    For the "code-n-fix" group, give them the puzzle that you haven't marked up... maybe withholding a few random pieces to make it a little more challenging. ;-)

    If you need strict scoring conditions, each connected piece counts as 1 point. Each missing piece from within a group of connected pieces subtracts 1 point. If there are more than one group of connected pieces, subtract 1 for each group besides the first.

    Being JustaProgrammer, (and being poor at jigsaw puzzles) I haven't (yet) done such an exercise. I offer this exercise on a non-exclusive license to anyone who wants to try it, with the requirement that you send me a description of how this worked out in practice.

    I apologize for not blogging lately. Things are busy at work. My laptop was having problems and I spent some time transferring files from the old one to the new one. My dog ate my homework. :-) I'll be back to the test-first "From Model to Model-View-Controller" paper real soon.

    [/docs] permanent link

    2004.Aug.09 Mon

    typo correction

    correction for string-list

    typedef std::list<std::string> StringList;
    

    [/docs] permanent link

    2004.Aug.08 Sun

    Part 1 - Test Driven Development from Model to Model-View-Controller

    This is an example of test-driven development. We're going to implement a simple calculator object test-first and hook it up to a user-interface. First thing we need to do is #include the test framework. I'm using my version of Michael Feather's CppUnit.

    #include "TestDrivenDesign.h"
    #include <string>
    #include <list>
    

    Now define our first test. I like to put these into a namespace.

    namespace SimpleCalcTests
    {
        DECLARE_TEST(CalcDisplayStartsEmpty);
        DECLARE_TEST(CalcHistoryStartsEmpty);
    
        DEFINE_TEST(CalcDisplayStartsEmpty)
        {
            SimpleCalc aCalculator;
            assertStringsEqual( "", aCalculator.GetDisplay() );
        }
    
        DEFINE_TEST(CalcHistoryStartsEmpty)
        {
            SimpleCalc aCalculator;
            StringList astringList = aCalculator.GetHistory();
            assertLongsEqual( 0, astringList.size() );
        }
    
        TestSuite* Suite()
        {
            TestSuite* result = new TestSuite("SimpleCalcTests");
            result->addTest( new SimpleCalcTests::CalcDisplayStartsEmpty );
            result->addTest( new SimpleCalcTests::CalcHistoryStartsEmpty );
    
            return result;
        }
    }
    

    So I've decided that a calculator has a display representable by a string, and a history that is a string-list. In order to get this to compile, I better define the minimal classes required. Normally you only implement one test at a time, but these are two very simple tests. Slow C++ compile-link-run turn-around-time tends make you want to batch things up. Be careful to keep the batches small.

    typedef std::list StringList;
    
    class SimpleCalc
    {
    public:
        SimpleCalc()
        {
        }
    
        virtual ~SimpleCalc()
        {
        }
    
        virtual std::string GetDisplay() const
        {
            return "display";
        }
    
        virtual StringList GetHistory() const
        {
            StringList result;
            result.push_back( "history" );
            return result;
        }
    };
    

    Note that the initial implementations of GetDisplay() and GetHistory() are going to make the test fail. That is intentional; I want the tests to inially fail in order to test the tests . I also initially wrote a single test, but changed it to two tests, so that each test only tests one thing. It's too easy to get false negatives or false positives if a test is testing multiple things. If you can't do the "right thing" when things are simple, what's going to make you do the right thing when thigns are more difficult.

    And why did I make the destructor and other methods virtual? First, it's a habit I've developed - if there is inheritance and the destructor and other methods are not virtual, you can get certain bugs that can be hard to debug. Second, I'm doing Object Oriented Programming. Polymorphism is a big part of that, and C++ does run-time polymorphism by declaring things virtual. Third, NOT declaring a destructor or a method virtual is a form of optimization... and optimizing code before you have hard evidence that it needs it is "premature optimization". Just don't do it.

    I also need to declare a test-runner and main function...

    int main (int argc, char * const argv[]) 
    {
        TestRunner calcTests("CalcTests");
        calcTests.addTest( SimpleCalcTests::Suite() );
        calcTests.runAllTestsOnce();
    
        return 0;
    }
    

    Here's the output from this code so far:

    TestSuite start CalcTests
        TestSuite start SimpleCalcTests
            TestCase CalcDisplayStartsEmpty...  AssertionFailedError 
                'expected: '' but was: 'display'', line 77, 
                file 'simplecalc/main.cpp'
                AssertionFailedError 
                FAIL 0 seconds
            TestCase CalcHistoryStartsEmpty...  AssertionFailedError 
                'expected: 0 but was: 1', line 85, 
                file 'simplecalc/main.cpp'
                AssertionFailedError 
                FAIL 0 seconds
        TestSuite end SimpleCalcTests
    TestSuite end CalcTests
    
    !!!FAILURES!!!
    Test Results:
    Run:  2   Failures: 2   Errors: 0
    There were 2 failures: 
        1) line: 77 simplecalc/main.cpp "expected: '' but was: 'display'"
        2) line: 85 simplecalc/main.cpp "expected: 0 but was: 1"
    

    This output is a little verbose because at various times using this test-suite I have needed to see where crashes were occurring (thus output about which suite and test are beginning to run and finishing running) and where slow code/tests were. Yes, I do care about code-speed, but I measure before I optimize.

    Now that I have the tests failing, time to make them pass. In this case, by permitting the display string to get empty and the history list to be empty. I'll demonstrate the use of a test-suite. (TestRunner is a sub-class of TestSuite, by the way.)

    class SimpleCalc
    {
    public:
        [other code unchanged ...]
    
        virtual std::string GetDisplay() const
        {
            return "";
        }
    
        virtual StringList GetHistory() const
        {
            StringList result;
            return result;
        }
    };
    

    Here's the output of the passing tests. It's much more succinct.

        TestSuite start CalcTests
            TestSuite start SimpleCalcTests
                TestCase CalcDisplayStartsEmpty...  0 seconds
    			TestCase CalcHistoryStartsEmpty...  0 seconds
    		TestSuite end SimpleCalcTests
    	TestSuite end CalcTests
    	OK( 2 tests)
    

    Part two will get into the meatier part of the calculator.

    [/docs] permanent link

    2004.Aug.07 Sat

    tips for venting "computer rage"

    If your robot or computer is giving you trouble (quote from Douglas Adam's Sirius Cybernetics Corporation song: And when it breaks down
    Or starts to annoy
    Or grinds when it moves
    And gives you no joy
    Cos it's eaten your hat
    Or had sex with your cat
    Bled oil on your floor
    Or ripped off your door
    ), just pick some of Dr. Smith's robot insults to describe the robot or computer to your satisfaction: http://www.geocities.com/SunsetStrip/Towers/3332/smith.html. Here are a few good ones:

    Arrogant Automaton
    Automated Oaf
    Blundering Bag of Bolts
    Computerized Clod
    Cybernetic Simpleton
    Digitised Dunce
    Hulking Mass of Mechanical Ignorance
    Mechanized Misguided Moron
    Obsolete Piece of Scrap Metal
    Sorry Specimen of Computerhood
    Traitorous Tin-Plated Fugitive from a Junkyard
    Traitorous Transistorized Toad
    Worthless Electronic Scrapheap
    Tyrannus Thesaurus
    

    [/docs] permanent link

    2004.Aug.06 Fri

    Engineering

    I would say that most people think "engineering" as designing using mathematical principles -- a [1] structural engineer who uses equations from handbooks to verify that the building the architect designed won't fall down. [2] Or a chemical engineer who uses equations from handbooks to verify that X amount of heat will be generated from a chemical process that takes in W and Z amounts of various chemicals that will be used in a factory to create certain plastics. [3] The "Army Corp of Engineers" is mostly seen as building dikes and bridges, not as designing solutions.

    To argue that software development is engineering will result in arguing whether any mathematical principles apply to the design, to what extent, and also bring in confusion about manufacturing and construction, and reinforce waterfall notions of design, then implement, then test. While there certainly are some mathematical principles involved in computer science, that isn't the problem we have in developing software.

    To instead argue that software development is a cooperative "game" in creating and deploying "knowledge" and various people-oriented practices help make that work (which allows talking about getting customers, testers, and developers talking instead of writing documents, and inverting design-implement-test waterfall to XP-style test, then implement, then design) gets the conversation away from arguing about definitions on "engineering" that neither participant really understands (and analogies to construction that really don't apply).

    In my examples 1,2, and 3, the "engineer" doesn't need to talk to "customer" much at all. In [1], the architect talks to the customer so the structural engineer doesn't have to. In [2], there probably is some direct communication, but possibly not if a "plant process designer" has just delegated some work to the chemical engineer. In [3] the conversation is limited to "stop this river from flooding this subdivision" or "get those tanks across that river" -- the amount of "knowledge" to be generated is very limited compared to the literally millions of decisions necessary to have a team write a million lines of source code.

    [/docs] permanent link

    2004.Jul.31 Sat

    Burn Charts

    Alistair Cockburn's chapter on project-tracking using burn-up charts, burn-down charts, "iceberg lists", and earned-value: http://alistair.cockburn.us/crystal/articles/evabc/earnedvalueandburncharts.htm

    [/docs] permanent link

    2004.Jul.27 Tue

    Bad APIs 2

    An alternative implementation of the function alloc(size_t size) could be defined to return a pointer to a block of memory that has the size at the front of it. In fact, this is how many implementations of these library functions are implemented -- but it wasn't standardized, and it wasn't made typesafe -- on those implementations where this was done, alloc would return a pointer to the data portion of the block, and you would have to "back up" and typecast the pointer to get the length portion of the block. A semi-typesafe example:

    struct MemoryBlock
    {
        size_t         block_size;
        unsigned char  block_data[];   // unbounded array
    };
    
    MemoryBlock* Alloc( size_t sizeIn );
    
    void Free( MemoryBlock* blockIn );
    

    While this has the benefit of less space on the "client" side of the function (retaining one pointer instead of a struct with two fields) the danger of this style is that heap corruption is more likely - bad code writing past either end of the data field can erase those block_size fields.

    Consider all the debugging tools we have today - would we need Purify, SmartHeap, and all those other tools as much if library functions like alloc and free had been implemented in a more object-oriented fashion?

    I'm currently trying to debug some code (not written by me) that mixed C and C++ memory-management: it used "free" on memory allocated by "new char[]" and "delete []" on memory allocated by "alloc". I think these functions were smart enough not to work with memory that the other set of functions allocated, so there were memory leaks. In some implementations, these functions might be safely interchangeable for non-object allocations, in other implementations you can expect crashes.

    So I fixed the code to be consistent, but I'm also getting crashes because some C++ objects are being deleted more than once [messing up the heap]. Apple's DebugMalloc provides some help in determining when the heap is messed up, but the irony is that DebugMalloc's leak detection feature works by implementing a form of garbage collection - it reports a leak when a memory allocation is no longer being pointed to. If I had real garbage collection, (or if the original coder had used boost::shared_ptr) I wouldn't have to worry about double-deletes.

    [/docs] permanent link

    2004.Jul.26 Mon

    BAd APIs

    Bad APIs start at the very beginning. For example, the C function alloc(size_t size) - a function to allocate memory in the heap - creates a block of memory; but what does it return? Not a data-structure describing the block, but half of that information, just the pointer. Imagine what could have happened if that function has been defined correctly:

    struct MemoryBlock
    {
        char*  block_start;
        size_t block_size;
    };
    
    MemoryBlock Alloc( size_t sizeIn );
    
    void Free( MemoryBlock * blockIn );
    

    If these two pieces -- pointer and length -- were always kept together, then other data-types implemented in C, like strings could have been safer...

    
    void StringCopy( MemoryBlock* destString, MemoryBlock* sourceString );
    
    

    [/docs] permanent link

    2004.Jul.20 Tue

    sustainable improvements

    Eventually, every programmer has to learn to make sustainable improvements in code that maintain or improve the goodness of its design, rather than unsustainable "patching" of code, which degrades the goodness of its design.

    Someone complains that members of his team are patching code instead of improving it, and therefore Extreme Programming isn't "scalable". The fact is, this lesson about the inappropriate use of "patching" is something that needs to be learned even if the team isn't doing XP. If it is doing XP, they are going to learn this lesson more quickly and more obviously than they would in a non-XP environment: their velocity is going to slow down over time until they can't create any new user-value within a single iteration. They will be forced to start refactoring ("refactoring" means improving the design of the code, not "rewriting" as many people seem to think). It seems that many if not most first-time XP teams have to learn the importance of refactoring from experience.

    [/docs] permanent link

    Flu

    How do people know when a chicken or some other bird has avian flu? Does it get a runny beak? Can chickens sneeze?

    [/docs] permanent link

    2004.Jul.13 Tue

    Notes From the WWDC Keynote (seen on video)

    WWDC 2004 - 3500 developers attending - 17% increase over last year

    Apple Stores - started 3 years - now have 80 stores

    20 million visitors per year

    250 million $ sales of third-party software

    ginza store in tokyo

    itunes music store - 70% market share for legal downloads, europe 62% of sales, 700,000 songs

    ipod = 50% market share by units sold

    airport express & airtunes - rendezvous for your home stereo - lossless compression and encryption - itunes streaming to target base station

    BMW - 3 series, minicoopers, etc., dealer-installed connection for ipod (in glove box) and car stereo/stereo-controls.

    all powermacs are dual processor now.

    1.25 gigahertz bus - faster than pcs

    ibm = 2.0 to 2.5 gigahertz - 25.% increase

    intel = 3.2 to 3.6 gigahertz - 12% increase

    LCD displays - competitors buy the panels that apple rejects

    20-inch, 23-inch aluminum, connect to pcs, macs, powerbooks, and 30-inch aluminum (g5 only with special video card using two dual-dvi connections). G5 can drive two 30-inch displays - 8 million pixels (single display) 2500x1600 4.1 million pixels 77% more than the 23-inch, $3299 ; all have dual firewire and usb ports built in - single cable that splits, dvi connection.

    panther - pixlet? - 12 million users - 50% of installed base - no other "new OS" has this many users, - 12,000 applications "transition is now over"

    industry has had only three major OS transitions so far

    apple II to MacOS 1984

    DOS to Win95 - 1995

    MacOS to MacOS X - 2000

    Win95 +etc to Longhorn - 2007

    microsoft office 2004 - "better than windows version"

    borland - java tools

    quark

    oracle - 10g database

    peoplesoft

    sun - java tools

    alias - bob bennet - maya complete - 25% of maya sales are for mac - alias sketchbook pro - 70% of downloads are for mac - maya unlimited "cloth, hair, fluid" effects used in games and movies - Lord of the Rings

    MYST IV - Revelation - simultaneous release on Mac and PC - music by peter gabriel

    guitar rig - low-latency audio - daniel haver - garage band plugin (and stand-alone) - foot controller to step through pre-sets, custom tones, sounds like analog instruments/amps/etc. studio and live-stage performances

    orbit - aran anderson - satellite simulations - 650 actual unclassified sats - computations to locate these used to take super-computer, developed in 3 months using xcode (one developer) - free freefall screen saver to ship

    macos x 10.4 tiger - ship 2005 "first half of year" - apple is again innovator and others will be following ('other people still trying to copy panther') - 150+ new features - OS X is #1 "unix" os by unit shipments - new feature 64-bit for any process, 64-bit system library, can also run 32-bit processes, LP64 GCC support, better SMP fine-grain locking, XGRID built-in, access control lists

    improved SMB performance, home directories, Kerberos and NTLMv2 authentication, HTML email, word tables in TextEdit

    search - itunes search is fast, now do the same thing in the rest of OS - "spotlight" - standard files formats, extensible, works with current apps, spotlight integrated into address book, mail, system preferences, and finder, search copyright metadata, search fields built into finder window, search by "color space" to find CMYK images, save queries as "smart folders"

    spotlight addressbook - save a query as a "smart group", search birthday "within next seven days"

    spotlight mail - search 50,000 messages instantly, save a query as a "smart mailbox"

    spotlight prefers - removed "favorites" bar - search for prefs related to "keyboard" or "desktop" including synonyms for microsoft terms ilke "wallpaper". ("wifi" = "airport" = "802.11")

    search for "everything abuot bertrand" across multiple apps - system-wide search in menu bar - shows pop-down list for images, movies, mail messages, address book contacts, pdf documents (like "half dome" in a PDF map), can show in window for complete lists, sort by kind/date/people

    spotlight sdk "today"

    H.264 - quicktime video - standard codec from MPEG group for high-def DVDs, scalable from high-def down to "3G" cell phone - open industry standard, frank casanova - 250 million copies of QuickTime shipped, can display high-def image as same data-rate as today's std-def DVD rates, will be built into DVDs soon.

    safari web browser - RSS and Atom support - "personal clipping service" - searching "tons of rss feeds" and save queries as bookmarks, sort by date or "this week", time, source of article, change length of articles to display in list format, i-tunes store has RSS feed of "top ten songs", group feeds together in 'tabs'

    "core audio" already shipping - "core image" & "core video" to ship in tiger - uses "GPU" to do graphics processing in floating-point. allows real-time filters, 100+ filters built-in. extensions via "image units" and "video units"

    phil schiller - "fun-house" demo app - over a billion floating-point calcs per second - "stack many effects" on top of each other - built on top of quartz - effects can be applied to text, non-destructive, live, active - any of the stacked filters can be tweaked independently, apply filters to quicktime video, implemented in one person-week in xcode

    ".mac" - half a million subscribers - sync engine built-into tiger, .mac preference panel, sync email, calendars, address boosk, etc., across .mac and multiple macs - sync sdk for other apps to use.

    dashboard - "expose for widgets" - built on webkit - javascript - little accessory apps - calculator, address book, itunes, stickie, stock tracker, web-cam viewers, and others. one button to bring up the widget collection, single-key-press to show/hide all the widgets - sdk available today

    automator - visual scripting - interactive scripts, 100 actions built-in, share and email scripts, iLife, email and access to other apps - sal soghoian - script to grab images from web (.mac home pages) - icons for various popular 'categories', list of actions for each category - drag action to "work-flow area" - automatically link actions together, click various settings for each action [radio buttons, pop-up menus, etc.], looks like this 'settings' GUI may be generated from applescript 'dictionary' of various apps. save "work-flow" scripts "into" various applications like Safari - makes scripting about as easy as hypercard, but different UI - SDK shipping today

    ichat - personal video conferences that "just worked" - now using H.264 - multiple users - 10 chatters for audio + 3 with video/audio - the 3 video feeds are joined into a single image/window - the 2nd and 3rd video feeds have a "perspective" look to them. [actually 4 videos - yourself is shown in small image]

    developer copy of Tiger today

    [] permanent link

    Metrics and Manager as Coach

    Brad Appleton wrote a very good post on the XP mailing list about his experience with a Little-League baseball coach who collected a lot of metrics, using them to improve the kids' game, but not using them as rewards or incentives (or blaming/dis-incentives.) A few quotes:

    I used to play little-league baseball. Overzealous parents and coaches were too often the norm, and made it be so much about winning-vs-losing that it sucked a lot of the fun and learning/improving right out of it.

    Then one year I played for a team that had a manager that was different. He abhorred all that other stuff. He was big on strategy and using data. [...] He used a lot of that to help him come up with the batting line-up, which people were best at fielding which positions, pinch-hitting and relief-pitching.

    He shared the info with the assistant coaches. The info was not shared with us kids. For starters, we were possibly a bit young to try and make sense of it, but he also didn't want to see it used to try and rank people as better/worse than one another.

    [...]

    Anyway, with all that data-gathering going on, and the way it was shared, it was NEVER used as reward/incentive. We all knew what our win/loss record was. After each game (win or lose) the very next practice the manager led a discussion about things that we did well, and then areas for improvement - which usually became our "drills" for the rest of that practice session.

    Whenever we played a particularly significant game, at the very beginning, the manager would tell us we were going out for ice-cream afterward REGARDLESS of whether we won or lost. Other teams and managers never did that. They only went out to the ice-cream parlor if they won. [...]

    I was never before on a little-league team that was so motivated, and enjoyed playing so much, and that so actively encouraged other team members (especially the weaker players, who needed it much more than our "all-stars"). All in all it was a great season, and the best I recall in my own little-league "career". We lost only one game all season. [...]

    I have a feeling we wouldn't have done as well if rewards like "ice-cream" had been conditional upon winning. I know we certainly wouldn't have enjoyed it as much. [...]

    [/docs] permanent link

    2004.Jun.23 Wed

    DDD and Multiple Databases

    In Eric Evans's Domain Driven Design, he describes various strategies to use when there are MultipleModels. Two or more teams may each have a BoundedContext for their unique models, and a SharedKernel for the model they have in common. In other situations, where one or more teams are forced to use an application or a database whose model is undesirable, the teams can use an AnticorruptionLayer to convert to/from two models. (In the ConformistStrategy, the team adapts to an existing model, even if it isn't the most desirable, and in the SeparateWays strategy, the teams don't have a shared model or even a shared kernel.)

    I bring this up to link it with Martin Fowler's DatabaseStyles: he uses the term IntegrationDatabase for a database intended to be shared by multiple applications, and ApplicationDatabase to describe a db intended to be used by only one application.

    It seems that the strategies for SharedKernel, AnticorruptionLayer and ConformistStrategy will tend to encourage the creation or use of an IntegrationDatabase, and the strategies for BoundedContext and SeparateWays will tend to encourage the creation of ApplicationDatabases. And that's OK, as long as everyone involved understands why these choices were made.

    [/docs] permanent link

    2004.Jun.12 Sat

    An Agile Success Story at Sabre

    Marco Dorantes Martinez points us to a Computer World article describing Sabre's rebuilding of its air-travel reservation system: "...four-year, $100 million-plus project...C++ and Java running on 17 HP NonStop database machines and 45 Linux servers...it's all working.". The article doesn't go into details, but a participant on that project has posted on the XP mailing list: they use XP practices including pair programming, open work-spaces, TDD and refactoring, and stand-up-meetings, have one or more XP coaches; the project is using multiple XP teams that grow and shrink in numbers as demand shifts. And they must be using Frequent Releases:

    Small steps also make it possible to respond to changes in technology. That's why Linux, which didn't look like a viable option in 2001, could be brought in later in the game.

    And small steps make it possible to go live with each iteration of the system before moving forward -- to make sure the technology works and to make sure the system is what users need. If it's not, it can be changed.

    [/docs] permanent link

    2004.Jun.02 Wed

    Speed Over Quality

    On Artimage.com/weblogs, Robert Martin writes "...then why would our company want to pay for crap that slows us down? Wouldn't they rather have good clean code that keeps us running fast? ... We often blame managers for schedule pressure. We often complain that our companies set unreasonable deadlines and have unrealistic expectations. This might be true, but it's only half the problem. The other half, the most important half, is within us. We consider our worth as programmers to be more associated with speed than with quality. And that's a tragedy; because it leads us to create messes. It leads us down the slower path. By rushing we ruin our chance to truly go fast." This generated a lot of comments, and one of my comments was the following:

    Why do some managers managers value speed over quality? I can think of two reasons: they believe that buggy software is normal, or they get rewarded for delivering buggy software early.

    The two ideas are often combined. If buggy software is normal, let's set an "aggressive" date for it to be "finished" (we're rewarded for meeting that date, even though nothing is really working well), and then spend twice that amount of time removing the bugs that were put in (and blame those programmers or those testers for any delays).

    How did the idea of buggy software come to be "normal"? Because so few programmers are taught bug-reduction techniques like code reviewing, pair-programming, unit testing or test-driven-development in college, and relatively many programmers [none of whom read blogs like this or even books on these subjects] learn these techniques after college. And managers (with MBAs or otherwise), haven't gotten training on the value of these practices either.

    [and check out these books - they're very timeless and enlightening: http://www.geraldmweinberg.com/books.html ]

    Some commenters said that sometimes meeting the deadline is more important than quality, but that is actually rather rare. Most of the time, considerable effort is spent on bug-fixing. If quality was not important, why are we fixing the bugs? As Johanna Rothman points out, some companies are spending more than 75% of their time fixing bugs (rework).

    [/docs] permanent link

    2004.May.25 Tue

    Energy Prices

    David Pimentel, Cornell professor of ecology, says: "The next time you're pumping gas or paying the heating bill, ponder this: As high as fuel prices are in this country, they would be even higher without government subsidies to prop up the industry. Instead of paying at the pump, every American family is paying about $410 in taxes each year for subsidies that keep gasoline prices and other energy product prices artificially low." [That's billions of dollars in taxes subsidizing the energy industry.]

    Unfortunately, no politician is going to get elected by promising to raise gas prices, even if doing so decreases our dependance on foreign oil, decreases corporate welfare payments (and thus lowers our taxes), and pays for more efficient energy use.

    [/docs] permanent link

    2004.May.22 Sat

    Feedback

    Matt Heusser writes on StickyMinds:

    In less-healthy organizations, feedback may be viewed as criticism or personal attack. When this happens, the organization cuts off its own ability to react and respond to change. ...[feedback] must be positioned so the recipient does not feel insulted or drawn into a spitting contest.... Another way to foul up the works is to point out problems without offering solutions. ... try asking simple, open-ended questions. ... "What are the issues I'm forgetting?" "What does success mean?" ... Even if your feedback is well received, and you find or fix what would otherwise have become a major fly in the ointment, you run the risk of being perceived as the "Savior" who will "put the project back on track." There is another name for a Savior whose project fails: scapegoat.

    [/docs] permanent link

    Snips

    On unit tests / programmer tests:

    Michael Feathers: "Recently when people have asked me what a unit test is I tell them it is a test that runs in under 1/10th of a second." (XP mailing list)

    "If the computer gets wet, would compressing its files help dry it out?" (said in a dream I had.)

    George Lakoff on conservatives' use of language to dominate politics:

    They have put a huge amount of money into creating the language for their worldview and getting it out there....

    Language always comes with what is called "framing." Every word is defined relative to a conceptual framework.... "revolt," that implies a population that is being ruled unfairly... If you then add the word "voter" in front of "revolt," you get a metaphorical meaning saying that the voters are the oppressed people....

    In Arnold Schwarzenegger's acceptance speech, he said, "When the people win, politics as usual loses." ... what he has done is frame himself and also Republican politicians as the people, while framing Democratic politicians as politics as usual....

    The conservative worldview, the strict father model, assumes that the world is dangerous and difficult and that children are born bad and must be made good. ... The only way to do that is through painful discipline ... good people are the disciplined people. ... to the right wing, the good citizens are the disciplined ones ... Wealth is a measure of discipline.

    ... With Schwarzenegger, it's in his movies: most of the characters that he plays exemplify that moral system. ... He just had to stand up there, and he represents Mr. Discipline.

    The phrase "Tax relief" ... got picked up by the newspapers as if it were a neutral term, which it is not. First, you have the frame for "relief." For there to be relief, there has to be an affliction, an afflicted party, somebody who administers the relief, and an act in which you are relieved of the affliction. The reliever is the hero, and anybody who tries to stop them is the bad guy intent on keeping the affliction going. So, add "tax" to "relief" and you get a metaphor that taxation is an affliction, and anybody against relieving this affliction is a villain.

    So what should they be calling it [taxes]?

    ... Taxes are what you pay to be an American, to live in a civilized society that is democratic and offers opportunity, and where there's an infrastructure that has been paid for by previous taxpayers. ... The highway system, the Internet, the TV system, the public education system, the power grid, the system for training scientists ... which has to be maintained and paid for. Taxes are your dues — you pay your dues to be an American. In addition, the wealthiest Americans use that infrastructure more than anyone else, and they use parts of it that other people don't. The federal justice system, for example, is nine-tenths devoted to corporate law. The Securities and Exchange Commission and all the apparatus of the Commerce Department are mainly used by the wealthy. And we're all paying for it.

    People vote their identity, they don't just vote on the issues, and Democrats don't understand that. Look at Schwarzenegger, who says nothing about the issues. The Democrats ask, How could anyone vote for this guy? They did because he put forth an identity.

    [/docs] permanent link

    2004.May.16 Sun

    WikiWikiHyperCard

    Ward writes:

    [HyperCard] Stacks were already easy to edit. The fields were automatically WYSIWYG editors. But linking was a pain that involved moving between both cards involved. My Links field abandoned regular stack links and used search on demand instead. Operationally, one would just type links they might follow in the Links field. Each line had a button nearby that would take you to the card if it existed or beep otherwise. If you held the button down, it would relent and go make the card for you.

    How did it work? It worked great. Lots of people came by to see HyperCard work. I'd show them a few graphic things and then pull out my stack. We'd get to poking through people and projects and so on when my guests would invariably say, "that's not exactly right." So we'd fix it right then and there. And we'd add a few missing links and go fix them too. The stack was captivating. We were often late for lunch.

    One of the most impressive HyperCard stacks I ever used was one to teach the language Esperanto. It was a very well-structured piece of educational software. Particularly cool were sections that had prose in Esperanto, and if you clicked on one of the words, it would be replaced by the english equivalent.

    HyperCard is orphaned, now, but there are some open-source and commercial replacements in development... see here for direct and indirect links. PythonCard looks interesting. (Is there no Smalltalk-based xCard?) Ideally, there could be a web-enabled HyperCard that's user-editable like a wiki, but more structured like HyperCard.

    [/docs] permanent link

    Source Code Control

    I'm still using CVS, but Subversion looks very good - check out this article by Mike Mason: http://osdir.com/Article203.phtml. There a book on-line as well.

    [/docs] permanent link

    2004.May.13 Thu

    Tweaking Stuff Until It Works

    A comment by Adrian Howard on Ralph Johnson's blog:

    I've found TDD especially effective with new programmers. They no longer make that classic beginners mistake of typing a bunch of code then tweaking stuff at random until it works. TDD forces them to move in small increments and they get continual positive feedback - absolutely fantastic for learning.

    Unfortunately I've seen "experienced" (non-XP) programmers who work the same way - typing a bunch of code then tweaking stuff at random until it works. Even worse, whole projects where the tweaking is done in the "testing phase". Those kinds of projects tend use a process I call "unconscious waterfall": there's a coding phase, and a testing-and-fixing phase, (and very rarely a design phase at the beginning). The testing-and-fixing phase tends to take the longest amount of time. See also CodeAndFix.

    Those unconscious waterfall projects tend to give responsibility for "quality" to the testing staff, when the true responsibility for testers is to report on the state of the project. Writing quality code is ultimately the developer's responsibility, and there are many tools to help: TDD or unit testing, pair programming or code reviews, etc. QA's role is to provide some feedback, but it usually comes too late in unconscious waterfall projects.

    Check out a paper by Joahanna Rothman for testers on non-agile projects: What do they pay you to do? and this one on testing in an agile project: Testers Shine on Agile Projects. What a difference!

    [/docs] permanent link

    2004.May.12 Wed

    TDD - Refactor Sooner To Avoid Throwing Away Tests

    Jim Menard in Unit Testing with OCUnit:

    1. Write a large chunk of the application.
    2. Write test suites that exercise everything written so far.
    3. Fix the bugs found by the tests.
    4. Write a few more tests; fix some more bugs.
    5. Add new features.
    6. Write tests for the new features.
    7. GOTO 5.

    Which he explains by:

    This process lets me experiment and make a few design mistakes during step 1, perhaps starting from scratch a few times. Since I wait before writing the initial set of test cases, I don't have to write and rewrite tests that are exercising code that I'm probably going to throw away.

    I'm thinking he hasn't quite "gotten" Test Driven Development yet. Then again, if you have no idea on how to do something, a spike (without unit tests) lets you figure it out. The XP practice would then be to throw the spiked code away, and now that you know how to do it, implement it test-first. This way you spend very little time in the debugger, and almost no time fixing bugs.

    However, his desire to avoid "exercising code" that he's going to throw away may be counter-productive. He may be writing too-big tests for too-big features, and probably writing too many tests before refactoring. My experience with TDD is that tests rarely have to change if they test for expected results rather than testing "how" something is done.

    When I'm doing TDD well, I write a small test that does very little, and then a small piece of code to pass the test, repeating with additional small tests until the code does everything I think it needs to do. Along the way, I refactor to eliminate duplication... I am very alert to writing a test that looks very similar to an existing test, and I'm on the alert for chunks of code under test that also seem to be duplicates. These are telling me that it's time to refactor to create an abstraction. I don't want to have 15 almost-identical tests that can be replaced by a single test after a refactoring; but replacing a second or third duplicate test by creating an abstraction is not painful, because the tests are small and I catch the duplication as soon as I see it.

    When I work this way, I rarely need to throw away and rewrite tests as the design evolves. I may need to change a name here or there, or some other small refactoring, but the tests are mostly immune to internal changes to the code under test.

    When I have problems doing TDD, it usually comes from not knowing how to use an external API. I take a stab at it. Find it doesn't work at all. Have to look up [more] documentation, take another stab. Search for example code, take another stab. And so on. (Also let my partner drive, if I'm pair programming). It's particularly irritating if the external API I'm trying to use is poorly documented, buggy, or behaves differently on different versions of the platform I'm working on. (This gets discovered when the test fails when I build and run on that other platform.) The test just sits there until I figure it out. Sometimes I take an entirely different path, and that test has to be eliminated -- though that's not a big deal, since that test is probably only three or four lines of code anyway.

    Back to the looking for duplication to be refactored... Jim has the following code in his test-case:

        STAssertEquals(123L, [entry amountInPennies],
                       @"bad amount; 123 != %ld",  // format string
                       [entry amountInPennies]);
        STAssertEquals(1.23, [entry amount],
                       @"bad amount; 1.23 != %f",
                       [entry amount]);
    

    I look at the format-string argument to STAssertEquals and see duplicated code. I'm not familiar with OCUnit, but the xUnit frameworks I'm familiar with will tell me the actual and expected values if the test fails -- I don't have to write a format string to do get that output. If OCUnit doesn't do this, I would rewrite it. Since in Objective-C we need to get the type correct for non-object types, and since we don't have function/method-name overloading, I'd write "equals" functions for the various types, so my tests would look like this:

        STAssertLongsEqual( 123, [entry amountInPennies] );
        STAssertDoublesEqual( 1.23, [entry amount] );
    

    It's by making small refactorings like this, as soon as you spot the duplication that you avoid having to do big refactorings later.

    Jim's article also talks about putting the data for the tests in an XML file, which might be useful for acceptance-testing, but is just a waste of time in test-driven development. You're not eliminating any duplication, you're just moving the data from the tests, where they're convenient, to an external file, which creates an indirection and dependency. The indirection makes it harder to understand why a test has failed, and the dependency means that refactoring is going to be harder -- changing the tests may also require changing that XML file, or vice versa, as well as more ways to fail: the test might not find the xml file, or find the wrong xml file, or the xml file might have the wrong data, having bugs in the xml-handling code, etc.

    [/docs] permanent link

    2004.May.08 Sat

    Smokers and Unit-Testers

    What inappropriate metaphor can I write about today, which will annoy the most people? How about smokers and non-smokers being analogous to undisciplined developers (the majority) and the disciplined developers (like those who participate in successful XP projects).

    A smoker may say that his smoking doesn't bother anyone else, and a typical developer who never writes unit tests may say his lack of discipline doesn't bother anyone else, but they're both wrong. If I'm in the same room as a habitual smoker, or on the same project as a undisciplined developer, I'm going to suffer to some extent -- from the physical odor of the former, or the code-smells of the latter.

    The larger context also sees problems: higher health-care costs for the smoker [and thus higher expenses by insurers and governments]; longer project times (for debugging) and lower-quality products from the undisciplined developers.

    Some strategies for trying to get stop people from smoking get you a deserved "anti-smoking zealot" label, and trying to promote XP and test-driven-development by using unflattering analogies [like I did here] can get you an "agile zealot" label.

    Preaching the good things that happen to people to quit smoking doesn't seem to affect the nicotine addicts -- even when that preaching comes from the converted. Larry Niven finds himself writing about food in his more recent novels, because now his taste-buds are operating much better than they were when he was smoking. To people who expect all software projects to have bugs, an XPer saying how his XP projects that had fewer bugs seems to have no impact. Either the XP project is judged to be full of exceptional developers, or the projects are judged as being not "as hard" as others.

    It's a quality of life thing. A non-smoker can climb stairs easily and taste his food; a disciplined XP developer can deliver quality software with less suffering. A crisis, or a particularly bad example, can sometimes move a non-smoker to stop smoking. [Best fictional example: Kenneth Branagh offered a cigarette by someone who smokes through the hole in his throat in Dead Again. His response: "I just quit."]

    If there is no personal crisis - late, buggy software and heroic bug-fixing are considered normal, and the company isn't failing and people are still getting raises - then software developers are going to continue with their usual habits.

    Fortunately, there does seem to a be trend to adopting test-driven development or at least unit testing... unit test frameworks are freely available for most platforms, and the frameworks themselves are not too difficult to use. For some programmers, the benefits of higher quality, more-modular, code is worth the effort, even if their co-workers don't see the point in it.

    [/docs] permanent link

    2004.May.05 Wed

    XP on a Large Project

    A Paper[pdf] by Amr Elssamadis of ThoughtWorks. Quotes:

    ...35 developers, 15 business analysts, and about 10 QA...

    Unit tests and integrated builds - are ABSOLUTELY MANDATORY... As the application gets larger and larger it becomes almost impossible to add new code or refactor existing code without going through tests.

    We originally had longer iterations - one-month ... had problems estimating [large stories] ... We are now doing two-week iterations ... estimations are closer to target....

    Have an iteration planing meeting at the beginning of each iteration where the customer and developers split up in groups all day to discuss the latest story cards and estimate them. At the end of the day regroup and present your estimations and findings... This will keep the whole team in-the-know ... without burderning everyone with an extremely tedious and long meeting.

    Frequent design meeting (lunch...) are very helpful....

    It will always be tempting not to refactor and to just patch a solution, but if it is patched too much the team will be forced to make major refactorings later on.

    ...a group of individuals are needed to be the customer....

    [/docs] permanent link

    2004.May.02 Sun

    Red Dwarf

    I was watching my tapes of Red Dwarf yesterday. It's an excellent British science-fiction comedy second only to the radio version of The Hitchhiker's Guide to the Galaxy in quality. No connection to "Agile" software development, except that you could say the show is about team-work. Extremely reluctant (and thus funny) team-work in the early seasons.

    Seasons 6 and 7 were the least funny, perhaps because the team was working most efficiently then. However, the split of the original creative team of Grant and Naylor, and no longer filming in front a live audience, probably had a lot to do with the decline in quality in these seasons. Season 8 returned to hilarity levels that seemed normal in seasons 2 through 5.

    One of the best bits of season 6 is this part of "Legion":

    RIMMER: Go to blue alert.
    LISTER: What for?  There's no-one to alert - we're all here.
    RIMMER: I would just feel more comfortable if I know that we're all on
      our toes 'cos everyone's aware it's a blue-alert situation.
    LISTER: We all are on our toes.
    RIMMER: May I remind you all of Space Core Directive 34124?
    KRYTEN: 34124.  "No officer with false teeth should attempt oral sex in
      zero gravity".
    RIMMER: Damn you both, all the way to Hades!  I want to go to Blue Alert!
    LISTER: Ok, ok.
    
    LISTER presses a button.  The "Alert" box on the wall starts to flash
    blue.
    
    RIMMER: Thank you.  A bit of professionalism.
    KRYTEN: Wait!  I've got something - I'm punching it up.
    
    5 Model Shot.
    
    We see a view of an orange, comet-like thing speeding through space
    
    6 Int. Cockpit.
    
    LISTER: Too small for a vessel... maybe some kind of missile.
    KRYTEN: It's impossible to tell at this range.  Whatever it is, they
      clearly have a technology way in advance of our own!
    LISTER: So do the Albanian State Washing Machine Company.
    RIMMER: Step up to red alert!
    KRYTEN: Sir, are you absolutely sure?  It does mean changing the bulb.
    RIMMER: There's always some excuse, isn't there?
    
    

    [/docs] permanent link

    2004.Apr.27 Tue

    How to write Acceptance Tests for GUI Applications

    John Roth sums it up in the XP mailing list:

    The way we usually handle this is with a layered architecture. There are three layers: the Graphical UI, the Logical UI, and the rest of the application. (The rest of the application is probably also layered, but it's not particularly interesting at the moment, so I'm ignoring it.)[...]

    The GUI is a thin facade on top of the LUI. If there is a button on the GUI, there is a method in the LUI that gets called when the button is pressed. If a field is to be displayed on the GUI, there is a method in the LUI that is queried for the contents of the field. If the GUI needs to be notified of something so the screen can be updated, there is a method in the LUI that will accept a callback. And so forth.

    The acceptance test deals with the Logical UI. Since the Logical UI is isomorphic to what appears on the screen, we don't lose anything except the hassle of trying to test the application through the GUI.

    When using Cocoa/NextStep, you specify the LUI methods to call in InterfaceBuilder [for example, if I recall correctly, a button in a dialog calls any method you want on the class you designate as the "target", instead of "sending an event"], so in that environment you actually do very little "GUI" programming - in the sense of writing code.

    My strategy for acceptance testing GUI apps has been to make the App scriptable. Support AppleScript access to your domain and GUI objects on MacOS. On Windows, we made appropriate objects COM accessible, and thus could write acceptance tests in JScript of VBScript (or almost any other scripting language on Windows.)

    [/docs] permanent link

    2004.Apr.24 Sat

    Moving to a New Environment

    Sean Malloy's comments on trying to get into a new development environment: here

    I was thinking about how some people won't use a language unless they can do it from emacs... and how I don't like environments that try to confine me to a single open window: Borland's JBuilder, for example, or the default modes of the windows of VC++ (though at least VC++ isn't too hard to change.). Any little thing, or lots of little things, can made moving to a new environment just a little too uncomfortable to actually do.

    [/docs] permanent link

    2004.Apr.20 Tue

    Designing for Inheritance

    What's so hard about Designing for Inheritance? Not being able to predict the future. It may be impossible to know what every possible subclass is going to want to do with your base class, but it isn't hard to make a class that handles the majority of subclassing needs. (And if you make the source code available, the person writing the subclass has all the information that they need, including being able to refactor your class.)

    But the real need isn't subclassing per se, but substitutability. Your class doesn't do exactly what we want, and we want to substitute our own class that does exactly what we want. In languages that require subclassing (or interface implementation) to get substitutability/polymorphism, that means we need to subclass or implement an interface. In more dynamic languages like Smalltalk, Ruby, Python, etc., we can just implement the methods in a new class, and pass in an object of that class where the other class object was expected. As long as the program isn't explicitly checking the name/identifier of the class of the object ("o.getClass().equals(expectedClass)" or "o instanceof expectedClass") we can usually get what we want.

    One simple way to implement substitutability in languages like Java or C++ is to declare interfaces or abstract base classes that reflect the public API of your concrete classes. Always declare variables and parameters using the interface/ABC type everywhere - never use the concrete type. There's a rule of (less-dynamic) OO design: abstract types should only depend on other abstract types, and concrete types should depend only on abstract types. Of course, no one follows that rule to the letter. It's more of a guideline. But something to think about, perhaps with some exceptions for "common" types like String.

    Here are some guidelines for writing a class that is easy to subclass: Always declare all public methods "virtual" or non-final. Declare member variables private, but also declare protected accessor methods for all the member variables and use those everywhere. Every place that you create an new object, put that "new" statement in a protected factory method that could be overridden. Break down large methods into ones that call a sequence of smaller, protected methods. If you have private methods, consider that a sign that those methods belong to another class (probably one that hasn't been written yet.) It's a little easier in Java than C++, because method-calls-on-this in a constructor in Java are "virtual" and are not virtual in C++.

    [/docs] permanent link

    2004.Apr.06 Tue

    Ant Rethinking

    The inventor of Ant writes:

    In retrospect, and many years later, XML probably wasn't as good a choice as it seemed at the time. [...]

    [...] when I fused XML and task reflection in Ant, I put together something that is 70-80% of a scripting environment. I just didn't recognize it at the time [....]

    If I knew then what I know now, I would have tried using a real scripting language, such as JavaScript via the Rhino component or Python via JPython, with bindings to Java objects which implemented the functionality expressed in todays tasks. Then, there would be a first class way to express logic and we wouldn't be stuck with XML as a format that is too bulky for the way that people really want to use the tool.

    [/docs] permanent link

    2004.Apr.05 Mon

    Measured Throughput

    Agile Hiring: see Esther Derby's article on Hiring for a Collaborative Team.

    Johanna Rothman writes about an organization where the number of requirements implemented are always significantly less than the number of requirements requested. They've been blaming the testers (!) and not seeing that their throughput through the whole system is limited. Given the numbers that she posts, I compute that the through-put is about 3.4 completed requirements per week for project 1, 3.7 per week for project 2, and 2.3 per week for project 3.

    If that company accepted that they're only going to get about 3 requirements per week implemented, no matter how long the project is, they could avoid waste in the "requirements/design" phase by not specifying more requirements than their measured through-put allows.

    They could also use that figure to move to incremental development as well, and maybe learn practices that would improve throughput as well. If they used XP or another appropriate set of agile practices, they could maximize information-flow and minimize delays between requirements, implementation, and testing.

    To find the bottle-neck, we need to know who's waiting on whom in this organization. Is there a queue of finished-but-not-tested work piling up in front of the testers? Then it could be that the testers are the bottleneck. One way to deal with a bottleneck is to change to a "pull system". In this case, a programmer only does implementation when tester is about to be ready to test their work. That leaves the programmers idle, but then they could use that "idle" time to improve their development process (code reviews, unit testing, etc.)

    In this system, the bottleneck is the programmers. The "pull system" can extend to the requirements: don't specify a requirement until a programmer about to be ready to implement it and a tester is about ready to test it. To move out of phasist approach, work on testing (creating automated tests) and implementation can overlap -- or (the XP way) the programming can actually follow the creation of tests and use the tests as an executable version of the specification.

    [/docs] permanent link

    2004.Apr.01 Thu

    Palindrome Day

    Today is 04-01-04 (sorta). Writer at work, do not disturb. The writer is disturbed enough already. Don't be fooled by that Google "gMail" announcement - the clue to the joke is the free 1 gigabyte per user feature. San Jose Mercury News reported it as straight news. Suckers.

    [/docs] permanent link

    2004.Mar.24 Wed

    Doctor, It Hurts

    The old joke: "Doctor, it hurts when I do this (raising arm over head)." The Doctor responds "So don't do that." I heard a complaint about an XP project: the acceptance testing for many stories were not being completed until the next iteration. This company was doing three-week iterations, where the stories themselves took three weeks to do (not including the testing time). So don't do that. My advice: smaller stories that aren't considered "done" until the acceptance testing for them is done. If a two-day story ends up taking four days, it still can be finished (including testing) before the iteration ends.

    Estimates for a story should include testing time. I also recommended that they look into "Fit" and "Fitnesse" to see if they can ease the creation of their automated acceptance tests, and even get the tests done before the code to make them pass is done.

    [/docs] permanent link

    Specification by Example and Surprises

    If you view XP's acceptance/customer tests and "unit"/programmer tests as specification by example, then the difficulties some game developers have experienced trying to use XP make more sense. "Game Play" is a subjective experience that is very difficult to quantify -- I'm talking about fast-paced first-person-shooter video-games, not solitaire. Part of a good game-playing experience would be the player's anticipation of what comes next, but being pleasantly surprised when it happens differently than expected.

    This lesson -- "the anticipation of what comes next, but being pleasantly surprised when it happens differently than expected" -- is one I'm learning at the writer's workshop I'm attending.

    [/docs] permanent link

    2004.Mar.22 Mon

    Writing

    My first day attending a workshop on writing is about to start. (Oh, I did take a creative writing class in college that was a sort of workshoppy.) Other than knowing this workshop is at least partly based on the work of Virginia Satir (google and amazon [The New Peoplemaking] her yourself - no time for links today), and knowing some of the people involved, I have no idea what's going to go on this week.

    Last week, I did a little work on two science fiction novels, but did very little writing. I also attempted to write using IBM's Via Voice, and that experience had a lot to do with not writing -- all those misinterpreted words brought out the editor in me instead of the writer. And, making an introvert speak his thoughts out loud goes entirely against nature.

    [/docs] permanent link

    2004.Mar.13 Sat

    Changing Artistry

    Hans Nowak blogs:

    Taoism is about being in harmony with nature. As the Wikipedia page says, "Do not try to force things, for nature is overpowering. In particular one must act in accordance with how things are, not how one wants things to be."

    Now, people excited about XP or other things often ask "How can we get [force] them to change?" The answer lies more in finding ways to get "them" to want to change, rather than trying to force them to change. If they don't want to change, they're not going to make the effort. If they perceive the need to change, then maybe they'll want to change. The problem is that sometimes, some people never see the need to change.

    Art Kleiner has been involved in a lot of Change Artistry: his book-credits include The Dance of Change, The Fifth Discipline [uncredited co-author], The Fifth Discipline Fieldbook, The Age of Heretics, Oil Change: Perspectives on Corporate Transformation, and Car Launch: The Human Side of Managing Change.

    Kleiner's most recent book seems to be a reaction to repeatedly seeing change efforts fail because the "core" members of a company don't really want the change to happen. The book is Who Really Matters: The Core Group Theory of Power, Privilege, and Success. Quoting the Publisher's Weekly review:

    The old saw "the customer comes first" is a flat-out lie, argues Kleiner, a contributing editor at strategy+business magazine and the author of several business books, in this fresh look at the structure and politics of business. He contends that "a depressing number of business corporations have evolved into organizations with one primary purpose: To extract wealth from all constitutions (not just the shareholders, but the employees, customers, and neighbors as well) and give it essentially to the children and grandchildren of some of its senior executives." Such corporate selfishness works because the key decisions in are being made by the "Core Group"-executives or employees whose needs and desires determine company behavior. Others within an organization immediately sense who is in the Core Group and adjust their behavior accordingly; "Day after day, in all the small decisions we made, all the employees contributed to keeping these individuals more or less at the center of the Core Group."

    Maybe this behavior - core group getting what it wants, the non-core group helping them get it - is a basic primate behavior that we've been saddled with from our primate ancestors.

    Perhaps the weirdest thing I've seen that could be attributed to our primate ancestry was a comment someone made to me during the recall-election for California governor. He said "I like [some candidate who was third- or fourth-place in the polls] but I'll vote for Schwarzenegger because he's going to win." Excuse me? If he's going to win, you don't need to vote for him. If you and everyone who thinks like you actually voted for your favorite candidate, Schwarzenegger might actually be defeated.

    I think wanting to vote for the winner (or otherwise helping the core group) is like an ape wanting to show support for the most likely replacement of the alpha male. Primates that didn't show support for the most likely alpha male were more likely to be killed or ostracized when the new alpha male took power (assuming they 'bet' right) -- we're descendants of those who "went along with the winners" and were thus more likely to reproduce. Today, our elections have secret ballots, so no one would ever know you didn't support a "winner", but we're still primates.

    [/docs] permanent link

    CMM

    Dean W. Schulze on agilemanagement mailing list refers us to http://www.cio.com/archive/030104/cmm.html:

    SEI officials say they are not in the business of controlling what companies say about their assessments. Nor will they reveal to the public which companies have been assessed or what the assessments consisted of. "We weren't chartered to be policemen—we're a research and development group," Hayes says.

    Indeed, CIOs who look to CMM for guarantees won't find them, says Rick Harris, director of application development for OnStar, a division of GM that provides communications inside the company's vehicles. He recalls confronting a manager from one of his CMM Level 5 offshore outsourcing companies who did not know how to do a testing plan for software. "My people had to train him to do it," he says. On another occasion, Harris's staff discovered that the offshore provider had fallen far behind schedule in one of its projects but had not told him. "You'd think a Level 5 company would have told me months before that the schedule was slipping and we needed to do something," he says.

    "Having a higher maturity level significantly reduces the risk over hiring a [company with a lower level], but it does not guarantee anything," says Jay Douglass, director of business development at the SEI. "You can be a Level 5 organization that produces software that might be garbage."

    That assessment is borne out by a recent survey of 89 different software applications by Reasoning, an automated software inspection company, which on average found no difference in the number of code defects in software from companies that identified themselves on one of the CMM levels and those that did not. In fact, the study found that Level 5 companies on average had higher defect rates than anyone else. But Reasoning did see a difference when it sent the code back to the developers for repairs and then tested it again. The second time around, the code from CMM companies improved, while the code from the non-CMM companies showed no improvement.

    [/docs] permanent link

    Encapsulation

    Quoting from http://www.netobjectives.com/ezines/ezine_2004_01.pdf:

    Gang of Four: "Consider what should be variable in your design. Focus on encapsulating the concept that varies."

    Alan Shalloway: "This mandate was a bit confusing to me at first. To me, encapsulation meant 'data-hiding'. But to the Gang Of Four, it means something else: Encapsulating the concept that varies is encapsulation of type.

    I'll go into this more some other day... see also Net Objectives other ezines: http://www.netobjectives.com/ezines/ezine_2004_02.pdf.

    [/docs] permanent link

    2004.Mar.08 Mon

    One is Not Enough

    A pattern gleaned from Artima Weblogs. Knowledge is not enough to write software well. Discipline is not enough. Practices are not enough. And so on. No single thing by itself is enough. Knowledge + Practice + Feedback + Discipline (and maybe a few other things) may be enough.

    [/docs] permanent link

    2004.Mar.01 Mon

    Individual Ownership Destroys Encapsulation

    Jeff De Luca, quoted by David J. Anderson:

    If you do not use class ownership, when you assign a feature to someone then they must touch four classes (for example) in the system. They must have knowledge of four classes in the system.[...] Encapsulation is one of the founding principles of objects and is about a class being able to hide[...]

    And how hard it is for a member of jelled team to have (or get) an understanding of the major classes of the system? In fact, how hard is it to understand any class of a system, if it's got intention-revealing names, "simple code", unit tests that reveal if your changes have broken anything, and so on? What I've seen happen many times in individual-class-ownership environment is not that the classes are intrinsically hand to understand, but that people defend their turf by discouraging other people from understanding their classes.

    Also, because everyone is afraid to modify other's classes, their own classes become kitchen-sinks full of stuff that really belongs elsewhere -- this does make classes harder to understand, because they end up being badly designed and violating encapsulation "in reverse" -- the big fat individually-owned-classes have many "internal" pseudo-objects they depend tightly on, when they should be having looser connections with external classes.

    [/docs] permanent link

    2004.Feb.29 Sun

    WAGNI

    Robert Martin: "Why do people get so upset when we say YAGNI [You Aren't Going to Need It], but not when we say KISS."[Keep It Simple, Stupid]

    Adrian Howard: "I find some people take it as a personal criticism. Saying "You aren't going to need it" seems to enter some people's heads as "Bah - you are a complete idiot for doing this".

    Maybe it should be WAGNI: We Aren't Going to Need It.

    [/docs] permanent link

    2004.Feb.26 Thu

    Efficient

    Cats are one of the most efficient predators, and they spend most of their time sleeping. CPUs are more powerful than ever and they spend most of their time idle or sleeping. Does this apply to humans? Apparently not. American Farmers are (making up a number) 100 times more efficient than they were 100 years ago, but instead of resting more, they farm 100 times more land or animals (and there are fewer farmers).

    Programmers can develop more powerful applications than they could 30 years ago, but more of them are spending longer hours than ever. Other American workers are also spending more hours at work. According to business magazines, most CEOs spend 60 hours a week or more at work. Compare that to our hunter-gatherer ancestors who only needed to hunt/gather 15 hours a week. Is this progress? (OK yes, we have medicine, Beethoven's 9th symphony on CD and mpg, TV, and books...)

    Eventually we or our descendants will be living in a world in which the only things we won't be able to manufacture for nearly-free would be (new) entertainments and some services. What will we do then? Will a few workers and companies have money, and everyone else subsists, or will we live in a post-capitalist society? Look for deflation in everything except real-estate and entertainment. Maybe computers count as entertainment.

    [/docs] permanent link

    2004.Feb.22 Sun

    Consequences of Decision-Makers

    I was thinking "how do Gore & Associates do projects?" Since there are no managers, but only "associates", some of whom are "sponsors", I imagine that new product development is organized by (and around) product champions, like 3M and Toyota. Quoting the Poppendieks: "Every new product program has a strong leader, at 3M it is the ‘champion’ and at Toyota it is the shusa or chief engineer.  In both cases, these people ‘own’ the product – their name is associated with it.  We have Art Fry’s Post-it notes and Kosaku Yamada’s Lexus. These leaders are the ‘voice of the customer’ to the team and they assure the proper amount of design goes into it before detailed development proceeds. [...] The concept of a project manager is foreign to both companies, as is the idea of monitoring tasks" [instead, they monitor results].

    Do these companies start selling a new product before they create it? That's a sure way to put make time-pressure the priority over everything else, including quality. I've heard that the Post-it note project was "cancelled" three times before it was completed, so I'm guessing that 3M doesn't sell products before they're "hatched". However, many software projects are are sold (with scope and time-frame fixed) before they're planned -- sometimes before they have any estimates. And they are not re-planned when detailed estimates (or reality) show that the scope and time-frame are unrealistic.

    In a problem-solving workshop that I participated in, 30 people in one room simulated a company, and the 'salesmen' were selling something we didn't know how to make. And I was part of that. I was also one of the designers for a product we didn't yet know how to make. It was hilarious. Everyone was in one room, and yet we did not communicate, estimate, and make plans based on the reality of the product development process --