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


           
    2003.Nov.30 Sun

    XP2004

    The XP2004 conference on Extreme Programming is scheduled for June 6-10, 2004 in Garmisch-Partenkirchen, Germany, 90 km from Munich.

    Trivia fact: In 1968 the legendary Nato Software Engineering Conference was held in Garmisch-Partenkirchen, where for the first time the term 'software engineering' was used.

    There's a call for experience papers, tutorials, workshops, panels, PhD Symposium, etc.

    [/docs] permanent link

    Growing an Article

    Chris Gardner on the XP mailing list points to author Mark Forster's blog on "growing articles". He presents six drafts of an article on this subject. The first draft simply consists of the words "Growing articles". You can see the final draft in his November 28th blog entry, and all six drafts here.

    [/docs] permanent link

    2003.Nov.29 Sat

    Unhappy Companies

    James A. Robertson linked to an article in Industry Week, which describes five things unhappy companies have in common:

    1. A belief that employees are dangerous and lazy.
    2. A conviction that customers cannot be trusted.
    3. A focus on policies, not principles.
    4. An obsession with today, not tomorrow.
    5. Leadership in all the wrong places.

    Check it out.

    [/docs] permanent link

    2003.Nov.27 Thu

    Department of Peace

    Did you know there are 50 members of Congress cosponsoring a bill to form a Department of Peace? I had to hear about it from a lecture televised on C-SPAN2 - an audience member asked Al Franken if he had heard of it. Neither of the two newspapers I read regularly have mentioned it.

    [/docs] permanent link

    2003.Nov.26 Wed

    Paradox of Happiness

    John Tarrant in the January 2004 issue of Shambala Sun (a magazine from the future!), writes:

    Everyone wants to use happiness as a fix for problems, yet happiness is its own, very big thing, and it is selling happiness short to make it a fix for problems. To be happy is to experience life not as a series of struggles but as a gift, one that has no known limit. This doesn't mean ignoring your difficulties: it means not assuming that they are what you think they are. If you throw away everything you believe about your difficulties you will notice that many of them disappear and the rest become interesting.

    [/docs] permanent link

    2003.Nov.23 Sun

    Command Pattern

    Martin Fowler writes of the CommandOrientedInterface and command objects and executors:

    Command oriented interfaces have a number of benefits. One of the primary ones is the ability to easily add common behavior to commands by decorating the command executor. This is very handy for handling transactions, logging, and the like. Commands can be queued for later execution and [...] be passed across a network. Command results can be cached [...]

    And, of course, it is relatively easy to add "Undo/Redo" support to command objects and store stacks of command objects to be undone/redone.

    In a dynamic language that supports reflection, one could create generic command objects by creating a class that retains a reference to an arbitrary object [call it a 'target'], a reference to an arbitrary method of that object [call that an 'action'], and a list of arguments to pass into that method [or perhaps only one argument, the 'sender'].

    Instances of this class could be created by reading a configuration file or deserializing instances that had been created in an Interface Builder. I'm not saying that Apple's Interface Builder does exactly like this, but it is doing something kind of like this. See this page for more.

    Cocoa and Interface builder allow creating powerful programs without writing (or generating) a lot of code. It's been one of the most advanced development environments for at least a decade (it used to be part of NextStep), and it still is one of the most advanced development environments.

    Smalltalk, Objective-C, and no doubt Python and Ruby could generic command-object classes like this very succinctly. Java would be more difficult, but it can be done in Java, as well.

    Perhaps if methods and method-calls (and classes) were more easily thought of as first-class objects [which is very far from the case in C++], tools for Aspect-Oriented programming would be easier or unnecessary.

    [/docs] permanent link

    2003.Nov.18 Tue

    It's the Object Model

    I think the power of a Smalltalk environment is not just the language, and not just the environment. It's the combination of those and the Object Model - the concepts that underlay the syntax. (And a good class library helps a lot.)

    I'd like to use a programming environment which has a choice of syntaxes but which uses the same object model. I could enter code in any of the following syntaxes, and see existing code decompiled into any of the following syntaxes:

    • JavaScript
    • Python
    • Smalltalk
    • Ruby
    • Object Pascal
    • RealBasic
    • Dylan
    • AppleScript
    • Eiffel

    Interestingly, there is one environment that is approaching the nirvana of multiple-syntaxes with a common object model. Apple's Cocoa, which is implemented in Objective-C, which has an object model inspired by Smalltalk, interoperates with Python, Ruby, AppleScript, and Java. Apple's XCode/ProjectBuilder environment allows writing code in these scripting languages and C/Objective-C/C++/Java/etc.

    There are a lot of good Cocoa books out there. My favorite so far is by Aaron Hillegass: Cocoa Programming for Mac OS X It's not a lengthy as the others, and it covers a lot of what makes up a Cocoa application.

    [/docs] permanent link

    2003.Nov.16 Sun

    My Maid Has a Web-Site

    After my wife read the book A Housekeeper Is Cheaper Than a Divorce, we hired a maid-service to clean our place once a week. Marina has been reliable and helpful. Now she has her own website: http://www.myhousecleaner.com/.

    [/docs] permanent link

    Innovator's Dilemma and Solution

    I've read The Innovator's Dilemma and I'm reading The Innovator's Solution. I recommend reading these books.

    The authors main points are that (1) established companies almost always get "trapped" by their customers into only supporting "sustaining" innovations - incremental improvements in their products or services, and (2) only (for the most part) new companies are able to take advantage of "disruptive" innovations that create new markets and eventually take over established markets "from below".

    For example, in the steel-mill arena, Minimills using a new, cheaper, process were at first only able to sell into the lowest-quality product area: rebar. The established companies stopped producing rebar because of the low margins, and concentrating on satisfying their most "demanding" customers in profitable high-quality product areas. But the minimills continued to improve their quality, and eventually took over more and more product areas - always coming in from below, always taking lower-margin business away from established players. At any time, the established traditional steel mill companies could have bought one of the existing minimill companies, or established their own minimills, but the lower margins are too unattractive for people used to higher margins. It seems likely that minimills will eventually take over the entire steel industry, and the people used to high margins will have to get used to no margins at all.

    Disruptive Innovation can also create new markets where none were before. The established companies, particularly large ones, do not have an incentive to sell into a new market, because the new market is so small compared to their existing markets. Sales would be 1/100th or smaller in comparison, and not attractive to people used to making larger sales numbers. Apple experienced this with the Newton. It pretty much established a new market and sold more Newton MessagePads in two years than they had sold Apple IIs in its first two years. The difference is that Apple was a much smaller company when it was selling Apple IIs (and had invested less money in Apple IIs than it had invested in Newtons.) A small company (like Palm originally was) would spend less on the product's development, and be more satisfied with sales totals that a large company would find to be too small.

    [/docs] permanent link

    2003.Nov.15 Sat

    More Software Pokayoke

    One difference between Pokayoke in manufacturing compared to software, is that software is always unique and fresh (if it isn't, some re-use is lacking). To "manufacture" a software product, simply copy the CD-ROM or post the installer on a web-site. However, pokayoke is always about quality assurance in either domain; either detecting problems as soon as possible, or preventing problems from happening.

    Harry Robinson has an article about a Pokayoke software tool here: http://www.campbell.berry.edu/faculty/jgrout/pokasoft.html, along with some background material about Pokayoke. Quotes:

    Shigeo Shingo was a leading proponent of statistical process control in Japanese manufacturing in the 1950s, but became frustrated with the statistical approach as he realized that it would never reduce product defects to zero....

    While visiting the Yamada Electric plant in 1961, Shingo was told of a problem that the factory had with one of its products. Part of the product was a small switch with two push-buttons supported by two springs. Occasionally, the worker assembling the switch would forget to insert a spring under each push-button.... This problem of the missing spring was both costly and embarrassing. Management at the factory would warn the employees to pay more attention to their work, but despite everyone's best intentions, the missing spring problem would eventually re-appear.

    Shingo suggested a solution that became the first poka-yoke device:

    In the old method, a worker began by taking two springs out of a large parts box and then assembled a switch.

    In the new approach, a small dish is placed in front of the parts box and the worker's first task is to take two springs out of the box and place them on the dish. Then the worker assembles the switch. If any spring remains on the dish, then the worker knows that he or she has forgotten to insert it.

    The new procedure completely eliminated the problem of the missing springs.

    Shingo went on to develop this mistake-proofing concept for the next three decades. One crucial distinction he made was between a mistake and a defect. Mistakes are inevitable; people are human and cannot be expected to concentrate all the time on the work in front of them or to understand completely the instructions they are given. Defects result from allowing a mistake to reach the customer, and defects are entirely avoidable. The goal of poka-yoke is to engineer the process so that mistakes can be prevented or immediately detected and corrected. Poka-yoke devices proliferated in Japanese plants over the next three decades, causing one observer to note:

    It is not one device, but the application of hundreds and thousands of these very simple "fail-safing" mechanisms that day after day has brought the quality miracle to Japan. Each one is relatively simple -- something you easily could do on your own. It is the totality, the hundreds of devices, that is almost frightening to behold.

    Let me rant about bit a the Standard C Library. This library represents not the best or most appropriate set of functions that C programmers need to use, just the the ones that were most commonly implemented by C compiler vendors when the standardization process was begun. The string functions provided by the library are dangerous. For example, the string-copy function "strcpy(destBuffer,srcBuffer)" doesn't check the size of the destination buffer, so copying a too-large string can overwrite the stack or memory, provided us with countless bugs and security holes. Also countless lines of duplicate code where the programmer checked the size of the source string against the destination buffer-size before doing the copy.

    The Standard C Library contains what might be considered a safer string-copy function "strncpy(destBuffer,srcBuffer,destBufferSize)" that will not copy characters beyond last byte of the destination buffer. But it will not terminate the string with a null-byte in the destination buffer if the source string is longer than the destination buffer. This lack of string termination means that functions expecting a well-formed string in that destination buffer will misbehave: accessing memory beyond the end of the buffer. A programmer who does not know this "gotcha" will have created another bug and/or security defect. Once again we will have countless amounts of duplicated code as the some programmers either write a "safe strncpy" function, or add a line of code to insure the destination buffer has a terminating null-byte every time they use strncpy.

    And guess what? There's another problem with strncpy (and most "safe strncpy" implementations). It doesn't copy characters, it copies bytes. In multiple-byte encodings like SJIS and UTF8, half of a multiple-byte character could be left at the end of the buffer, if the buffer just happens to be one byte too short.

    I avoid most of the problems with strcpy/strncpy, etc., by using the C++ std::string class. It dynamically allocates memory for strings, so I never have to consider buffer-sizes. This helps mistake-proof string coding. One frustration I have with this class, is that it is possible to pass a null-pointer into the constructor. The standard says that a character-pointer passed into the constructor must not be a null-pointer, but the implementations I use will not detect this situation. Generally, if this happens, there will be a crash sooner or later, and some debugging will be required to find out how a null-pointer got passed into a std::string. If the implementation of std::string had a simple line of code -- "assert(ptr != NULL);" -- the debugging time would be reduced.

    C and C++ have a problem where its static type-checking falls down: integers are freely (and silently) convertible to pointers and bools, and vice-versa. In this domain, the language is "loosely-typed". The bool value 'false' can be passed into a std::string constructor because the compiler changes it character-pointer (whose value is the null-pointer). A character-pointer can be assigned to a bool variable - if the character-pointer is the null-pointer, then the bool variable takes on the value 'false', otherwise it takes on the value 'true'. Microsoft's CString class used in MFC has a "type-cast" operator method that returns a character-pointer to the CString's internal buffer. I recently found some code that "assigned" a CStdString (a cross-platform class with an API similar to CString) to a bool variable -- this silently called the character-pointer type-cast operator and assigned 'true' to that variable, since CStdString allocates its own non-null buffer. Not at all what I wanted.

    Fortunately, I can avoid std::string and CString and use (and customize) CStdString. My version of CStdString has an assertion to detect being passed a null-pointer. My version of CStdString does not define a character-pointer type-cast operator. These two changes help mistake-proof my code.

    [/docs] permanent link

    2003.Nov.13 Thu

    TDD is Pokayoke

    Pokayoke is a way to prevent mistakes from being made, or to detect a mistake immediately. It is "fool-proofing".

    You might think that explicit/static typing is all we need for fool-proofing, but we know from experience that the presence of explicit typing does not eliminate bugs. Let's show this with an example in Java.

    Requirement: "The game displays the winning player's name in the game-log."

    class Player
    {
        public int score;
        public string name;
    };
    
    class GameLog
    {
        public string logText;
    
        public void appendText( string textIn )
        {
            // implementation left for the reader.
        }
    };
    
    class Game
    {
        public void displayWinningPlayer( Player playerOne, Player playerTwo, GameLog log )
        {
        }
    }
    

    Now the above code satisfies the compiler's explicit type-checking, but it doesn't satisfy the requirement. Let's build a way of detecting this failure to meet the requirements - using Test Driven Development.

    // ignore other JUnit scaffolding... just show the test...
    
    public void TestDisplayWinningPlayer() throws Exception
    {
        Player one;
        one.score = 12;
        one.name = "stan";
    
        Player two;
        two.score = 13;
        two.name = "kyle";
    
        GameLog log;
    
        Game game;
        game.displayWinningPlayer( one, two, log );
    
        assertEquals( "kyle won with 13 points", log.text );
    
        game.displayWinningPlayer( two, one, log );
    
        assertEquals( "kyle won with 13 points", log.text );
    }
    

    So how do we know the test is a valid one for the requirements? Well, it looks good to me. I ask my pair partner; he thinks it looks good, too. Since we're doing Extreme Programming, we ask our on-site customer what the log should look like. She looks at our test and says "This displayed text should should have an exclamation mark at the end." So we add "!" to the end of the strings in our tests.

    We also validate the test by running it now, even though the displayWinningPlayer function is empty. The test fails (as we expected) because the necessary code to make it pass hasn't been written yet. If it had passed, then we would know something is wrong with our test.

    assertion failure: expected 'kyle won with 13 points!' is not equal to actual ''.
    (line number and stack crawl follows.)
    

    Now we write just enough code to pass the tests. Unlike some examples in the TDD literature, I'm going to write the 'right' code directly, instead of taking tiny steps.

    class Game
    {
        public void displayWinningPlayer( Player playerOne, Player playerTwo, GameLog log )
        {
            if ( playerOne.score > playerTwo.score )
            {
                log.appendText( playerOne.name + " won with " + playerOne.score + " points!" );
            }
            else if ( playerTwo.score > playerOne.score )
            {
                log.appendText( playerTwo.name + " won with " + playerOne.score + " points!" );
            }
        }
    }
    

    We run the test and get this output:

    assertion failure: expected 'kyle won with 13 points!' is not equal to actual 'kyle won with 12 points!'.
    (line number and stack crawl follows.)
    

    Whoops. Our second assertion failed. We can immediately see that the failure has something to do the points, since it got the name right. We don't even have to get into the debugger. Doh! Look at the source: when player-two has the higher score, we still append player one's score. We fix it, and the now the test passes. Pokayoke.

    We ask the customer about ties, and he says that it can't happen according to the rules of the game. I would probably document that kind of 'negative requirement' with an assertion in the code. (The assertion has no effect in 'release builds' but it does have an effect in 'debug builds' that we use in test-driven development and manual pre-release testing).

        public void displayWinningPlayer( Player playerOne, Player playerTwo, GameLog log )
        {
            assert playerOne.score != playerTwo.score : "ties are not supposed to happen - fix your test/code";
            if ( playerOne.score > playerTwo.score )
            {
                log.appendText( playerOne.name + " won with " + playerOne.score + " points!" );
            }
            else if ( playerTwo.score > playerOne.score )
            {
                log.appendText( playerTwo.name + " won with " + playerTwo.score + " points!" );
            }
        }
    

    And one last point. I could have written all of the above in Python, which does not have explicit/static typing. The tests would still detect my failure to meet the requirement, and the code would be a lot shorter and more succinct.

    Extreme Programming has another way of detecting errors relatively quickly: "Frequence Releases." If possible, some end-users of this game will see versions of the game perhaps as often as every iteration. But that goes beyond pokayoke into the general area of feedback.

    [/docs] permanent link

    2003.Nov.11 Tue

    Religion

    Ron Jeffries wrote something quotable today:

    Calling something you don't understand and don't know how to do "religion" is an entirely specious argument. There are people all around you doing these things and having them work. Tell us what happened when you tried it. Until then, it seems fatuous to tell us that we can't be doing what we are doing.

    [/docs] permanent link

    2003.Nov.08 Sat

    Wrong Tools For the Job

    Someone wrote to Bruce Eckel asking for help:

    I'm trying to develop a business application in C++. I want to be able to build a framework of the business objects which can be extended later without touching the framework source.

    My main problem (one of them anyway) has been designing a way for these objects to be persistent. I want to use a relational database product....

    The first thing wrong is using C++. I've used C++ for close to 16 years, but for the purposes he wants (persistence, extending a system without modifying code), it is the wrong tool. This is a case where you need a dynamic language with good reflection capabilities. Python or Smalltalk (or even Objective C or Java in some circumstances) would be better choices.

    The second thing possibly wrong is very likely using the relational database. Unless interoperability or scalability issues require it, it would probably be better to use persistence/serialization options available in Python or Smalltalk instead of trying to get around the relational-object impedance mismatch.

    The third thing, which Bruce goes into, is premature framework building. What is the problem being solved? Maybe it doesn't need a full-blown, extensible framework.

    The writer also complained about Visual Basic applications being too rigid to re-use. There is another tool can help for this problem: separate the GUI from the model by incrementally implementing the model test-first (Test Driven Development) and implementing thin GUI code afterwards.

    [/docs] permanent link

    Principles are Constant, Practices Can Vary

    Curtis Cooley writes (book links are my addition):

    Womack and Jones opened my eyes in Lean Thinking to the fact that practices don't map from project to project. They discovered after their landmark book The Machine That Changed The World that manufacturing companies were having little or no success implementing Lean Manufacturing even though the company embraced and believed it. The problem was that the companies were trying to map the practices that Toyota used to their particular manufacturing process. This doesn't work. The principles of lean manufacturing are constant, so you take the principles and adopt your own practices, possibly from a list which includes practices known to work.

    The interesting thing is that Toyota's practices don't even stay the same from month to month. Their continual search for improvement (driven by all levels of employees - not just management or a few driven people), means trying things and fixing things all the time. See what Joe Ely has written here:

    Several years ago, I read a discussion of Toyota's openness in conducting tour after tour of their facility. The reason is that most visitors see things as they are. They take a "mental photograph", if you will, of a static system, resolving to try to do what they see. But the real power in Toyota's system is in its dynamic nature. It is impossible for the outsider to see just how rapidly and repeatedly the Toyota folks change the system. It is anything but static...it is a living, breathing, dynamic system that both changes constantly and is amazingly stable.

    PS: We as programmers will be much better off if we could tune and periodically modify not only our practices, but the IDE and programming language we use as well. (Toyota can refine and build new tools for making cars, we should make it easy for us to do refine and build new tools for making software solutions.) Smalltalk is one particularly malleable system. In Squeak and many other implementations of Smalltalk, the compiler is written in Smalltalk and is something you can modify (as well as the IDE). [Unlike for complicated languages like C++, a Smalltalk compiler is succinct and relatively more understandable.] I don't have it handy right now, but some time ago I was given a piece of code, less than third of a page in size, that adds an "increment assignment" operator to the language, so you can write something like "a :+= b" instead of "a := a + b". Many other things that would be additions to the language in other languages, are just new methods or classes in Smalltalk.

    [/docs] permanent link

    2003.Nov.07 Fri

    Remnants

    The days of the week - (mostly) forgotten gods:

    • Sun's day
    • Moon's day
    • Tiw's day (a Saxon war-god)
    • Woden's day (Anglo-Saxon/Teutonic god)
    • Thor's day (Norse god)
    • Freya's day (Teutonic goddess)
    • Saturn's day (Roman god)

    See also http://www.crowl.org/Lawrence/time/days.html.

    [/docs] permanent link

    2003.Nov.06 Thu

    Cost of Low Quality
    Johanna Rothman's What Does it Cost You to Fix a Defect? And Why Should You Care":

    After release, Company A estimated that it spent 20 person-days per fix. At $500 per person-day, this comes to $10,000 per fix. Company A typically had 20 "emergency" fixes after each release, for a total post-release fix cost of about $200,000.

    Company B tracked the time it took to fix a defect during implementation (before system test), and found the average time to be about two hours, or about $125 per fix. Company B generally didn't release fixes to its products once the product was in the field, so it had no extra post-release costs.

    Like the others, Company C did not track defect fix time during the requirements, design, and implementation phases. However, Company C engineers used a build-every-night and fix-any-defects-immediately approach to product development. In effect, the engineers were finding and fixing defects throughout the entire lifecycle. They spent an average of one person-hour each day fixing defects from the previous night's build, or about $60 per defect. Using this approach — along with code walk-throughs and peer reviews — they generally shipped a very high-reliability, low-defect product, and were able to avoid most post-release defects costs. When they did have an "emergency fix," their average time to fix was about 5 person-days per fix, or $2500 per fix.

    Company A had the highest cost, over $400,000 just to fix defects.... Company C had the largest, most complex project, with the most people, and was able to contain its defect costs to about $135,000.

    Nynke Fokma's Are We Solving the Real Problem?: The global organization had a list of 5 company values for all thousands of employees all over the world. One read "Exceed Customer Expectation." How many projects had we shipped in the last year that did not live up to customer expectation, let alone "exceed" it? I had no idea. None of us was directly in touch with customers and users so how will we know how we are doing?

    Elizabeth Hendrickson's You Can't Test the Wings Back On an Airplane:

    Testing can tell you when something isn't right, but it can't fix what's wrong.

    When I talk with individuals, most understand the difference. Yet the common behavior of software development groups shows that some people still believe that a test group really can ensure quality. The biggest indicator that this attitude persists lies in the name given to test groups: QA, Quality Assurance. Beyond that, there is an attitude, common in many organizations, that foists blame for bad releases on QA.

    Quality problems originate long before the testers get their hands on the product. Even in an environment where testers are involved early, testers without training in quality techniques are unlikely to lend much to a quality effort. In short, naming a group QA seems to make some people in other groups think they are officially absolved of the responsibility to promote quality practices. "That's QA's job." I've heard more than one programmer, technical writer, and project manager utter those words.

    Actually, quality is everyone's job. It begins with the requirements and ends with a solid product shipping out the door: a product that meets, exceeds, or redefines the customers needs and expectations.

    [/docs] permanent link

    2003.Nov.05 Wed

    Test-Driven Design/Development

    I'm about two-thirds done reading Unit Testing In Java: How tests drive the code by Johannes Link. It's a very good book. Go buy it now, even if you're not programming in Java, and then finish reading my blog. :-)

    The summary form of test-driven development is:

    1. Think about what we want to the program to do.
    2. Write a test that shows some aspect is done.
    3. Run the test, see it fail because we haven't written the code to get the thing done yet (this tests our test, giving us some confidence that our test is written correctly).
    4. Write the smallest amount of code to make that test pass.
    5. Run the test, hopefully see if pass. (If it doesn't, fix the problem.)
    6. Refactor to clean up the code.
    7. Run the test again, to make sure refactoring didn't break anything.
    8. Repeat [sometimes skipping 6 and 7] until you can't think of any new tests, or until the code stops changing as a result of adding tests.

    So what if we don't know what we want the program to do? Writing a test can help us figure that out. Since the code hasn't been done yet, the test is "black-box" and does not necessarily commit us to any particular way of implementing the solution. We can write "Exploratory Tests" to investigate existing code - does calling "X" do "Y"? Write a test and find out.

    I don't have time to write lots of tests. Well, you only have to test code that you want to work. If you don't test it before you write, you'll be testing it in some fashion after you write it. Or someone else will test it, file a bug report because you didn't test it, and then you have to not only interrupt whatever you're doing and fix it, but also test it to confirm that you fixed it. And the time-delays between your writing the code, the tester finding the bug, and your trying to fix the bug means that you will be less familiar with the code, and thus fixing it will be that much harder and slower.

    There is, of course LOTS of code out there that was not written this way (some of it is mine). Just browse some of the code on the internet or in your company's source-code-control system - probably most of it isn't written using test-driven techniques.

    You'll probably find these things in non-test-driven code (particularly in projects that don't do code-reviews or pair-programming and refactoring):

    • Dead code -- code that is never invoked.
    • Duplicate code.
    • Unreferenced parameters and variables.
    • Variables that never vary: 'constant' variables.
    • Toughly-coupled code. You can't use a class in isolation because it depends on lots of other concrete classes.
    • Non-cohesive classes and methods. (Classes and methods that do "too much")
    • BUGS

    There is in fact a whole list of "code smells" (possible design problems) at http://c2.com/cgi/wiki?CodeSmell. TDD helps prevent some of them, and refactoring with the safety net of tests can allow you to to fix the others. With TDD and Refactoring, you don't have to live with smelly code.

    I find that once my tests are passing, I almost never have to go back and fix any bugs later. This saves me a lot of time. At the worse, it takes about the same time as coding + debugging, but it's less stressful. If a bug arises during TDD, it is most likely in code that I wrote less than five minutes ago -- easily found and fixed.

    For those people who say they don't have time to write tests: why do you have time to write dead code, duplicated code, and where does the time to fix bugs come from?

    In traditional development and testing, you create a lot of defect-ridden code, and then test the defects out. The underlying assumption is that this is the only way it can be done. Test-Driven-Design works with a different assumption: You can put the quality in first, and not have to spend time getting defects out.

    Traditional (maintenance) development, since it usually isn't supported by a suite of tests, eventually grinds to a halt: the code becomes so fragile that it can't be modified without breaking something. I don't know if the IRS has depreciation tables for source-code assets, but the reality is that code eventually loses value unless you take steps to keep it from losing value. Sometimes, code becomes unmaintainable while the company is still trying to make money off of it - the result is the company loses money or doesn't get the opportunity to modify the code to make more money. Test-Driven-Design provides a suite of tests that allows you to refactor - keeping the code maintainable so it is easy to enhance, re-use, etc., so you can make money.

    [/docs] permanent link

    2003.Nov.01 Sat

    Lean Conference

    Joe Ely mentions a Lean Conference. While most of the sessions are aimed at Lean Manufacturing, and a few aimed at Lean Office work, I found this session description particularly interesting and applicable to Lean Software Development:

    GS4 - Lean Liberates Leadership: Flowing Through the Top of the Bottle Jim Greer, CEO, The Greer Company

    There is a common misconception among even experienced leaders that their job is to lead. To lead would then mean to control. Lean leadership is a giving away of control and discovering leadership in others. When I exercise lean leadership I inspire leadership in others to find and eliminate waste, to create a more direct route, to decide and move in more efficient ways. When one person controls leadership there is by definition a bottleneck. Most bottlenecks are at the top of the bottle. This talk is designed to help those who are positioned at the top of the bottle to help others to be liberated to lead without putting the whole business in jeopardy. It is also designed to help those who are stuck in the bottle to develop strategies to appropriately influence those at the top.

    [/docs] permanent link