Our coffee machine is currently at the shop for repair, so we’re stuck drinking instant. It’s not fantastic, but it’s really all right in a pinch. In fact, my parents exclusively drink instant because it’s what they’re used to — seems like a pretty common thing in the UK and is probably a war relic or something (I haven’t looked it up).
Instant coffee is really easy to make: you take some coffee granules1 from a jar, put them in a cup and add hot water. If you’re an uncivilised barbarian, you then add milk and/or sugar. And this is what my fiancée2 — let’s call her Evelien because that’s her actual name — was doing on this hot Sunday morning while I was still lazing in bed.
I know that’s what she was doing because she woke me up and handed me a cup, saying “try this”. Bleary-eyed, I took a sip of what was the second-most3 disgusting cup of coffee I’ve ever tasted. It was extremely sour. “No,” was all I could muster. To her credit, I received a glass of water in return.
This was Evelien’s third attempt at a cup of coffee this morning, and she had me try it because she was starting to think something was wrong with her taste buds. So what had she tried so far?
Making the Coffee #
The first cup contained granules from the same jar she’d used (with success) only yesterday, hot water, condensed milk4, and a sweetener tablet. Sour.
After the first cup she checked the condensed milk and thought it smelled a bit off, so tossed that.
The second cup was identical to the first, but this time with brand new condensed milk. Still no good.
For the third cup, she decided it was time to get out a new jar of coffee granules. Other than new instant coffee, this was the same and produced the same sour result (this is the one I tasted, bleurgh).
Back to me, in bed, wishing I’d never woke up. She more or less told me what she’d done. I’d just had a sip of water.
“Is the kettle okay?”
And so it unfolds that Evelien had descaled the kettle yesterday, with vinegar, and completely forgotten about it. Yup, we were drinking coffee made from vinegar in place of water.
A Better Approach #
We got to the root of the problem in the end, but it took three cups of coffee, some waste, and a fair bit of time. And our relationship had taken on some serious trust issues.
But what have we learned? How could this be approached better? And why am I talking about making coffee on a software blog?
The main issue is that ingredients were mostly tested as part of the finished coffee. Instead, they could have been tested either in isolation or as part of a gradual process.
The milk was tested in isolation, which is great. The water was not. And what about the water after it had been boiled? After coffee had been added?
In software, it’s easy5 to open up a CLI and confirm any suspicions. Is your coffee coming out weird? Bust open a CLI, check
water.tastes_ok? regardless of the outcome, you’ve just narrowed down the potential set of issues.
Another fantastic tool in your box is your debugger. Making coffee is trivial, but building up other systems may not be; a debugger lets you inspect state at each step of the way, letting you home in on the real issue in no time.
def make_coffee(water, coffee_granules, sweetener, milk, kettle) debugger # water.tastes_ok? # => true # next heated_water = kettle.heat(water) # heated_water.tastes_ok? # => true # next coffee = Coffee.new(coffee_granules, heated_water) # coffee.tastes_ok? # => true # next coffee.add(sweetener) # coffee.tastes_ok? # => true # next coffee.add(milk) # coffee.tastes_ok? # => false # We now know that the coffee only turns bad after adding the milk. # milk.expired? # => true # And now we know why. If we didn't, we could next step into the `Coffee#add` method and see # if it's doing something unexpected. end
If you’re working through a particularly complex process, throw a couple of breakpoints at milestones and skip between them; you’ll narrow down the issue quickly (divide and conquer).
echostatements in their code rather than a debugger. This works in a pinch, but it’s a poor man’s debugger at best. Spend some time setting up and getting used to a real debugger; you’ll thank me later.
Ultimately, software engineering boils down to finding solutions to problems. We solve problems all the time in our day-to-day lives, and the process we use — whether in software or the real world — is much the same.
When something unexpected is happening with your software, you need to go from “the coffee is sour” to “water from the kettle is gross” to “the water is vinegar and needs replacing” in quick order. If you’re trying to determine the problem based on the state of the whole system, you’re just making stabs in the dark. Break it down.
These are made from brewed coffee that has been dehydrated. Yes, it’s real coffee! ↩︎
Evelien is one of the most intelligent people I know, although this story does seem to disprove that. I got her permission to write this. ↩︎
#1 is a story for another time. ↩︎
This is the go-to dairy coffee additive in the Netherlands, called “koffie melk” or literally “coffee milk”. It comes in small cartons or bottles here, whereas in other countries it’s sold in cans. ↩︎
Actually this depends on which language you’re using. It could be trivial, or it could not be. Maybe your language has better tooling in other areas. ↩︎