Duct tape considered harmful
Blogs are a useful and important tool for professional developers and engineers, for two main reasons. Firstly, by and large, we are not free to divulge the details of the work we do while under contract — but at our next interview, those details are precisely what the interview itself is there to judge. So blogs (and I include this one without question) can take on a professional portfolio role, showcasing examples of professional work as applied to side projects, giving professional opinions on relevant products and work practices and so forth, all of which informs an interviewer who does their research as to the suitability of a candidate for a position. This is an old technique that artists and graphic designers are explicitly familiar with.
Relevant professional blogs can also act as a cheap way to monitor your continuing professional development. They’re not training courses, they’re not accredited and they never will be; but observing what your peers are doing is a very old way of watching for trends that you might consider directing your own CPD efforts towards. Through RSS feeds, RSS aggregator sites and a decent RSS reader, it is relatively easy to monitor large numbers of blogs with little effort beyond the actual reading of new articles as they appear.
The problem is that some bloggers, so focussed on the first goal of presenting a good online portfolio, and so obsessed with metrics like pages-served-per-week as a measure of progress towards that first goal, post dross which can then impede others in the pursuit of the second goal because of the lack (and impossibility) of an effective peer review process. In some cases, bloggers seem to abandon completely the goal in pursuit of the metric – chasing after eyeballs without having anything of substance to then display to this newly captured audience.
The specific example that pushed me to write this comment is this latest post from Joel Spolsky’s blog entitled “The Duct Tape Programmer”. However, this is just the most recent example – it’s a sadly growing trend, and it’s long since turned nasty. Zed Shaw‘s now-infamous “Rails is a Ghetto” post, a forceful criticism of the programming community surrounding the Ruby on Rails platform, has been copied so many times by people attempting to surpass its levels of outrage that he has now in fact pulled the original post from the internet and will not re-release it, believing that these levels of unprofessional comment do no good. It’s a good sentiment, but some degree of comment is still called for — finding the right balance is an ongoing challange.
Returning to the motives for this comment with that restraint in mind, on the first day of engineering as an undergrad we were shown video footage of the Tacoma Narrows bridge collapse. For the few who have not heard of, or seen this, it’s a classic engineering cautionary tale, showing how a groundbreaking theoretical advance in one area of structural engineering failed because of a then-little-understood phenomenon in another area (aeroelastic flutter in this case). It’s often the first example of this shown because it’s got an excellent visual record (the footage is now preserved by the Library of Congress as being of significant cultural significance) and because it’s spectacular to watch with an obvious failure mode; and because no human lives were lost as a result (the unfortunate dog is rarely mentioned).
Later examples of what happens when engineering projects go awry are less pleasant to consider. Whether they be cases where the engineers themselves did nothing wrong, as in the Tacoma Narrows collapse; or cases where the engineers were not listened to, as in the Space Shuttle Challanger disaster or the Hyatt Regency walkway collapse; or in cases where poor engineering was the root cause of the error, like the failed Patriot missile intercept at Dhahran or the Therac 25 radiation treatment system; the end lesson was the same – an unacceptable outcome. A failure in an engineering system can cost lives, even in systems that appear noncritical at first glance. More often, such failures cost enormous sums of money – €355 million euro in today’s money for the Ariane 5 Flight 501 disaster, for example, an error caused by not testing a subsystem within its expected operating parameters. Even the most jaded and unethical cynic who place prices on human lives lost via the cost incurred in compensation and damages by the company held responsible, find such penalties unacceptable (which is, obviously, the justification for financial penalties in such cases).
The standard approach taken to minimise or prevent these unacceptable outcomes is conservative design, using trusted components, with testing and quality assurance being critical parts of the design and implementation processes. In older branches of engineering – civil and mechanical engineering to give good examples – this isn’t a standard approach, it is the only approach. Society decided quite some time ago that bridges that didn’t stay up were simply not acceptable. Younger branches of engineering, however, are only still learning this very old lesson. Computer and software engineering, the youngest branches of all, are in some quarters still wondering if it’s really necessary.
A lot of this is because of the desktop PC market having such prevalence. It’s a large and easily entered market segment, so it dominates teaching and its commercial entities are highly visible publicly – and that (because of the less obvious image of other, larger market segments like embedded systems) may not be a good thing. Few desktop applications have direct critical status where a failure would cost lives. Most software companies specifically preclude their software being used in such a capacity as part of their end user licences. And market forces in the desktop market are such that time-to-market and initial development costs need to be minimised. With pressure like that, and consequences not seen as critical, corners are cut relentlessly. The new sub-market of web programming is even more sensitive to these pressures and has in fact evolved new work practices to cope with them, even to the point of glorifying speed of development past the point of professional efficiency. And critically, that attitude feeds back into the teaching environment, polluting the learned work practices not only of those engineers and programmers who will go on to work in the desktop and web markets, but also of those who will go on to work in markets where failure is far less acceptable and far more costly. This unnecessarily extends training times and raises risks associated with new engineers.
Hence the provocation caused by Spolsky’s post, which states that a “duct tape programmer” (meaning one who rushes code out the door and using the specific example of Jamie Zawinski from his interview in Coders at Work) is a superior programmer. In one way, he does have a valid point, though badly made, with regard to complexity – as pointed out in Thirty Years of C suspiciously recently, some features of some languages (in this case the higher abstractions in C++) are sufficiently ill-understood and poorly standardised in implementation that it is a good work practice to avoid using them. However, while Dyer was making a point based on insufficient reliability and robustness in the available tools, Spolsky is making the same assertion purely on the basis that it takes more time to produce a good design than to use a simpler tool and “duct tape” a solution.
He then goes past the point where there was a defendable justification, agreeing with the throwing out, not only of complex designs with their long development time, but also multiple inheritance, multithreading, and unit testing amongst others. I would certainly agree that certain business practices are inefficient (and Scott Adams makes a fun living documenting many examples of this), but this dumbing-down of the engineers toolbox is ridiculous.
Multiple inheritance in many cases can be an avoidable and poor design choice – but in some cases, such as PyQT GUI design using QT designer, it is the simplest solution to an inherently complex problem. It also speeds development as an additional benefit.
Multithreading is difficult to design for if you rush the design. However, to throw it out on the basis that it is overly complex is to abandon large amounts of difficult problems that require solutions – some situations simply require concurrent processing and cannot be reliably handled in any other way. Embedded programmers have being using concurrent techniques for decades now, and while there are well-understood dangers (and less-well-understood ones, and presumably completely unknown ones as well), it’s a necessary tool in the engineer’s toolbox.
And as to throwing out unit testing on the grounds that it does not add to the final product because the customer doesn’t see it and that it costs time to add — there are some well-known if not terribly polite responses to such a suggestion which to my mind answer the idea insufficiently forcefully. Unit testing – testing of all kinds, in fact – is not an optional extra. To see its abandonment recommended publicly is somewhat outrageous.
Certainly, not everyone writes embedded system code or medical or financial software – and those outside these perceived critical zones might think this testing to be overkill, might feel that if your iPhone mashup app or even your iPhone needs to be restarted because of a bug, that that’s just a small glitch, easily fixed and not worth developer time to prevent. The problem with this school of thought is that we’re coming into (if not already deeply embedded in) an age where people have lost their mistrust of computer systems to the point where they will drive cars onto train tracks into the path of an oncoming commuter train because their GPS told them to, or drive a twelve-foot-tall busload of children under a nine-foot-tall stone bridge because their GPS didn’t warn them (even when the warning signs outside the bus did).
The domain of software which can be considered critical – where a failure can cost enormous amounts of money, or worse, lives – is expanding without much notice being taken. It’s later than you think – and you may already be in that domain.
Testing your code is not an optional extra. And duct-taping a solution can be harmful.
Good show! Finding people that make sense seems to be difficult in this industry.
As a software engineer, it still surprises me that people don’t know about software reliability engineering – http://en.wikipedia.org/wiki/Reliability_engineering#Software_reliability
Speaking of bridges: http://softwareindustrialization.com/TheLostArtOfSoftwareEngineering.aspx
Keep up the good writings!
Joel blogs by hyperbole. He deliberately overstates his case in order to make the point. It’s like acting on stage, you exaggerate your movements because people at the back of the room have to see what you’re doing. Look at a stage actor from 3 feet away and you’ll think they’re hamming it up. You’re looking too closely at his writing.
I’m pretty sure that Joel doesn’t accept his employees shipping shit code. Look at his “Joel Test” that he bangs on about: http://www.joelonsoftware.com/articles/fog0000000043.html All but one of the points are about driving code quality.
The argument is not “just crank it out and ship it as soon as it compiles”, it’s “don’t screw around trying to make it 100%, ship it when it’s good enough”. What constitutes “good enough” depends on the application. If it’s control software for a space shuttle, then you need a pretty rigorous validation phase. If it’s Twitter, then getting it to market trumps any quality so long as it mostly works most of the time. I think you also overestimate the amount of code in the wild which falls towards the “space shuttle” end of things.
Zawinski wasn’t arguing against unit testing per se, he simply chose between thorough testing and shipping on time. In his particular scenario shipping late was not an option, so to get paid he cut the testing. It’s a crappy choice to have to make, but surely tough project management choices like that are the bread and butter of every engineer?
As for the other stuff he eschewed, well, that (to me) boils down to “if it’s complex and you don’t *really* need it then throw it out because it’s more trouble than it’s worth”. Surely that’s engineering in the mould of Saint Exupéry?
Software engineering is a greatly misunderstood idea. Those who think that it’s like civil/mechanical/whatever engineering don’t realise that it’s a fundamentally different beast. I have *never* written a piece of software which I could specify to the level expected in traditional engineering. Unless you have time & money to burn, some design *must* be deferred to implementation. That would be madness while building a bridge or a rocket but it’s perfectly reasonable and sensible for software.
Software developers need to stop pretending that they need to “catch up” to traditional engineering in terms of processes. Software is just different. Sure, we can learn from their mistakes and borrow as much as we can, but sometimes there is no analogy that works and we just have to strike out on our own and learn what works best for software.
One of the main points of Joel, as far as I understand, is that it’s better to provide the customer something that works soon, than something that’s “perfect” later. I think the idea of continuous integration prevalent in agile methodologies reflects this.
It’s also interesting that even though Netscape, the example he so acclaimed, was successful in business terms for a while, it eventually failed (perhaps due to poor quality of code?). Though thanks to Netscape we now have Mozilla. Perhaps it was a lose-lose situation for Netscape. If they had spent more effort on code quality they would might have lost their window of opportunity and never got to re-engineering phase even.
I don’t agree that one should avoid unit testing, multiple inheritance etc. just because they are complicated and not everyone understands them. On the contrary, they should be used if they make your life as a developer easier. You could argue that by properly testing your code you make your life easier on longer term. From business point of view that’s where the catch is. Should you invest on maintainability from the start or handle that issue later even though it might cost more then?
I agree with Conor that software engineering is not directly comparable to other engineering disciplines. It’s called “soft”ware for a reason. Software is malleable.
Arguing by hyperbole to a professional audience is, at the very least, patronising. If Spolsky thinks we can’t discern his argument unless he waves his hands a lot, but we can earn a living producing some fairly complicated bodies of work, I think he’s overestimating the complexity of his argument. So I take what he writes as he writes it, because that’s about the fairest thing I can see to do.
And I agree with the KISS principle – it’s basic, good engineering. But there’s a line between following KISS; and using a hammer to pound a screw into a plank because it’s easier than learning to use a power screwdriver. I think Spolsky’s a long way past that line.
And I remember Navigator when it first came out (I was an undergrad at the time). And it was an experimental piece of code then, not a production system. And from what was seen years later when the codebase got released to the Mozilla project, it never really got past that point. It was so much duct tape that they were paying down technical debt in Mozilla for almost a year before they had a usable codebase again, and even today they’ve got issues with bloat and internal structure. Zawinski might have shipped fast, but we’ve paid for his ship date several hundred times over by this point.
As to the software engineering stuff, I think this is down to perspective. A good engineer has severe paranoia about phrases like ”take off your engineering hat and put on your management hat”, and for very good reasons. It’s part of a good engineer’s training to have that absolutely drilled into their skull because the alternative is unacceptable. And bluntly, I think it’s not acceptable that it isn’t drilled into all programmer’s skulls regardless of their initial training schools. We accept far too much in the way of failure from our software, and it is leaking back into our teaching environments.
And I don’t overestimate the amount of code that falls into the “space shuttle” end of things – embedded systems code far outweighs all other forms of computer code in the wild. And of the non-embedded stuff, well, I don’t consider financial and medical software to be particularly non-critical; and in fact, when you get right down to it, the niche you find Twitter and it’s peers in is absolutely minute in terms of the overall deployed “global codebase”. It’s like android – lots of hype about one phone versus a rather unconcerned and quiet Nokia busily working on that 50% global market penetration…
About the Netscape case.
It was not poor software quality per se what killed Netscape. It was the decision to rewrite the whole thing from scratch. Navigator 5.0 took ages to come out and was buggy at the end, leaving the whole market for Microsoft to take. That is the same unprofessional cowboy attitude M. Dennehy criticizes in this article… (uhh? refactoring is so complex, lets rebuild the whole thing again. yeeeeehaa!!!!)
And the whole point is that software is *not malleable enough*. Every decision has an inherent amount of inertia, proportional to interdependece between the submodules involved and the rest of the system. Bad decisions are equivalent to technical debt. Pick up enough debt in your project (thus, screw up badly and frequently enough) and it will get busted.
A main area of contention seems to be about whether testing is a necessary precursor to shipping a good product. What I find ironic is the use of the metaphor of engineering a bridge as the basis for what makes good engineering. Real bridges are NOT tested. Most of the components are not individually stress tested either (since it would damage it) — rather they are checked for compliance to specification (non-destructive checking). You ever see anyone drive larger and larger trucks over it until the bridge fails?.
Rather, what is regarded as optimal is an engineering discipline that gives the right answer on the first try, guaranteed. Continuing along this line, the best software practices are those which will result in correct code on the first try with no testing. This is an achievable goal. The whole focus on ‘unit testing’ as a means of ensuring software quality is misleading — the very best it can ever do is _confirm_ and _validate_ already existing quality. Testing cannot ‘ensure’ quality that should have already been there by the development methods and tool-set used to create it.
I agree that the basis is this is to start with 1) known good components and 2) known good methods of combining these components. The known good components and assembly processes themselves need to be known as good by similar arguments — that the methods used to create them are also of such a nature to guarantee the right outcome. Even on the component level, testing can only validate the quality that should already be there on the basis of the guarantee.
People have a knee jerk reaction to any suggestion that quality is a result of something other than testing. Confirming a process via testing is simple to understand, much simpler than understanding why a certain outcome is guaranteed by design. Management loves testing because of its simplicity — it is all they are usually willing to understand. Since most management cares primarily about minimizing risk, and “testing” seems to be the best “legal standard” by which they can protect their own reputation, it is seen as being the answer to all software problems. Unfortunately, it is a complete red herring and actually serves to _keep_ software design practices in the relatively primitive state that we still see them today.
Advocating testing as “quality assurance” has some short term tactical value, but it is strategically useless — you may win some battles, but you will definitely loose the war.
Software will never get better than “good enough” unless a more authoritative approach — more than simple testing, at whatever level — is used.
To return to brass tacks: To a customer, the *only* value of a software product is in the increased potential on the part of the user to create/manipulate something of significance (typically data). Therefore, code is not value. Design specifications are not value. Requirements documents are not value. Testing is not value. None of these things add value — only the increased potentials (the shipped functionality) is real. The rest are ultimately distractions. The only _guaranteed_ way to establish something in aggregate (some data transaction or transformation — a functional operator) as being _possible_ (ie as potential and value) is to use construction and build methods that themselves establish and are composed of guarantees. Testing never establishes a true guarantee; it can only validate one — a crucial difference.
Is testing a necessary precursor to shipping a good product?
No. A good product is built out of goodness using good techniques — not testing.
Joel’s audience is as much managers as it is programmers so I don’t think it’s fair to ask him to treat his audience like grown-ups. Not all of them are. 🙂 Also, in fairness to managers not all the programming audience of Joel on Software will be careful readers either.
Netscape died primarily due to business failures, not technical ones. Sure, they built up a pile of technical debt but ultimately they lost market share because IE was bundled with Windows and heavily pushed by the dominant software company of the time. They ended up in a fight with an 800lb gorilla so there was only one inevitable result.
Also, if they had taken it slower and produced a better product arguably we wouldn’t have the Mozilla project. Netscape would have been squished a lot easier and a lot earlier.
Netscape was buggy as hell (NN1 was my first real browser – I don’t think Compuserve counts) but so were all the alternatives and having a web browser beat the hell out of having no browser at all. Plus, even v1 was more reliable than the net connection it was using so it would have been a waste of time hunting down the odd crash here and there. Chase the big wins and all that.
End users don’t care about quality until it bites them in the ass. Even then, it’s hard to make them care because the net cost of poor software quality is far outweighed by the net cost of demanding high quality software. Also, how often do you have a software crash causing loss (as opposed to a bug that doesn’t damage anything)? For me, it’s less than once per month and it’s rarely more than about 5 minutes of my time lost. I’m a pretty heavy user of software so I’d assume that the average person sees less than that. Is it truly worthwhile paying to chase down those bugs or are we better off considering it a cost of doing business? Would I pay more for my software to get that time back? Probably not. I’d pay more for better UIs but TBH I’m pretty sure I’m in a minority on that front.
Code quality, cost and date of availability are all traded off against each other. In an ideal world (for us software guys) the business concerns (cost and arrival time) would be dictated by the quality but they’re not and they won’t be. A good coder will strive for the best quality possible within those constraints but a lot of the time (in my experience at least) the result is that the shipped code is known to be buggy. Do you think that there could be a *significant* increase in code quality without an increase in cost or time?
“embedded systems code far outweighs all other forms of computer code in the wild” [citation needed] Are you calculating in terms of volume of code or volume of usage?
About bridge building – firstly, large numbers of structures like the Silver bridge failed precisely because of insufficient testing. The response was to improve testing and make it more invasive, not to “find more goodness”. And no, you don’t see some poor schmucks being paid to drive more and more trucks over bridges until they collapse – because oddly, killing people in bridge collapses is no more acceptable before the bridge is opened than it is after that point. There are significantly more advanced testing methods available – and testing to destruction is still done, by the way, just not with the components you’re putting in the bridge. (Those you are going to trust like that are tested to ensure they’re identical to the ones you verified through destructive testing).
To return to brass tacks, as you say, the difference in our views lies here : the value to the customer might be the increased potential that software provides; but the value to the user is the actual benefit it provides, weighed against the cost. And not only are those different metrics entirely, they’re also different people. The customer is someone you want money from and haven’t gotten money from yet; the user is the person who has to use your product. Not all customers are users, and their interests may well conflict, and in such cases, the customer is certainly not going to keep the users interests in mind. It falls to the engineer who builds the system.
Coding for customers may ship product; but that road leads to the Ford Pinto Memo way of thinking. Coding for users may not make you a millionaire, but it produces better software.
If Joel is writing for managers without technical knowledge, then he is doing no favours to us working stiffs by recommending stupid ideas like losing tools from the toolbox. It’s hard enough to produce something without having a PHB tell us what tools to use when they have no idea what those tools are or do. And as to recommending dropping testing to PHBs because it doesn’t add value, well that’s just plain vindictive.
And I’m pretty sure you’ve got the same perspective issue going on here that I mentioned below. There’s coding for customers (where you want to ship, ship, ship because there’s money to be made!) and coding for users (who are often not the same people and whose interests conflict with those of customers, and quite often, it’s the user who takes it in the neck instead of the customer when something goes sideways). Engineering is very insistent that engineers code for users – business and management are very insistent that engineers code for customers.
Thing is, every engineer out there is (or should be) immediately remembering the phrase “take off your engineering hat and put on your management hat” when faced with that choice.
Historically speaking, we’re in a unique place right now, right at the start of all our fun stuff becoming part of the infrastructure. This has happened to all the other branches of engineering over the years. Mechanical starts off as a bunch of guys trying to build something and sell it, there’s little in the way of ethical considerations, it’s ship-ship-ship all the way; over time, as society becomes dependant on what they’re building, the requirements of the actual user, and the ethical duties to that user became prevalent. It’s not so much a point you hit in the development of the industry as it is a phase the industry slides into, and we’re mid-slide right now from what I can see.
When we start seeing the first serious legal penalties coming in for poor software engineering, that’s when we’ll know we’re nearing the end of that slide. Thing is, waiting until then to adjust our techniques is somewhat unethical.
As to the amount of embedded code out there, Ganssle estimated off back-of-envelope calculations that there were some five million embedded projects out there, with around 240,000 more coming in every year. He wound up with a 50-50 split between the embedded and non-embedded codebase sizes. I’ve seen papers from ACM conferences which go further than that, to the point where it’s projected that 60% or more of all code written everywhere next year will be for an embedded system.
[…] Duct Tape Considered Harmful (Hacker News)Signs of a Programmer Created UI (Hacker News)09/21/09 PHD comic: 'Annual Grad/Faculty Softball Game, pt. 4' (PHD Comics)TEDTalks : Rebecca Saxe: How we read each other's minds – Rebecca Saxe (2009) (TEDTalks (hd))WordPress Just Made Millions of Blogs Real-Time With RSSCloud (Hacker News)Work expands to the time allowed (The Endeavour)Three algorithms for converting color to grayscale (The Endeavour)TEDTalks : Dan Pink on the surprising science of motivation – Dan Pink (2009) (TEDTalks (hd)) […]
[…] Duct tape considered harmful Blogs are a useful and important tool for professional developers and engineers, for two main reasons. Firstly, by and […] […]
Perhaps I can restate in another way to make my notion about testing clearer. If I start with a steel bar of a specific thickness and length, as an engineer, I am going to ‘know’ that it will have certain tensile capabilities, bending moments, compression resistance, etc. I do not need to perform any tests to know that a bar of this kind is going to have certain functional characteristics — it is inherent in the physics and is reliable knowledge.
Note that testing to _validate_ that the material is in fact steel and is correctly formed is an inherently /different/ kind of testing — it is a validation of what something is, rather than what it does. This is also very different than testing a new, otherwise unknown material, to identify what sort of characteristics it has. Neither of these other types of ‘testing’ has anything to do with the basic idea that it is *only* possible to argue causality in the direction from what something _is_ to what it _does_. IF we are working with a bar of known size, material, and mechanical correctness THEN we can be certain of its having known functional properties. *All* engineering modalities, regardless of kind, depend explicitly and completely on causal relations of exactly this type: they all are causal statements that go from what something is to what it can be expected to do.
The basic problem with software ‘testing’ is that it attempts to go backwards, against this necessary and fundamental flow of causality. Software testing attempts to go from testing what some code /does/ (its functions) backwards towards assertions about what it /is/ (its quality/correctness). Not only is this terrible engineering practice, it goes against the very nature of logic itself. Software testing is the logical fallacy of affirming the consequent. It is the syllogism of attempting to argue from statements: 1) “IF A is true THEN B is true” and 2) “B is true”, towards the inherently faulty conclusion of “Therefore, A is true”. How different is this from the idea of software testing which writes tests in from of “IF our algorithm is correct (of high quality), THEN it will perform function Z”? When the code ‘passes’ the Z functional tests, then the QA department, engineers, management, etc, feel/think/claim that they can then assert “the algorithm is correct” — yet this is not so!
The basic problem here is inherent the very idea of how most people conceive of the function of software testing. Testing of system function (what something does) does will never allow for a way to argue backwards “that the system is of high quality” (an claim of what something is). Conflating the basic notions of validation testing (testing what something is) with property/characteristic testing (testing what it does) — as many people do — will not help (posts above make this mistake). How often do you find yourself or your peers thinking: ‘because the unit/system tests have all passed, that/therefore the system is of high quality (ie, reliable)”? It is a surprisingly insidious and common idea — yet even having a majority of practicing software professionals believe it does not make it logically correct — it is still complete bullshit to think that ‘software testing’ as it is currently conceived has anything at all do do with software/system quality.
Software design practices will remain at a infantile stage forever, unless and until the basic logic and principles of structural casual process are recognized and incorporated into the code writing methodologies at a primary and fundamental level. Chasing after ‘improved testing practices’ (TDD, etc) as a ‘silver bullet fix’ is inherently broken. It is a fad, and it will pass. The rise of TDD is more the result of management types trying to get useful code work from masses of unskilled ‘developers’ (cheap labor) than it is a reflection of any basic principle of ‘good software engineering practices’. If you reflect on it, you may notice that TDD proponents all tend to be associated with development groups that are much more cost-driven than quality-driven: TDD is seen as a way to avoid hiring truly skilled engineers, instead replacing them with vast numbers of code monkeys. As a truly skilled engineer (the minority) would you wish to contribute to the promotion of this basic fallacy?
Forrest, to look at it more clearly, if you have a bar of properly formed steel, you know it will have a tensile strength of X from prior destructive testing on other bars. Your testing, therefore, is not to see if X is the tensile strength; but if the bar is properly formed. It is indirect testing.
With unit testing, you exploit the fact that you can directly test software by seeing if it does what it’s meant to – whereas with a bar of steel, if you test its tensile strength directly, you have to do it destructively.
There’s nothing running counter to the flow of causality here. It’s a different form of testing, that’s all.
Thank you for writing this post. It is very nice to see someone write about the dangerous and uninformed writings of bloggers such as Joel Spolsky.
[…] This post was mentioned on Twitter by Web Startup Group, Mark Dennehy, hnquestions, Hacker News, Thomas Buck and others. Thomas Buck said: Why Joel Spolsky was wrong about 'duct tape programmers' being good programmers. http://bit.ly/cmuRvZ […]
The day someone shows me a skyscraper you can jack up and move to another continent or add twelve basement levels to is the day I’ll accept the civil engineering analogy.
And the day you can rewrite Linux in pure haskell is the day you’ll have an analogy that works.
Both the author and Joel Spolsky are right, but at different ends of the spectrum. When this subject comes up, it is a discussion of Technical Debt. The way I explain it is that technical debt is just like how you pay for anything else: you pay now or you pay later. Joel’s argument is acceptable if you decide to pay later, where time-to-market is vital (and a moot point if you don’t get there first because you go out of business), and is analogous to a credit card. You save now, but incur huge interest payments later. *As long as you understand that*, then it’s a valid choice. What is an *invalid choice* is to decide that you want to pay later but then change your mind and expect software maintenance to be free in the future.
The author’s argument is also correct: in safety-critical applications, you *cannot* pay later. It’s like paying for a product where they don’t take credit cards, only cash. And in regards to testing, I don’t buy the argument that software should be like bridges but that bridges are not tested but are reliable due to specifications. That may be true for bridges, but software cannot have quality constructions that way. The reason is simple: *unlike* a bridge, you only ever write software once! There’s no point in writing the same software code again and again, you simply copy it! Bridges can’t be duplicated out of thin air, they have to be rebuilt again and again. Every software coded is new in some way, and THAT is why you must test it.