What is a bug, anyway?
The answer depends a great deal on who’s asking:
If the user reports a bug, they basically mean, “I was using the software and something happened that I wish was different.” This could mean that the “delete” button works perfectly, but that they didn’t mean to press it. Or it could mean that the back button in a SPA doesn’t revert to what they thought was the previous view. Or it could actually represent a flaw in the code. But these situations look similar to users, especially non-technical users.
A bug here is basically a discrepancy between the user’s mental model of how the app should act and how the app acts. (And remember, as far as your user is concerned, your app is your user experience.)
As a developer, when I think about bugs, I tend to think of them as code first. There is something intrinsically flawed in the code. The flaw might only be exposed in one narrow set of circumstances, and therefore be hard to find. But code is, in some way, actually wrong. These could be something silly, like an off by one bug in an array index, or downright hard to find, like a rare race condition in some cache refresh. But whatever the difficulty of the bug, it’s a code flaw.
By “specifier” I mean anyone who helps design the software. It could the a program manager, a client of a consultant, a project lead, another dev. This perspective on bugs has three distinct subspecies:
- The code does not implement the specification
- The specification does not meet the specifiers expectations.
- There is behavior that was never specified, but turns out to be relevant.
Case 2 is very similar to a user bug. The code doesn’t do what I thought it would. Case 1 is probably the only clear cut instance in this article of a mistake by the developer.
Case 3 can come in a variety of flavors. One example is a “What about time zones” kind of bug: your code checks to see whether two events occur on the same day, but forgets to check which time zone the two events were in. Everything is fine until, suddenly, the Hawaii office starts post-dating checks when they work late. We’re in case 3 because no one said what should happen if the two events are in different time zones, but then in real life it came up.
If they developer faithfully implemented the specification, but the specification didn’t say anything about what the back button on the browser would do if you pressed it on the receipt page, so the developer didn’t make any effort to control that behavior, and now the user wants that back button to return them to the last item they added to their cart, no one’s happy, and no one’s really in the wrong. So who’s right?
No one, really. There isn’t some Platonic form of ideal software floating around that we failed to implement. There also isn’t some user interface that will perfectly protect people from accidentally doing the wrong thing. There are, however, some guideposts:
- It should be easier to do the more usual, safer, more normal tasks. For example, in a photo app it should be easier to view the photo than to edit it, easier to edit it than publish it, and easier to publish it than delete it. (At least, if your client base is careful about what photos they publish.)
- It helps to get second opinions early in the process. If the specifier or a user acceptance tester doesn’t like the way an app behaves, decide what needs to change. If no one sees how the user interface looks until the app is almost done, people will be surprised and unhappy.
- Don’t take it personally – the goal is that your software should be fun and easy to use, not that you should be right about disputes.
- Compromise – there are tradeoffs in every discipline. If you want to have a button for X, you can now no longer have a user interface with only 3 buttons. If you want the button to be blue, it can’t be green. Iteratively move towards the best compromise.
Remember, software can’t be perfectly specified without being written. If I’m ordering bolts, then by the time I specify the expected strength and tolerances, the length, the thread pitch, the diameter, etc, I can exhaustively specify the bolt. Any order of bolts that arrives not meeting my specifications is clearly wrong.
Software is not like that. If I order an iPhone app, I can’t specify the behavior exhaustively in every case. A specification so exact that it can be mechanically implemented without human decision making is the source code, not the documentation. I think that’s why waterfall doesn’t work with software as well as it works with, for example, bicycle manufacture.
With bicycle manufacturer, I could specify all the materials and assembly processes for the bicycle, get them working, and then regard any deviation from this spec as a flaw in the bike produced. The upfront spec is king.
Imagine for a moment that you’re a bicycle manufacturer, and you’ve just gotten your designs set up with an assembly line and bikes are flying out the door. Your phone rings, and your panicked customer asks, “these bikes sync with Outlook, right?” The upfront spec cannot be king because software cannot be specified exhaustively except by writing it.
In an analogy to manufacturing, the source code is the engineering spec and the compiler is the manufacturing process. And we have pretty thoroughly debugged compilers at this point.
I think where the process does need some refinement is getting the compiler’s output into the hands of the customer. If we want to stretch our manufacturing metaphor a little farther, that’s where shipping logistics comes in. For an interesting account of that, you should read The Phoenix Project. But the software, the source code itself, is always subject to change. Being ready and able to change it when you realize that the spec is wrong, or that the spec is right but the user doesn’t like it, is key.
Till next week, happy learning!