Object-Oriented Sandwiches – Part 3
Welcome to part three of a series where I’ll attempt to explain Object-Oriented Design (OOD) through the metaphor of a fictional sandwich shop. In this part we’ll learn about building trust in your objects through Test-Driven Development.
These examples build on the previous posts, so if you haven’t read them yet, start with part one.
Welcome back to the Rubytown Sandwich Shop
We’ve discovered that the sandwich shop is a collection of things which communicate in specific ways to get work done. Bob and Jane trust each other, and so far they’ve been able to take care of all the shop’s responsibilities, but it won’t be that way forever. How can a business (and an application) change and expand without falling apart?
Just when the sandwich shop has really started to take off, disaster strikes. Bob’s increasingly-frequent illnesses have finally driven him to see a doctor, and she gives him some bad news: he needs to start taking it easy or something bad is going to happen. Jane knows from experience that she can’t run the shop alone, so they’re facing a difficult challenge: hiring employees.
Bob hates this idea: as we’ve seen, he’s a bit of a control freak, and the idea of not having his hands on every sandwich gives him hives. His first instinct is to hire some random person off the street and just order them around the kitchen, but Jane points out that he’ll get more tired yelling at the “new kid” all day than he would making the sandwiches himself. And as we established in the last post, “nobody likes a micromanager”.
When you’re green, you’re hired!
Jane has an idea: they’ll make up a list of things the perfect employee would be able to do: toast, slice, stack ingredients, wrap sandwiches. Each applicant will go into the kitchen and attempt to do everything on the list. If they can do them all successfully, they’re hired! While she’s at it, she makes a different list of things an employee would need to do to run the counter: write down orders, make change, restock napkins. Bob and Jane can get away with simply putting a “Now Hiring” sign in the shop window, but a larger organization with many positions to fill would send out a formal job posting with the responsibilities listed out, to filter out inappropriate applicants without having to waste time interviewing them.
In programming, this idea of deciding what an object needs to do before we create it is called Test-Driven Development or TDD. If the object passes the test, we know it implements the behavior we want (which is why some people prefer the term Behavior-Driven Development or BDD). Our test might say “I’d like to be able to send a ‘stack’ message with a list of ingredient names, and the object would return a stack of those ingredients in the same order”. Naturally, if we run this test it will fail, because the object doesn’t even exist yet! Since most testing frameworks return a failure report in red text, we call this a “red” test.
The interesting part of this “hiring process” for objects is that we can create the dream employee exactly the way we want! We can create a class for the object and run the test again: this time it will fail with an error that says it found the object, but the object doesn’t behave the way we want. This is progress! We write some code to implement the ‘stack’ behavior, and now the test succeeds (typically reported with green text). We call tests that succeed “green” tests.
The complete sequence of writing a failing test then writing some code to make it pass is called “Red, Green, Refactor”. Refactoring is a process of cleaning up code that already works to make it easier to maintain, but we’ll defer this very-important step for the moment.
It’s about trust
Bob thinks writing out a whole formal list of things an employee can do is a waste of time. He wants to just hire somebody and see how it goes: if it doesn’t work out, he’ll fire the new kid and hire another one. Jane points out that while the new kid is working, their customers might be getting the wrong sandwiches or waiting too long for their orders. Does Bob want to risk the reputation of their business because some high-school kid can’t run a toaster? If they give the kid a test-drive when the shop is closed, the shop’s reputation isn’t at risk, and they don’t have to pay the kid a dime.
In programming, a program that doesn’t do something properly is said to have a “bug”. Generally, the users are the ones who notice bugs, because they use our software all day to do real work. They point it out, we fix the code and the program gets better. But doing TDD means that our tests are the first users of our code, before we release it to the world, so if something fails, our program’s reputation is safe. Users remember the bugs they report and every one erodes their confidence that all the other parts of your program are correct. The more of these bugs we can drive out with our tests, the fewer will get to the users. Nobody’s perfect, but TDD helps us get a lot closer to it.
It’s about flexibility
The hiring process at Rubytown is a story with a happy ending. After a few applicants who couldn’t find the mayo with both hands and a roadmap, Bob and Jane find one kid to handle the kitchen and one to run the counter. “Kid” is a relative term: Bella is 22 and Edward is 30, but they look like kids to Bob and Jane. After a month of smooth sailing at the sandwich shop, Bob and Jane take their first vacation in years (a long weekend at a bed & breakfast upstate) and return to find the shop hasn’t burned to the ground or been closed down by the health department.
The End? Not quite
So Bob and Jane can take some well-earned time off and the sandwich shop is clipping along without a care in the world. Are we done yet? Almost.
Remember our “red, green, refactor” TDD cycle? It’s time to consider that mysterious word “refactor”. But to do that, we need to go where almost no one has gone before: into Bob’s kitchen. Because it’s a nightmare in there…
- Test-Driven Development is the “hiring process” for trustworthy objects. If the object passes the test, it’s hired!
- The TDD cycle is “Red, Green, Refactor”: write a failing test, write the code to make it pass, then clean them both up. h2.* Your tests are your application’s first users, but these users don’t lose faith in your application if they spot a few bugs. By the time your application gets to human beings, it will be rock-solid.