Often, in the software development game, we’re asked to add a feature to an existing system. Sometimes this system has been around for a long while, as there’s no notion of “planned obsolescence” in much of software.
I recently encountered a situation that is highly symbolic of the problem, if not an actual software issue, per se.
At an office I’ve worked in, they have very nice washrooms (yes, this is related to software – bear with me here). They’re modern, with nice clean stalls and such, and feature toilets with the “auto-flush” feature you’ve no doubt seen elsewhere.
Once you’ve finished your transaction, you just finish up and leave, and the sensor detects you leaving and auto-flushes the, ah, buffer, for you. Excellent, now you can be free of having to remember to do that yourself, and assured that it’s already been done when you enter the stall. Kind of like auto-commit on a JDBC connection. Well, kind of.
Anyway, let’s talk about feature conflict.
A new feature was recently added to this fine setup: paper seat liners. You’ve probably also seen these – they’re the nice little rings of paper in a dispenser, usually on a wall, that allow you to isolate your back-end interface from the implementation details of the toilet seat.
Also very fine idea. In the case of this particular washroom the dispenser for these is attached to the wall behind and above the toilet itself.
Taken independently, each of these features (auto flush and seat liner) seem like perfectly good features, and their implementations are quite reasonable. In functional testing, each performs exactly as it should.
The difficulty comes in integration testing, when you try to use the system as a whole.
Let’s take a use-case and walk through the scenario: The – ah – user enters the system. Standing in front of the toilet, he (definitely he in this particular case) decides to avail himself of the seat liner, and removes an instance from the dispenser. No problem. At this stage, the auto-flush sensor has already detected the presence in it’s scope, and does nothing, as it doesn’t trigger until you leave the area.
Now an implementation detail: the way the paper liner works is that the spot in the middle of the paper is cut out, and drops down to touch the water, while remaining attached to the remainder of the liner. The idea here is that when the water leaves during the flush, the liner will be drawn down into the bowl with it, and appropriately de-allocated. As we’ve said, previous functional tests verify this works just fine.
Now let’s assume the user has correctly deployed the liner, and wishes to transact his business. Well, if you were facing the toilet when you came in, you probably don’t want to be anymore at this point, so you turn around. Here’s where the feature conflict rears it’s ugly head: the flush sensor, noting the movement, often picks this moment to decide it’s time to flush.
The liner, having deployed correctly, departs the scene at this point, just as the user completes their interface. Unfortunately, that is the moment at which the liner is supposed to be there. You see (or, more correctly in the case of the user, feel) the problem.
So, which feature is broken? Taken one at a time, neither is broken – they both do exactly what they’re supposed to do. The failure is at the point of the wholistic view of the overall system, and neatly demonstrates the fact that it’s impossible to consider features or potential features in isolation, in any system. You must consider scenarios of users actual interactions with the system, and how the new feature will affect those scenarios.
Nobody said it’s easy, but it’s important.