Chapter 4. Analysis: Taking Your Software into the Real World
It’s time to graduate to real-world applications.
Your application has to do more than work on your own personal development machine, finely tuned and perfectly set up; your apps have to work when real people use them. This chapter is all about making sure that your software works in a real-world context. You’ll learn how textual analysis can take that use case you’ve been working on and turn it into classes and methods that you know are what your customers want. And when you’re done, you too can say: “I did it! My software is ready for the real world!”
One dog, two dog, three dog, four...
Things are going well at Doug’s Dog Doors. The version of the dog door you just developed in Chapter 3 is selling like crazy... but as more doors get installed, complaints have started coming in:
Your software has a context
So far, we’ve worked on writing software in a vacuum, and haven’t really thought much about the context that our software is running in. In other words, we’ve been thinking about our software like this:
But our software has to work in the real world, not just in a perfect world. That means we have to think about our software in a different context:
The key to making sure things work and that the real world doesn’t screw up your application is analysis: figuring out potential problems, and then solving those problems—before you release your app out into the real world.
Analysis helps you ensure your system works in a real-world context.
Identify the problem
The first step in good analysis is figuring out potential problems. We already know that there’s a problem when there are multiple dogs in the same neighborhood:
Plan a solution
It looks like there’s a change we need to make in what our system does. Do you know what it is? Below is a part of the diagram detailing how the dog door system works:
Brain Power
There’s an important addition that needs to be made to the dog door system, in addition to what’s shown in Sharpen your pencil answers. What is it?
Update your use case
Since we’ve changed our dog door diagram, we need to go back to the dog door use case, and update it with the new steps we’ve figured out. Then, over the next few pages, we’ll figure out what changes we need to make to our code.
We need a new use case to store the owner’s dog’s bark.
Our analysis has made us realize we need to make some changes to our use case—and those changes mean that we need to make some additions to our system, too.
If we’re comparing a bark from our bark recognizer to the owner’s dog’s bark, then we actually need to store the owner’s dog’s bark somewhere. And that means we need another use case.
A tale of two coders
There are lots of ways you could solve the design puzzle in Design Puzzle. In fact, Randy and Sam, two developers who Doug’s Dog Doors just hired, both have some pretty good ideas. But there’s more at stake here than just programmer pride—Doug’s offered the programmer with the best design a sparkling new Apple MacBook Pro!
Randy: simple is best, right?
Randy doesn’t waste any time with unnecessary code. He starts thinking about how he can compare barks:
Comparing barks
All that’s left to do is add a comparison of barks into BarkRecognizer
’s recognize()
method.
Delegation in Sam’s dog door: an in-depth look
Sam is doing something very similar in his Bark
and DogDoor
classes. Let’s see exactly what’s going on:
The BarkRecognizer gets a Bark to evaluate.
Doug’s hardware hears a dog barking, wraps the sound of the dog’s bark in a new
Bark
object, and delivers thatBark
instance to therecognize()
method.BarkRecognizer gets the owner’s dog’s bark from DogDoor
The
recognize()
method callsgetAllowedBark()
on the dog door it’s attached to, and retrieves aBark
object representing the owner’s dog’s bark.BarkRecognizer delegates bark comparison to Bark
The
recognize()
method asks the owner’s dog’sBark
object to see if it is equal to theBark
instance supplied by Doug’s hardware, usingBark.equals()
.Bark decides if it’s equal to the bark from Doug’s hardware
The
Bark
object representing the owner’s dog’s bark figures out if it is equal to theBark
object from Doug’s hardware... however that needs to happen.
The power of loosely coupled applications
In Chapter 1, we said that delegation helps our applications stay loosely coupled. That means that your objects are independent of each other; in other words, changes to one object don’t require you to make a bunch of changes to other objects.
By delegating comparison of barks to the Bark
object, we abstract the details about what makes two barks the same away from the BarkRecognizer
class. Look again at the code that calls equals()
on Bark
:
Now suppose that we started storing the sound of a dog barking as a WAV file in Bark
. We’d need to change the equals()
method in the Bark
class to do a more advanced comparison of sounds and account for the WAV files. But, since the recognize()
method delegates bark comparison, no code in BarkRecognizer
would have to change.
So with delegation and a loosely coupled application, you can change the implementation of one object, like Bark
, and you won’t have to change all the other objects in your application. Your objects are shielded from implementation changes in other objects.
Delegation shields your objects from implementation changes to other objects in your software.
Back to Sam, Randy, and the contest...
With Randy’s quick solution, and Sam’s more object-oriented one, let’s see how their applications are working out:
Maria won the MacBook Pro!
To both Randy and Sam’s surprise, Doug announces that Maria, a junior programmer he got to work for the company as a summer intern, has won the laptop.
Randy: Oh, this is ridiculous. My solution worked! That laptop is mine, not some intern’s!
Sam: Whatever, man. My solution worked, too, and I used objects. Didn’t you read Head First Java? An object-oriented solution is the way to go... the laptop’s mine!
Maria: Umm, guys, I don’t mean to interrupt, but I’m not sure either one of your dog doors really worked.
Sam: What do you mean? We tested it. Bruce barked, “Rowlf!” and the door opened up... but it stayed shut for the other dogs. Sounds like a working solution to me.
Maria: But did you do any analysis on your solution? Does your door truly work in the real world?
Randy: What are you talking about? Are you some sort of philosophy major? Is this like a “there is no spoon” sort of thing?
Maria: No, not at all. I’m just wondering... what if Bruce were to make a different sound? Like “Woof” or “Ruff”?
Sam: A different sound? Like if he’s hungry...
Randy: ...or excited...
Maria: ...or maybe... he really needs to get outside to use the bathroom. That’s, ummm, sort of how things work in the real world, isn’t it?
Randy and Sam: I guess we hadn’t thought about that...
So what did Maria do differently?
Maria started out a lot like Sam did. She created a Bark
object to represent the bark of a dog.
But Maria went even further: she decided that since a dog might have different barks, the dog door should store multiple Bark
objects. That way, no matter how the owner’s dog barks, it still gets outside:
Pay attention to the nouns in your use case
Maria’s figured out something really important: the nouns in a use case are usually the classes you need to write and focus on in your system.
Maria: That’s right. That’s how I figured out I needed a Bark
class... it showed up in the use case as a noun in Steps 2 and 6.3. So I created a Bark
class.
Randy: So that’s where I went wrong... if I had looked at the use case and circled the nouns, I would have known to create a Bark
class, too.
Maria: Probably. A lot of times, even if I think I know what classes I need, I double-check my ideas with the nouns in my use case to make sure I didn’t forget anything.
Sam: But you don’t need a class for some of those nouns, like “the owner” or “request,” or even “inside.”
Maria: That’s true... you still have to have some common sense, and understand the system that you’re building. Remember, you need classes only for the parts of the system you have to represent. We don’t need a class for “outside” or “inside” or “the owner” because our software doesn’t have to represent those things.
Randy: And you don’t need a class for “the button” because it’s part of the remote control—and we already do have a class for that.
Sam: This is all great, but I was just thinking... I came up with a Bark
class, too, and I didn’t need the use case to figure that out.
Maria: Yeah... but then you didn’t end up with a dog door that really worked, did you?
Sam: Well, no... but that’s just because you stored more than one Bark
object in the dog door. What does that have to do with the use case?
Looking at the nouns (and verbs) in your use case to figure out classes and methods is called textual analysis.
It’s all about the use case
Take a close look at Step 3 in the use case, and see exactly which classes are being used:
There is no Bark class here!
The classes in use here in Step 3 are BarkRecognizer and DogDoor... not Bark!
3. If the owner’s dog’s bark matches the bark heard by the bark recognizer, the dog door should open.
Note
Here’s Step 3 from the use case that Randy wrote for his dog door. In his Step 3, “bark” is a noun.
Step 3 in Randy’s use case looks a lot like Step 3 in our use case... but in his step, the focus is on the noun “bark”, and not “the owner’s dog.” So is Randy right? Does this whole textual analysis thing fall apart if you use a few different words in your use case?
What do you think?
One of these things is not like the other...
It looks like Randy’s Step 3 is actually just a little bit different than our original Step 3... so where did Randy go wrong?
3. If it’s the owner’s dog barking, the bark recognizer sends a request to the door to open.
Note
Here’s our Step 3, from the original use case we wrote back in Chapter 3.
Focus: owner’s dog
Our original Step 3 focuses on the owner’s dog... no matter how the dog sounds when it barks. So if the owner’s dog barks with a loud “Rowlf!” one day, but a quiet “ruff” the next, the system will let the dog in, either way. That’s because we’re focusing on the dog, not a particular bark.
3. If the owner’s dog’s bark matches the bark heard by the bark recognizer, the dog door should open.
Focus: owner’s dog’s bark
Randy’s use case focuses on the owner’s dog’s bark... but what if the dog has more than one sound it makes? And what if two dogs bark in a really similar way? This step looks similar to the original Step 3, but it’s really not the same at all!
Textual analysis tells you what to focus on, not just what classes you should create.
Even though we don’t have a Dog
class, textual analysis gave us an important clue about what our system really needs to do: get the owner’s dog in and out of the door, regardless of how he barks. In other words, our analysis helped us understand what to focus on... and it’s not a specific bark.
Once you’ve figured that out, it makes sense to think about what a dog really does. Does a dog always bark the same way? That’s when Maria figured out her real-world solution: she realized that if the owner’s dog could bark in more than one way, and the point was getting the owner’s dog outside, then the dog door needed to store all the ways that the dog could bark, not just one of them. But Maria would have never figured this out if she hadn’t really analyzed her use case.
Remember: pay attention to those nouns!
Even if the nouns in your use case don’t get turned into classes in your system, they’re always important to making your system work like it should.
The point is that the nouns are what you should focus on. If you focus on the dog in this step, you’ll figure out that you need to make sure the dog gets in and out of the dog door—whether he has one bark, or multiple barks.
Pay attention to the nouns in your use case, even when they aren’t classes in your system.
Think about how the classes you do have can support the behavior your use case describes.
The verbs in your use case are (usually) the methods of the objects in your system.
You’ve already seen how the nouns in your use case usually are a good starting point for figuring out what classes you might need in your system. If you look at the verbs in your use case, you can usually figure out what methods you’ll need for the objects that those classes represent:
Class diagrams dissected
There’s a lot more to a class diagram than boxes and text. Let’s see how some lines and arrows can add a lot more information to your class diagrams.
Note
Notice that this diagram, although positioned very differently, has the same classes and associations as this diagram.
Randy: I may have missed creating a Bark
class, but my solution wasn’t that bad, and I didn’t waste a bunch of my time drawing squares and arrows.
Maria: Haven’t you ever heard that a picture is worth a thousand words? Once I had my class diagram, I had a pretty good idea about how my whole system was going to work.
Randy: Well, yeah, I guess I can see that... but I had a good idea of how my system would work, too. It was just in my head, not drawn out on paper.
Sam: I think I’m starting to come around on this UML thing, Randy. I mean, once you’ve got the use case, it’s pretty natural to do some analysis, and turn the nouns into classes. It seems like you wouldn’t have to spend as much time worrying about what should be a class, and what shouldn’t.
Maria: Exactly! I hate writing a bunch of classes and then finding out I did something wrong. With use cases and class diagrams, if I make a mistake, I can just scribble things out and redraw my diagram.
Note
Remember how we said OOA&D helps you write great software, every time? This is one way OOA&D can help you avoid making mistakes in your code.
Randy: Well, I guess that’s true. Rewriting code takes a lot more time than rewriting a use case or redrawing a class diagram...
Maria: And you know, if you ever have to work with anyone else, you’re going to have to explain that system in your head to them somehow, right?
Sam: I think she’s right, Randy. I’ve seen your whiteboard when you’re trying to explain your ideas... it’s a mess!
Randy: OK, even I can’t argue with that. But I still think class diagrams don’t tell the whole story. Like, how is our code actually going to compare barks and figure out if the dog door should open up?
Class diagrams aren’t everything
Class diagrams are a great way to get an overview of your system, and show the parts of your system to co-workers and other programmers. But there’s still plenty of things that they don’t show.
Class diagrams provide limited type information
Class diagrams don’t tell you how to code your methods
Class diagrams only give you a 10,000 foot view of your system
So how does recognize() work now?
Maria’s figured out that her BarkRecognizer
class should be able to compare any bark it receives against multiple allowed barks, but her class diagram doesn’t tell us much about how to actually write the recognize()
method.
Instead, we have to look at Maria’s code. Here’s the recognize()
method of her BarkRecognizer
, and how she solved the barking problem:
*These are just a few of the things we thought of. Your answers may be totally different, if you thought of other things that the class diagram doesn’t really show.
Get Head First Object-Oriented Analysis and Design now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.