Black box testing explained
Whether or not you’ve heard of “black box testing”, you’ve certainly performed it. As the name suggests, it involves treating the system you’re testing as a proverbial black box—that is, you don’t know or care how it works, just that it does. For example, to test your transmission repair job, drive down the block, maybe even onto the highway, and make sure the car shifts smoothly and doesn’t make any weird noises. See? You’ve been black box testing your entire life. Heck, you might even call yourself an expert.
Allow me to let you in on a secret of the web development trade: the hard part isn’t building something (at least, something small) that holds up to a little black box testing. In fact, I’d go so far as to say that part is quick and easy¹. Sure, it’s more work if the testing is at least thorough—for example, the tester is checking across breakpoints, touchscreen devices, and browsers, and maybe even trying an unusual series of steps—but in most cases, I could spend about a third of the development time I normally would if the only requirement was to pass a black box test.
But let me elaborate: I could only spend a third of the amount of time on the first task or two you assigned me. If I had to do more than that one task and kept spending the bare minimum amount of time on each, things would start to change: the time needed would start to grow in proportion to the amount of shortcuts, or “technical debt”, that had accumulated. As things devolved further, you’d start to see more and more regressions, or unintended side effects (in some cases, I’d know these problems were going to happen and just have to increase the time spent to avoid them, but in others, it would be entirely unexpected). If I were working alone, I’d at least stand some chance of keeping things together despite the chaos, mostly because I’d have a good idea of where the “bodies were buried”, so to speak (after all, I would have buried them all myself…). But if there were even one other developer working on this project, never mind more than one, things would rapidly slow to a frustrating crawl of compounded mistakes and inefficient fixes.
So if my one-third estimate is correct, the truth is that I spend a full two-thirds of my day making sure my work is clean, well-documented, and done “right”. Perhaps it’s not the most glamorous work, but I would not for a second try to shortchange it, and I know both my fellow developers and our clients are better off for it (and I hope they’re grateful!).
Maintainable code: a basic example
An easy way to communicate time to a computer is to just convert it all to a single unit, typically seconds. That is, instead of saying “one week”, just write “604800”. Doing so removes all ambiguity (Are there 30 days in a month or 31? Is a day the same thing as a día?) which is precisely what you want if you’re a computer or someone trying to communicate with one. The only downside is that, if you’re a human, it’s a little harder to decipher.
Okay, pop quiz, how long is this:
If the first thing you thought was “10 seconds short of a non-leap year”, hats off to you (warning though: you may be part cyborg). For the rest of us, we can make the task a little easier simply by rewriting that number slightly:
(365 * 24 * 60 * 60 - 10)
Not so bad, right? The beauty of that notation is that you can come to the same conclusion whether you’re a computer or just a simple human without a calculator.
When black box testing comes up short
Clearly, 31535990 and (365 * 24 * 60 * 60 - 10) would be indistinguishable during black box testing—that is, things would still appear to work identically either way.
But in the context of software that will be touched by multiple developers, perhaps separated by long periods of time, they are far from identical: one is easy to read, and the other is not! That legibility makes a difference not only in how fast you can interpret what the original author intended, but also in how likely it is that you’ll make a mistake. For instance, consider what happens if we unintentionally swap two digits in each version. One of these should now look wrong, at least on closer inspection; the other, while also wrong, probably still looks like the same incomprehensible gobbeldy-gook it always did:
31553990 (365 * 42 * 60 * 60 - 10)
Oh, and by the way: if you still only care about whether or not this code is functioning as intended, there’s a good chance you’ll have to wait nearly a year to finish your black box testing…
Code review to the rescue
Of course, that example is merely the tip of a very, very large iceberg of issues that are exceedingly difficult or downright impossible to turn up with black box tests. Fortunately, where black box testing fails us, another, more powerful tool comes to the rescue: code review. In short, once a developer has completed a chunk of work, not only can we have someone else test to make sure it functions as expected, but we can also have a second developer look over the code itself to make sure the underlying logic is both sound and maintainable.
Say, for instance, I didn’t know any better and had left the time in our example above written as 31535990. Testing would find nothing amiss, but an experienced code reviewer almost certainly would. Not only would this ensure that the codebase stayed readable and tidy, but I’d learn something, becoming a better developer in the process. The reviewer could even go a step further and question why I felt it necessary to use 10-seconds-short-of-a-year as the time interval; perhaps there would be a more elegant way to accomplish the same thing. At the very least, the code reviewer would be aware of what I’d done and why, and be able to use that knowledge in their own work on the same project and beyond.
¹ Most developers and project managers recognize the danger in this phenomenon: show all your work to a client too soon and they’ll often mistake it for something that’s practically done (and then wonder why on earth you end up taking so long to finish).