Chapter 4. Analysis: Taking Your Software into the Real World

image with no caption

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:

image with no caption
image with no caption

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:

image with no caption

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:

image with no caption

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:

image with no caption

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:

image with no caption

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.

image with no caption
image with no caption

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!

image with no caption

Randy: simple is best, right?

Randy doesn’t waste any time with unnecessary code. He starts thinking about how he can compare barks:

image with no caption

Sam: object lover extraordinaire

Sam may not be as fast as Randy, but he loves his objects, so he figures that a new class devoted to dog barks is just the ticket:

image with no caption
image with no caption

Sam: updating the DogDoor class

Since Sam created a new Bark object, he takes a slightly different path than Randy did in updating his version of the DogDoor class:

image with no caption

Comparing barks

All that’s left to do is add a comparison of barks into BarkRecognizer’s recognize() method.

Randy: I’ll just compare two strings

image with no caption

Sam: I’ll delegate bark comparison

Sam is using a Bark object, and he lets that object take care of all the sound comparisons:

image with no caption
image with no caption

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:

  1. 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 that Bark instance to the recognize() method.

    image with no caption
  2. BarkRecognizer gets the owner’s dog’s bark from DogDoor

    The recognize() method calls getAllowedBark() on the dog door it’s attached to, and retrieves a Bark object representing the owner’s dog’s bark.

    image with no caption
    image with no caption
  3. BarkRecognizer delegates bark comparison to Bark

    The recognize() method asks the owner’s dog’s Bark object to see if it is equal to the Bark instance supplied by Doug’s hardware, using Bark.equals().

    image with no caption
  4. 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 the Bark object from Doug’s hardware... however that needs to happen.

    Note

    The details of how this comparison happens are hidden from all the other objects in the dog door application.

    image with no caption
image with no caption

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:

image with no caption

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:

image with no caption

Randy AND Sam: It works!

Both Randy and Sam ended up with a working dog door that let in only the owner’s dog.

image with no caption

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.

image with no caption

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...

image with no caption

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.

image with no caption
image with no caption

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:

image with no caption
image with no caption
image with no caption
image with no caption

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.

image with no caption

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:

image with no caption

There is no Bark class here!

The classes in use here in Step 3 are BarkRecognizer and DogDoor... not Bark!

image with no caption

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?

Note

HINT: Look closely at Randy’s Step 3. Does it describe a system that works exactly the same as the system on page 170?

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.

image with no caption

3. If the owner’s dog’s bark matches the bark heard by the bark recognizer, the dog door should open.

Note

And here’s Step 3 from the use case that Randy came up with for the same dog door.

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!

image with no caption
image with no caption

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.

image with no caption

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.

image with no caption
image with no caption

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:

image with no caption

From good analysis to good classes...

image with no caption

Maria’s Dog Door Class Diagram

image with no caption

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.

image with no caption
image with no caption

Exercise Solutions

image with no caption

Note

Notice that this diagram, although positioned very differently, has the same classes and associations as this diagram.

image with no caption

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?

image with no caption

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

image with no caption

Class diagrams don’t tell you how to code your methods

image with no caption

Class diagrams only give you a 10,000 foot view of your system

image with no caption

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:

image with no caption
image with no caption

Exercise Solutions

image with no caption
image with no caption

*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.

image with no caption
image with no caption

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.