Duct Tape Programming

Tags:

Joel tells the story of The Duct Tape Programmer, and Uncle Bob offers his response. Now these are two pretty smart guys who know a lot about software development. But when we receive fundamentally different messages from a couple of industry luminaries like Joel and Uncle Bob, we’re left wondering - “Who is right? Who should we listen to?”

Joel makes some valid points, but it’s strange that immediately after discussing the dangers of overengineering and the importance of shipping the product, he points out the following:

Zawinski didn’t do many unit tests. They “sound great in principle. Given a leisurely development pace, that’s certainly the way to go. But when you’re looking at, ‘We’ve got to go from zero to done in six weeks,’ well, I can’t do that unless I cut something out. And what I’m going to cut out is the stuff that’s not absolutely critical. And unit tests are not critical. If there’s no unit test the customer isn’t going to complain about that.”

I’m not quite sure how unit testing encourages overengineering nor how unit testing impedes shipping the product. Unit testing does neither. In fact, unit testing inspires a simpler design, not a more complex one. And because unit testing helps developers build quality into the product, I’m certain it doesn’t inhibit shipping the product - or at least a product that works. The correlation makes no sense, and I can’t help but wonder if the message wasn’t an intentional jab based on some past conflicts.

Of course, I certainly agree that favoring simplicity and getting the job done are righteous goals. Sometimes you have to cut a few corners, take a few shortcuts, and implement a solution that isn’t perfect. But there still exist fundamental practices of professionalism that must serve as our guide. And as Uncle Bob points out, unit testing is one of these practices. Bottom line! As a humorous post on twitter suggests:

never take software advice from a bug tracking system salesman

Unit testing is important, has significant long-term benefits, and developers should use them. However, I do take slight issue with Uncle Bob’s following statement:

I found myself annoyed at Joel’s notion that most programmers aren’t smart enough to use templates, design patterns, multi-threading, COM, etc. I don’t think that’s the case. I think that any programmer that’s not smart enough to use tools like that is probably not smart enough to be a programmer period.

In this respect, Joel is right. There might be a lot of people out there who aren’t smart enough to be programmers, but the reality is that only 50% of us can be above average. Of course, we all think we’re in the upper 50 percentile and when we’re looking at code written by someone else, it’s apparent to us it’s the other guy or gal who’s in the lower half. Without arguing who belongs where, the reality is that if we were all smart enough to use these advanced constructs, we wouldn’t be left with the mess we have today.

But really this only reinforces the importance of unit testing, which is why statements that denounce unit testing are so surprising. Think about it…Would you rather maintain a codebase with near 100% test coverage or a codebase with near 0% test coverage? Maybe those who can’t answer this question are the folks that shouldn’t be programmers!

From http://techdistrict.kirkk.com/

0

Kirk an industry analyst at Burton Group. For 15 years, I worked in the trenches on real software projects. I believe software development is an amazing profession. I take a keen interest in design, architecture, application development platforms, agile development, and the IT industry in general, especially as it relates to software development. I also enjoy experimenting with new technology, whether it be the the cool new framework or tethering my smartphone to my Mac via Bluetooth to get an internet connection. Kirk is a DZone Zone Leader and has posted 55 posts at DZone. You can read more from them at their website.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jeroen Wenting replied on Mon, 2009/09/28 - 4:41am

It's simple math. If I have 50 hours of effective time to write something that meets the customer requirements, kinda, and my estimate is that I need 75 hours to do it at least, I'm already behind the curve (and that's the normal mode we all operate as all know), something has to go.
If I deliver a product with missing functionality, I get bad looks from everyone. If I deliver it (partially) untested, that's expected anyway so that's what I do. Customers expect (new) software to be buggy after all. I'd love to deliver something without any bugs, but that will never happen even given perfect requirements (lol, don't exist) and all the time needed to perfectly implement them (never going to happen either).
In the extreme, development groups get to take the blame for problems introduced by factors outside their control. Like at one job where we were blamed for network problems introduced by our hardware guys forgetting to plug in a new router so a new customer could not contact our servers. Of course the customer called that the software couldn't connect, and the call was mindlessly logged on software. As policy there was to count only the original log group as the one to blame for all calls, we took the blame despite it not being our problem. As ALL customer problems were logged as software problems, we took the blame for every problem customers had from power failures to bad sectors on harddisks. And (though an extreme case) such things aren't all that unusual, at another company we were reprimanded for not writing software that would continue running while the computer was down during a power failure for example.

Ran Biron replied on Mon, 2009/09/28 - 5:18am

@Jeroen Wenting (and everyone else interested)

I completely disagree. I'd rather ship half the features as good (or "acceptable", as dictated by the specs, those being dictated by customers / marketing). At the very least, I'd rather KNOW I have a problem and say it in my release notes: "hey, don't do A,B,C in sequence without saving after B - you might lose 4 hours of work".

This is without getting into the huge amount of time saved by not getting into the pit of regressions, as in "I changed a bit in module A last week and suddenly module B doesn't work", or the fact that it's far easier to unit test a lot of scenarios than to QA-test them.

I'm a big fan of unit tests, integration tests, regression tests, black-box tests... Basicly, I'm very lazy. Everything that can be done automatically, should be. I'd rather write ten unit tests, parameterize them to test hundreds of scenarios, run them continuously to check for concurrency issues - than to sit hours analyzing logs from customers, where I don't have a debug environemnt, no proper logging and no reproducable scenarios.

Regarding customer value - I don't think customers appreciate falsehood. Getting an unready and untested feature out, not knowing what kind of bugs it has or if (god forbid) it might damage the customer data - I regard this as lying.

This might sound high and mighty, but facing impatiant but happy customers is far better than facing angry ones.

 

 

ob1 replied on Mon, 2009/09/28 - 5:44am

"It's simple math. " Depends what equation you are running. Personally, if I have 10 features to write, I'd rather write 5 features that are full tested and working and most importantly won't regress, with another 5 that are either missing, incomplete or have known issues, rather than 10 features none of which work correctly, have expected results and even when fixed, will easily be broken again.

Alex(JAlexoid) replied on Mon, 2009/09/28 - 6:25am

 

And because unit testing helps developers build quality into the product, I’m certain it doesn’t inhibit shipping the product - or at least a product that works.

 Yes it does force people into writing code that brings little end user value. Quality code, regression tests and similar, unfortunatelly are not interesting to the users.

I have personally worked on a project with automated test coverage over 88% and yet it's a really horrible piece of software that is inferior to most of the projects that had 0% code coverage. The end result? That software that had 88% code coverage had a minimum of 8 hours of development time of ANY change in code or configuration.

 Would you rather maintain a codebase with near 100% test coverage or a codebase with near 0% test coverage? Maybe those who can’t answer this question are the folks that shouldn’t be programmers!

I have had the misery of maintaining both types, unit tests are no panacea. And 0% is no horror story.

Karl Peterbauer replied on Mon, 2009/09/28 - 8:24am

I definitely prefer a good, healthy codebase with low test coverage to a bad codebase with high test coverage. The question "to test or not to test" is wrong. Test code is also code. Bad programmers tend to write trival, irrelevant, bad test code, making any refactoring even harder.

Rogerio Liesenfeld replied on Mon, 2009/09/28 - 9:49am in response to: zaph0d

It would be nice if what you describe is how the world works. In my experience, it is not.

Customers/end users normally expect to get everything they asked for, on the previously set date. If you don't deliver anything on that date, or deliver only part of the expected functionality, then they get angry.
Obviously they don't like finding bugs, but in the projects I have participated in, they actually were quite accepting of that. They understand an initial version has flaws, and are generally willing to allow extra time for fixes and improvements. At least they got to see and play with the feature, even if it still requires work. I don't know, maybe customers think that a feature not delivered, but supposed to be partially implemented, has in reality not even been started. So they demand to see it sooner rather than later.

I am not saying I like things this way, only that it is what I have seen in real application development projects.

Ran Biron replied on Mon, 2009/09/28 - 3:31pm in response to: Rogerio Liesenfeld

"It would be nice if what you describe is how the world works. In my experience, it is not."

Well, in my experience, shipping bad code to customers result in either:

1. Customers seeing the effect of the bad code almost immediatly and demanding a patch to fix the bad code, forcing you to spend useful "next version" time on the previous version. That might be ok if you only plan on one meaningful version, but if you plan on more, you've just blown the next version schedule.

Or worse,

2. Customers  not seeing the effect of bad code, resulting in data corruption in their databases. This forces your company to send recovery teams to the customer, spend a huge amount of effort on all levels, compensate the customer and generally lower the probability of any favorable opinions forwarded.

I've seen, first hand, both of those options - these are very much "real world" situations. They're both crappy and cause general misery around.

On the other hand, there's option 3:

3. Customer do not recieve a promised feature / recieve only a partial feature a specific timeframe for the full feature delivery. Customers are angry, but not as much. This is especially true for big systems because the time from product release to actual production implementation is huge (takes between 1-2 years in the product I'm working on).

Regarding the "initial version" arguemtn - that might be correct, if you're releasing an "initial version". However, if your product already has some market presence, your best bet is not to deliver crappy features that might hurt its reputation. The product I'm wokring on has been on the market for 6 years now (in various forms and names) - delivery a really crappy central feature now would be disasterous - and I can say that from a personal experience as well (horrible personal experience).

[Edit - clicked submit by mistake]

Besides, I'm working in a multi developer environment (aren't we all?) and am responsible for supplying working APIs to other developers. How do I know these APIs work? How do I know these APIs are even workable (design/syntax) without writing some client code? If someone from another team comes and says "your API doesn't work", all I have to do is whip up the test and see - either he's correct or I can say "see this test works? now its your responsibility to supply a repeatable case that causes the API to fail."

In addition, tests actually make me develop faster. In the compile-run-debug cycles sense, I don't have to wait for the entire server to load, I can test just my small module until it's ready, only then test it in a "real" environemnt. In the design sense, I can add requirements and make sure they're done just by creating some new tests (that initially fail, then start to pass). In the multi-developers sense, I can be sure my code is working, focusing my efforts in another module, one which is either under-tested or which has failed tests.

I'm not saying "test everything". I'm not even saying "get XX% coverage". But do test what's important. Do test customer scenarios and APIs. Do test critical sections in your code, especially those that can corrupt data. Not doing so might be good for the short run, but very bad for the long run.

Andreou Dimitris replied on Tue, 2009/09/29 - 6:02am

I lol'ed at bad math: "only 50% of us can be above average" That's true for the median, not the average! It wouldn't surprize me if 70% or more of programmers were *below* average, given the vast gap in quality between the upper levels and lower levels of programmers.

Ran Biron replied on Tue, 2009/09/29 - 9:17am

+1 :)

jdelawder replied on Tue, 2009/09/29 - 12:33pm

It was argued whether it would be better to deliver a smaller number of features or all of the features without testing. I'm going to take a neutral stance here and agree with both sides.  I think that unit testing is very important; however, there is no arguing that it inhibits the delivery time of our software under certain conditions.  With that said, if I had to pick one or the other I would have to go with less features that are well tested.

I think Agile development is great and I like the way the industry has moved toward it.  It is better to implement software in iterative "blocks" of features that are well tested.  As we progress through more and more iterations, we can continue adding more reliable and stable features.  This also facilitates the application of TDD and continuous integration.  All excellent.

The sad part is that many of us don't have the luxury to work on projects that are free to implement their own lifecycle.  I work as a contractor and am bound by the lifecycle model that my client wants to follow.  So, in the end we get stuck doing age-old waterfall development.  That lifecycle does not lend itself to unit testing and TDD.  By the time requirements creep has abated you're always behind schedule and testing is the first thing to go because the client doesn't physically see it.

David Lee replied on Wed, 2009/09/30 - 9:17am in response to: jdelawder

Exactly. And most of us work in IT shops and for consulting companies not product companies. As you noted, we simply don't have the luxury of choosing. I've been saying this #### for years.... "working in an IT shop is very different than working for a product/software company". How you deliver software is different, the cost for delivering that software is different, the consequences for bugs are different, the best way to develop the software is different. TDD is not best way to develop software in an IT shop.

Torbjörn Gannholm replied on Thu, 2009/10/01 - 8:31am

Any of the math here is only as accurate as the assumptions. There seems to be an assumption that you can deliver 10 untested features or 5 tested features. That's simply not correct. Writing tests is more code, but all LoCs are not equal. Focused testing, especially test-first coding, leads to more focused coding and clearer thinking, which enables you to develop the features faster. Perhaps you can even write 10 fully tested features in the same time, I don't know, but it's certainly more than 5. The benefit of tests becomes even greater in the next release, when you can use almost all your time to develop new features as opposed to using most of your time fixing the previous ones. And the technical debt of not testing just keeps adding up and your project eventually grinds to a halt. So with full testing, you might end up with, say 21 fully tested and working features in 3 releases and a codebase where you can proceed without fear to make it 28 features in release 4, while without testing you might have 19 working features after 3 releases and a total mess of code so that any new feature you try to add makes everything blow up in your face.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.