Continuation of prior episode: And yet… Could this possibly be the moment to at least pause and reflect? What if it was time for us to start changing the way we work?
Let’s take this bug. In the blink of an eye, you found both the cause and the solution. You opened up the code, made the requisite change and compiled the build. In ten minutes, the application can be released for acceptance testing. But you’ll have to provide the customer with test-case data. And you’ll have to wait until he runs and greenlights the tests before releasing to production.
You rack your brain. You project answers to the questions running through your head:
“What if it doesn’t work?”
“I’m sure it works.”
“And what if it doesn’t work?”
“It wouldn’t be our fault.”
“If it doesn’t work, how long will it take to find out?”
“Anywhere from several hours to several days.”
You think some more.
“Two possibilities: either you have fully fixed this program, or it has one or more new
“If it’s fixed then we’re doing all this testing ritual for nothing.”
“If it isn’t, then of course it’s just as well that we’re waiting.”
You’re groping around in the darkness. There’s uncertainty. But one thing is certain: the room is huge – there’s basically an echo. A huge room cluttered with hundreds of indefinite objects, a crowded mess in which you can’t see a thing. You can only move hesitantly forward, running into whatever obstacles you encounter. This game you have loved playing since you were 15 (that is now running you ragged at thirty) has one rule all players recognize:
What would you rather do in this situation? Would you slow down and hold your hands out to find the obstacles, or would you confidently cross the room? Others might get down right away on all fours to avoid falling. Amateurs. Getting on all fours is like admitting defeat in advance.
You walk upright. Blindly, but upright. You pretend to be able to get out of the room in one pass. You swear: It was the last bug! You say: “There’s only this one very small problem to fix and we’ll be good.” But you’ve never played this game without running into some sort of obstacle. Every time you fall, and every time you quickly jump back up, dust yourself off, and rearrange the stuff around you figuring that it was likely in the shape of a block, a stack or at the very least a heap. There. That should do it.
You would love to be able to go home now. You say to yourself “Tomorrow will be brighter.” But tomorrow, when you return to the room, it will still be just as dark. And maybe you’ll run into things again, odd-shaped things you don’t recognize.
Logic bombs. As you fix one bug, you sow new ones. What could you do that would make a difference?
You certainly aren’t able to turn on the lights. If you could, that would obviously fix most everything.
If only someone would switch on the lights. You can almost hear the crowd sigh with relief: Ahhhhhh!
You look out into the room:
The first obstacle you were systematically hitting hadn’t been put away correctly. Once set in its place by the pillar that obstacle wouldn’t bother anyone, in fact.
You now clearly see some of the obstacles that you had thought were inevitable, insurmountable. You realize you can clear them away in no time.
The obstacle you had thought to be your last hurdle in fact scattered about the room in so many pieces you can hardly count them all. Your “last obstacle” was actually dozens of tripwires.
And in this bright light, with this new clarity, you are on the verge of figuring out the elusive second rule, that very few players know:
But you can’t articulate anything around this second rule because you have neither the means (it would mean knowing how) nor the time (it would take months) to switch on the lights again on this inscrutable project.
Back to reality.
What to do?
Take a break.
You go the corner kitchenette next to the foosball table make yourself some ramen soup. You wander back to your desk to slurp noodles and stare at the purple lines floating around the clock on your screen – 8:45 pm. You down some mango juice and pick up a fortune cookie. You open the wrapper and read your fortune:
Very funny. It makes you think of Jeremy’s joke yesterday. Jeremy, the skeptic who always makes fun of anything related to methodology, had opened his fortune cookie and read in a learned voice: “Every line of code is justified by a test that didn’t pass” which threw everyone into fits of laughter, even those who had never heard it before.
Every line of code justified by a test that didn’t pass. What will they come up with next!?
You log in to your system. Why not? You decide right now, as if it were a principle of survival in a strange dark environment, that obstacles you encounter once won’t get in your way again.
You circle back, open the bugged version of the code. You create a test module. You write a test that fails. It fails because this bug is there. You take precious time writing the test. The code is not easily suitable to tests of this sort. That’s because the test targets a section of the code that should be executed independently of the rest. It seems ridiculous given this section is so tiny. Two lines.
The code is tightly coupled with its external dependencies. The effort expended in creating this test is disproportional to the few lines of code that it will end up testing. All of this for just that. A mountain out of a mole hill. Frustration.
Your vibrating phone interrupts your thought process. It’s Stephanie.
“I heard your message. I ate. Are you coming home soon?”
“Yes, soon. I’m exhausted. How are you?”
“I tried to repair my bike. It’s the gear.”
“It’s a mess. I tried to adjust it but I can’t move the gear without pedaling and when I’m sitting in the seat, I can’t see the gear up close. Plus it’s dark, and the light in the courtyard is too dim.”
“So I turned it upside down onto the seat to pedal with my hands. But the chain doesn’t move correctly that way because the bike is upside down.”
“And you – how are you?”
“What time will you be home?”
“I’ll head out in ten minutes.”
You say to yourself: “What’s the use – it’s impossible!” But think. In the time it took you to decouple this bit of code and write this test, were you really just going to wait around for the customer, doing nothing other than inserting more logic bombs in the code?
You move forward. You break the dependencies. It’s not pretty. The code seems even more overelaborate than it did before this test. You succeed as best you can to isolate the culprit code. It isn’t spectacular, but at least your test runs without any calls to the database.
You fix the bug.
The test turns green.
Maybe you have just enough time to write another test. This part of the code is (in the dark) totally deprived of tests. For this part of the code, you don’t even know what the test would have to assert. You run the test, and the result tells you what the code is actually doing. You paste the result in the test, even though you have no idea whether this represents the truth. You tell yourself that at least you’ve figured out what the code is doing, and that you could come to rely on this test to ask the program manager more questions. That’s more reliable than throwing random hypotheses around in the dark, hoping not to bungle it up.
You decide to stick with this principle for a while, writing a test for each new piece of functionality that you want to create or modify.
It’s as if each time you poke around the dark room, you set down a little lamp to mark your spot. The light it casts may not be very bright, but it will shine on until the end of the project.
You lock your computer and go home.