"An idea, like a ghost, must be spoken to a little before it will explain itself." - Charles DickensSometimes, we do things in our programming practices that just seem right. But we may struggle to figure out how to illustrate why it feels right to colleagues and peers. We have a vague idea, and some of the words involved, but a succinct explanation evades us. This post, is an attempt to shed a little light on some of the principles I follow in regards to "unit testing." Some of this fell into place, just days ago, though I've been doing this a certain way for 12 years now.
Back in the 50's, there was a sort of revolution that took place in the manufacturing world. Quality was the issue. Leading role was played by E. W. Demming. Some of the plot themes were things like process control, quality control, statistical process control, shewart charts, kanban cards, etc. It was a big hit in Japan initially, and would eventually make its way over to the States and other places. As a Mechanical Engineering student, I had this stuff pounded into my head through long years of college.
One of the things that struck me about these ideas (ideas that would eventually be caught up in and respun as "lean or agile" manufacturing practices) was a subtle shift in quality testing. Many factories convinced themselves that they had quality because they did testing. Classic manufacturing testing philosophy, said that you assembled the gadget, and at the end of the factory, you ran the assembled device thru a screen of tests. If it passed these tests you shipped it. In this era, the bolt vendors could be pretty lax in their tolerances; assembly personal at the plant would take up the slack, pairing bigger bolts with bigger washers and smaller bolts with smaller washes. As long as the machine at the end performed it's function nominally, it was good enough. Of course, when the device came under stress, this variety led to failures and subpar performance.
Demming and crew, felt that this was pointless to catch defective products that late in the cycle. It was wasteful. So they pushed testing and quality control back into the process. They advocated tolerances on the component parts, rather than the unit as a whole. The basic idea is that if you tighten up the quality on the parts that compose your device, your device ends up the better. In fact, if you had a controlled process, and high quality inputs, then you could confidently ship higher quality products while actually reducing end testing. In years to come, those that made the change to this mentality survived, those that did not, mostly failed.
It's instructive to me, that while both methods advocated and adhered to "testing", the Demming approach and application of testing was the one that produced better results.
Since the "splashdown" of XP in 1998 and the following furor of Unit Testing in Software, I've witnessed similar parallels in the application of testing software. Everyone claims they do it. When Ken Treis and I came home from OOPSLA 98, we determined we'd try this. We put together a version of a Wiki server for VisualWorks, and we used workspace scripts to make test that we got the right http responses when we sent different kinds of queries against our server. And having done that, we went right on writing software the way we always had. It didn't really matter how we architected the code as long as it passed these high level tests. Of course, we kept discovering all kinds of edge cases. Though I was well versed in the Demming school of thought about testing the components, rather than the end product, I missed the potential corollary.
It wasn't until Camp Smalltalk 2000, when Ken had the chance to work with Ron Jeffries, that we got a chance to see it done right. Ken saw, and quickly shared with me, what a real unit test looked like. The light bulb went off for us. This would change the way we developed our algorithms at a component level. I've been a happy unit tester since. I am firmly entrenched in the belief that unit testing is to software what component testing is to manufacturing. Usually, it takes the form of having a particular test class for each meaningful class in your system. There are of course adaptations, but more often than not, I find that the adaptations are rationalizations that allow people to test in the "old school" style while telling themselves they're doing it differently and making a real difference.
In manufacturing, the point is to reliable reproduce and accepted design. In software, we don't do that. The ability to reproduce our software designs, is not in question. The creative part of what we do, is to create algorithms, of various sizes and shapes, of varying complexities. When we write unit tests for the components (or objects) of our algorithms, we're embracing the same set of principles that drove the quality revolution. Try it out. Don't write so many tests for the overall features of your system. Try writing tests for your components. One to one.