Duct Tape Programming
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/
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.
- Login or register to post comments
- 3211 reads
- Printer-friendly version
(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
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
Alex(JAlexoid) replied on Mon, 2009/09/28 - 6:25am
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.
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
Rogerio Liesenfeld replied on Mon, 2009/09/28 - 9:49am
in response to: zaph0d
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
Ran Biron replied on Tue, 2009/09/29 - 9:17am
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
Torbjörn Gannholm replied on Thu, 2009/10/01 - 8:31am