Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Desktop Developer

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « Exploring Reactive Extensions - IObservable and IObserverRaleigh Code Camp Followup »
    comments

    Last week I had the pleasure of presenting at a .Net Code Camp on the topic of Unit Testing. A key theme of the session was barriers to adoption and the values we can achieve using this tool.

    The main barrier to my adoption of Unit Testing was the idea that writing twice as much code would increase the value of my work. Twice as much code, as was pointed out in a response to my post two week's ago, sounds like higher maintenance costs, higher initial development costs, and a greater opportunity for bugs.

    How Does Adding Code Increase Value?

    People have published numerous lists of benefits they have received from Unit Testing, but there is still this seemingly illogical starting point of creating more code to deliver the same end product. And before evaluating any other benefits we could achieve from Unit testing, we have to start by resolving that seeming contradiction.

    Current Process

    Consider a software process that includes developers, a QA department, a customer review, and a production deployment.

    1. Each developer writes code to fulfill assigned features or tasks
    2. Once enough pieces have been written, the developer can wire them together and debug the pieces they have written
    3. Completed pieces are handed off to QA
    4. QA tests those pieces against the requirements
    5. Bugs (code defects or missing requirements) are returned to developers
    6. Once QA is satisfied, the pieces are handed off to the customer for review
    7. The customer reviews the pieces, possibly sending back instructions for refinement or corrections
    8. Once the customer is satisfied, the pieces are deployed to production
    9. End users use the pieces in production and interact with production data

    This won't match everyone's environments but it should be simple enough to be representative of the work that happens in our environments.

    Unit Testing is Testing at the Source

    In Lean Manufacturing there is the concept of moving quality to the source of production. Tests are created that are quick to execute and provide the operator with a quick detection of defects instead of waiting for a Quality Control at the end of the process.

    Moving testing closer to the source reduces the number of defective parts that are stored, transported, and used in later production steps. It allows for faster reaction time to correct the problem and reduces the number of interruptions from having to stop a run and re-produce product for a previous order.

    All of these costs have well-defined values in manufacturing environments as well as parallels in our own environments.

    Lean Development

    Each step in our sample development process above increases the base cost of producing a working feature. The further a bug makes it without being detected the greater costs it has accrued and the more cost it will take to correct it.

    Effort and cost of bugs increase dramatically as time passes
    Effort and cost from bugs increase dramatically as time passes

    Costs:

    • Bug while writing one unit: Cheapest cost
    • Several pieces wired together: changes to the unit and surrounding units
    • During Handoff: Wasted meeting/handoff time for devs and QA personnel, potential schedule change, additional debugging time and cost changes (per prior step)
    • Bugs found in QA: (at minimum) Handoff to Dev, switch from new task to work on bug, investigation, development, debugging changes, handoff to QA, QA repeats some level of testing (high potential for new bug, developers tend to test direct changes only)
    • Bugs found in handoff to customer: (at a minimum) Prior QA steps,time for QA to duplicate problem, task-switching time for QA, cost of customer time and others involved, re-handoff to customer, timeline impact, potential impact to customer trust (depends on frequency - costs include increased micro-management, increased meetings, etc)
    • Bugs found by customer: Similar to last step but any testing to this point by customer is likely to be duplicated, customer schedules impacted, cost of extar customer time, timeline impacted
    • Bugs found in production: Prior step + developers are pulled off other tasks to detect and cleanup bad data, schedules are impacted due to developer time, potentially wasted end user time, potential to retrain + monitor users to work around problem and then retrain back afterward

    Besides people-based costs, there are also hidden costs to returning to development and quality stages. The more time that passes between writing the code and returning to it, the more familiarity will be lost and the higher the potential that other pieces will have been added on top of the bug. Other details, such as the specifics of the requirements that code was fulfilling and how it was initially tested prior to QA hand-off, will rely on the memory of the developer and will have to take into account any changes that have occurred since initial development. Perhaps of greater concern is that QA will not have the same level of familiarity with the tests they initially performed and the customer is more likely to add even more 'refinements' when it comes time to re-review the changes.

    Unit Testing is our tool for doing testing at the source, to catch defects earlier before they propagate costs throughout the process.

    The Value of Quality at the Source

    Unit Testing will not prevent all bugs but it will catch bugs earlier, reducing the costs above. Unit Testing starts earlier, allowing us to test each unit we build instead of waiting until we have 10-20 built and wired to an interface. For the situations where a bug still makes it past development, we will have a solid set of tests to run after making corrections so we can not only test changes but also the rest of the codebase, heavily reducing the risk of creating new bugs out of bug fixes.

    The value we gain from Unit Testing is value to the team and the business, not to the individual developer (though there are values to be gained there as well).

    Balancing Cost and Value

    There is a cost to writing Unit Tests that we have to balance with the potential savings and risk reduction. I don't believe there is a universal answer as to how much Unit Testing is appropriate for a given environment, project, and team. Many teams take it on faith that 100% coverage is their best bet, but I am not convinced.

    What I can tell you is that all of the benefits of this tool are out of your reach if you don’t give it a test drive.

    As several people saw in my CodeCamp presentation, it doesn’t take long to add a Unit Testing project to an existing application and build a few tests. Pick a particularly complex business function or an existing bug in need of correction. If you decide to start evaluating it for greater implementation, the list of costs above should provide some pointers on where you can create some measurements to determine the level of value you are receiving.

    Other posts in this unplanned series:

    About the Author

    User bio imageEli delivers software and technology solutions for a living. His roles have included lone developer, accidental DBA, team lead, and even unintentional Solaris consultant once. With experience in adhoc, Lean, and Agile environments across NSF grants, SaaS products, and in-house IT groups, he is just as willing to chat about the principles of Lean or Continuous Delivery as he is to dive into Azure, SQL Server, or the last ATDD project he created.
    Social SitingsTwitterLinkedInHomePagedeliciousLTD RSS Feed
    InstapaperVote on HN

    8 comments

    Comment from: Christiaan Baes (chrissie1) [Member]
    Christiaan Baes (chrissie1) I actualy think it's much more then twice the code, but it would be hard to get real number about it. But you appreciate it even more when tests go red which you never expected to go red with that change.
    11/15/10 @ 11:23
    Comment from: Alex Ullrich [Member] Email
    Alex Ullrich I'm not sure it's much more than twice the code (3x wouldn't surprise me a bit though), but I agree that the more coverage you can get the better. We made some changes last week that caused a whole bunch of tests to fail throughout the system (probably over 100 overall across different parts) and never would have caught all of them without tests.
    11/16/10 @ 05:27
    Comment from: Christiaan Baes (chrissie1) [Member]
    Christiaan Baes (chrissie1) 3x is 50% more so that is much more for me.
    11/16/10 @ 05:42
    Comment from: Eli Weinstock-Herman (tarwn) [Member]
    Eli Weinstock-Herman (tarwn) I tend to say 2x just because it's easy. The actual amount is going to depend on a lot of factors; How you've written the code (ease of testability, complexity of units, number of dependencies), whether you're manually mocking objects or auto-mocking, what level of testing you do (coverage, and whether you do integration tests also, etc) are just a few of those factors. There have also been studies that show that unit testing (and especially TDD) will reduce the size of the resulting production code, so add 1.5x, subtract .33x...

    And that's all at time of initial production. Legacy and maintenance phase applications can be heavily affected by the presence of Unit Tests when business rules are modified. With apps that have unit tests, we tend to refactor and rewrite the rules that are changing. Without unit tests, our safety net, we tend to do more patching or band-aiding because we are afraid to change the pieces we know are working. So long term maintenance projects tend to bloat as they age and add another potential factor to the equation.

    So I say 2x because it's a useful generalization and every other item I mentioned above is probably another topic on it's own :)
    11/16/10 @ 05:51
    Comment from: local user [Visitor]
    local user I am astounded by all of the comments about unit tests that are 2-3 times larger than your code. How is that? If I have a method with 10 lines of code and I write 5 unit tests for it - I essentially have 5 assert statements in it's most basic form. What are you people doing, putting logic in your unit tests? WTH. Call your block it returns X,Y or Z or an error, assert it, the end. If you are writing such large unit tests your architecture needs to be rethought out or something, because you are doing something wrong.
    11/16/10 @ 08:26
    Comment from: Jeff L. [Visitor] · http://langrsoft.com
    Jeff L. I don't know about plain ol' unit testing (POUT, aka TAD test-after development), but I have seen many different projects done using TDD.

    With TDD done comprehensively, the amount of test code is usually a bit more than the production source base.

    However, and a big however, the overall amount of code is usually half the size it would otherwise be, or even less. How do I know this? One example: At a shop in Cleveland, they took a "typical" Java app of about 180,000 lines of code, added lots of tests, and refactored it down. Nine months later, they had 70,000 loc; another month later, they had 60,000 lines.

    A quick look at just about any typical app reveals lots and lots of code unnecessary duplication. It partly exists because of the risk involved with not getting rid of it. In contrast, on a test-driven app, we factor out duplication *far* more than we would otherwise. Hence the line count stays low.

    I'll take the Pepsi Challenge any day that just about every non-TDD'd app can be shrunk by at least a third and usually to a half.

    Ergo: half the typical size + unit test code that's a little larger than that = perhaps a little more total code than before. Plus you get the other myriad benefits of having the test coverage. It's always seemed worth it to me.

    (It does require keeping the UTs themselves clean, too, i.e. minimizing duplication and emphasizing abstraction.)
    11/16/10 @ 12:58
    Comment from: Eli Weinstock-Herman (tarwn) [Member]
    Eli Weinstock-Herman (tarwn) local user: There is more to a unit test than a single assert though. At it's basic you need a minimum of 2 lines (action and assert) but I think 1-3 lines of setup (arrange) is not unusual - netting you 3-5 line functions. Anything else is pure guesswork when we're talking generalities (complexity of target code, test up front vs test on new project after vs testing on legacy) and assuming that all situations will provide the perfect circumstances seems a bit naive.

    Jeff: Thanks for the info - I don't have experience w/ TDD on that scale and I suspect many projects manage to shrink down that far - shows what can be done if we refactor aggressively w/ good test coverage.
    11/16/10 @ 13:42
    Comment from: Alex Ullrich [Member] Email
    Alex Ullrich Jeff - I've definitely experienced the same thing regarding line count. TDD has a way of forcing you to do the bare minimum that is quite nice.

    local user - I think it's pretty hard to do the pure unit testing that you describe in a non-trivial app. To test higher level objects you need to worry about how to address dependencies between objects (either by setting up real objects or mocking/setting expectations) and this can lead to 3 or 4 ten line tests to test a 5 line method pretty easily.
    11/17/10 @ 07:59

    Leave a comment


    Your email address will not be revealed on this site.

    To mislead the spambots.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)