Chapter 1. Well-Designed Apps Rock: Great Software Begins Here

image with no caption

So how do you really write great software? It’s never easy trying to figure out where to start. Does the application actually do what it’s supposed to? And what about things like duplicate code—that can’t be good, can it? It’s usually pretty hard to know what you should work on first, and still make sure you don’t screw everything else up in the process. No worries here, though. By the time you’re done with this chapter, you’ll know how to write great software, and be well on your way to improving the way you develop applications forever. Finally, you’ll understand why OOA&D is a four-letter word that your mother actually wants you to know about.

Rock and roll is forever!

There’s nothing better than the sound of a killer guitar in the hands of a great player, and Rick’s Guitars specializes in finding the perfect instrument for his discerning customers.

image with no caption
image with no caption

Just a few months ago, Rick decided to throw out his paper-based system for keeping track of guitars, and start using a computer-based system to store his inventory. He hired a popular programming firm, Down and Dirty Coding, and they’ve already built him an inventory management app. He’s even had the firm build him a new search tool to help him match up a customer to their dream instrument.

Rick’s shiny new application...

Here’s the application that the programming firm built for Rick... they’ve put together a system to completely replace all of Rick’s handwritten notes, and help him match his customers with the perfect guitar. Here’s the UML class diagram they gave Rick to show him what they did:

image with no caption

Here what the code for Guitar.java looks like

You’ve seen the class diagram for Rick’s application on the last page; now let’s look at what the actual code for Guitar.java and Inventory.java look like.

image with no caption

And Inventory.java...

image with no caption

But then Rick started losing customers...

It seems like no matter who the customer is and what they like, Rick’s new search program almost always comes up empty when it looks for good guitar matches. But Rick knows he has guitars that these customers would like... so what’s going on?

image with no caption
image with no caption

What’s the FIRST thing you’d change?

It’s obvious that Rick’s app has problems, but it’s not so obvious what we should work on first. And it looks like there’s no shortage of opinion:

image with no caption

What would you do first?

image with no caption

How do you write great software, every time?

image with no caption

Good question... and there are lots of different answers:

image with no caption

Great software is... more than just one thing

It’s going to take more than just a simple definition to figure out exactly what “great software” means. In fact, all of the different programmers in What’s the FIRST thing you’d change? talked about a part of what makes software great.

First, great software must satisfy the customer. The software must do what the customer wants it to do.

Win your customers over

Customers will think your software is great when it does what it’s supposed to do.

image with no caption

Building software that works right is great, but what about when it’s time to add to your code, or reuse it in another application? It’s not enough to just have software that works like the customer wants it to; your software better be able to stand the test of time.

Second, great software is well-designed, well-coded, and easy to maintain, reuse, and extend.

Make your code as smart as you are

You (and your co-workers) will think your software is great when it’s easy to maintain, reuse, and extend.

image with no caption
image with no caption

Great software in 3 easy steps

Note

It may not seem easy now, but we’ll show you how OOA&D and some basic principles can change your software forever.

image with no caption

Remember Rick? Remember his lost customers?

Let’s put our ideas about how to write great software to the test and see if they hold up in the real world. Rick’s got a search tool that isn’t working, and it’s your job to fix the application, and turn it into something great. Let’s look back at the app and see what’s going on:

image with no caption

So let’s apply our 3 steps

image with no caption
image with no caption

Frank: Sure, that would fix the problem Rick’s having now, but I think there’s probably a better way to make this work than just calling toLowerCase() on a bunch of strings all over the place.

Joe: Yeah, I was thinking the same thing. I mean, all that string comparison seems like a bad idea. Couldn’t we use constants or maybe some enumerated types for the builders and woods?

Jill: You guys are thinking way too far ahead. Step 1 was supposed to be fixing the app so it does what the customer wants it to do. I thought we weren’t supposed to worry about design yet.

Frank: Well, yeah, I get that we’re supposed to focus on the customer. But we can at least be smart about how we fix things, right? I mean, why create problems we’ll have to come back and fix later on if we can avoid them from the start?

Jill: Hmmm... I guess that does make sense. We don’t want our solution to this problem creating new design problems for us down the road. But we’re still not going to mess with the other parts of the application, right?

Frank: Right. We can just remove all those strings, and the string comparisons, to avoid this whole case-matching thing.

Joe: Exactly. If we go with enumerated types, we can ensure that only valid values for the builder, woods, and type of guitar are accepted. That’ll make sure that Rick’s clients actually get to look at guitars that match their preferences.

Jill: And we’ve actually done a little bit of design at the same time... very cool! Let’s put this into action.

Don’t create problems to solve problems.

Ditching String comparisons

The first improvement we can make to Rick’s guitar search tool is getting rid of all those annoying String comparisons. And even though you could use a function like toLowerCase() to avoid problems with uppercase and lowercase letters, let’s avoid String comparisons altogether:

image with no caption

Let’s take a look at the big picture:

image with no caption

So what have we really done here?

We’ve gotten a lot closer to completing step 1 in building great software. Rick’s problem with searches coming up empty when he’s got a matching guitar in his inventory is a thing of the past.

1. Make sure your software does what the customer wants it to do.

Even better, we’ve made Rick’s application less fragile along the way. It’s not going to break so easily now, because we’ve added both type safety and value safety with these enums. That means less problems for Rick, and less maintenance for us.

Note

Code that is not fragile is generally referred to as robust code.

image with no caption

Rick’s customers want choices!

Rick’s come up with a new requirement for his app: he wants his search tool to return all the guitars that match his client’s specs, not just the first one in his inventory.

image with no caption

Test drive

We’ve talked a lot about getting the right requirements from the customer, but now we need to make sure we’ve actually got those requirements handled by our code. Let’s test things out, and see if our app is working like Rick wants it to:

image with no caption

Back to our steps

Now that Rick’s all set with our software, we can begin to use some OO principles and make sure the app is flexible and well-designed.

image with no caption
image with no caption

Looking for problems

Let’s dig a little deeper into our search tool, and see if we can find any problems that some simple OO principles might help improve. Let’s start by taking a closer look at how the search() method in Inventory works:

image with no caption

Brain Power

Is anything wrong here? What problems might there be with Rick’s search tool?

Hint: Think about what each object is named, and compare that to its function. Anything seem odd?

Analyze the search() method

Let’s spend a little time analyzing exactly what goes on in the search() method of Inventory.java. Before we look at the code, though, let’s think about what this method should do.

  1. The client provides their guitar preferences.

    Note

    The client can specify only general properties of an instrument. So they never supply a serial number or a price.

    Each of Rick’s clients has some properties that they’re interested in finding in their ideal guitar: the woods used, or the type of guitar, or a particular builder or model. They provide these preferences to Rick, who feeds them into his inventory search tool.

  2. The search tool looks through Rick’s inventory.

    Once the search tool knows what Rick’s client wants, it starts to loop through each guitar in Rick’s inventory.

  3. Each guitar is compared to the client’s preferences.

    For each guitar in Rick’s inventory, the search tool sees if that guitar matches the client’s preferences. If there’s a match, the matching guitar is added to the list of choices for the client.

    Note

    All the general properties, like the top wood and guitar builder, are compared to the client’s preferences.

  4. Rick’s client is given a list of matching guitars.

    Finally, the list of matching guitars is returned to Rick and his client. The client can make a choice, and Rick can make a sale.

Use a textual description of the problem you’re trying to solve to make sure that your design lines up with the intended functionality of your application.

image with no caption

Frank: Hey, that’s right, Joe. I hadn’t thought about that before.

Jill: So what? Using a Guitar object makes it really easy to do comparisons in the search() method.

Joe: Not any more than some other object would. Look:

image with no caption

Joe: It really doesn’t matter what type of object we’re using there, as long as we can figure out what specific things Rick’s clients are looking for.

Frank: Yeah, I think we should have a new object that stores just the specs that clients want to send to the search() method. Then they’re not sending an entire Guitar object, which never seemed to make much sense to me.

Jill: But isn’t that going to create some duplicate code? If there’s an object for all the client’s specs, and then the Guitar has all its properties, we’ve got two getBuilder() methods, two getBackWood() methods... that’s not good.

Frank: So why don’t we just encapsulate those properties away from Guitar into a new object?

Joe: Whoa... I was with you until you said “encapsulate.” I thought that was when you made all your variables private, so nobody could use them incorrectly. What’s that got to do with a guitar’s properties?

Frank: Encapsulation is also about breaking your app into logical parts, and then keeping those parts separate. So just like you keep the data in your classes separate from the rest of your app’s behavior, we can keep the generic properties of a guitar separate from the actual Guitar object itself.

Jill: And then Guitar just has a variable pointing to a new object type that stores all its properties?

Frank: Exactly! So we’ve really encapsulated the guitar properties out of Guitar, and put them in their own separate object. Look, we could do something like this...

Encapsulation allows you to hide the inner workings of your application’s parts, but yet make it clear what each part does.

Note

New to encapsulation? Flip ahead to Appendix B, read that short introduction to Objectville, and then come back here and keep reading.

Now update your own code

With this class diagram, you should be able to add the GuitarSpec class to your application, and update the Guitar class as well. Go ahead and make any changes you need to Inventory.java so that the search tool compiles, as well.

image with no caption

Update the Inventory class

Now that we’ve encapsulated away the specifications of a guitar, we’ll need to make a few other changes to our code.

image with no caption

Getting ready for another test drive

You’ll need to update the FindGuitarTester class to test out all these new changes:

image with no caption

Get online

You can download the current version of Rick’s search tool at http://www.headfirstlabs.com. Just look for Head First OOA&D, and find “Rick’s Guitars (with encapsulation)”.

Getting back to Rick’s app...

Let’s make sure all our changes haven’t messed up the way Rick’s tool works. Compile your classes, and run the FindGuitarTester program again:

image with no caption

Brain Power

Can you think of three specific ways that well-designed software is easier to change than software that has duplicate code?

Design once, design twice

Once you’ve taken a first pass over your software and applied some basic OO principles, you’re ready to take another look, and this time make sure your software is not only flexible, but easily reused and extended.

image with no caption
image with no caption

Let’s make sure Inventory.java is (really) well-designed

We’ve already used encapsulation to improve the design of Rick’s search tool, but there are still some places in our code where we could get rid of potential problems. This will make our code easier to extend when Rick comes up with that next new feature he wants in his inventory search tool, and easier to reuse if we want to take just a few parts of the app and use them in other contexts.

Note

Now that you’ve made Rick a working search tool, you know he’s gonna call you back when he wants changes made to the tool.

image with no caption
image with no caption

How easy is it to make this change to Rick’s application?

Take a look at the class diagram for Rick’s application, and think about what you would need to do to add support for 12-string guitars. What properties and methods would you need to add, and to what classes? And what code would you need to change to allow Rick’s clients to search for 12-strings?

How many classes did you have to modify to make this change? Do you think Rick’s application is well designed right now?

Guitar

serialNumber: String

price: double

spec: GuitarSpec

getSerialNumber(): String

getPrice(): double

setPrice(float)

getSpec(): GuitarSpec

GuitarSpec

builder: Builder

model: String

type: Type

backWood: Wood

topWood: Wood

getBuilder(): Builder

getModel(): String

getType(): Type

getBackWood(): Wood

getTopWood(): Wood

Inventory

guitars: List

addGuitar(String, double, Builder, String, Type, Wood, Wood)

getGuitar(String): Guitar

search(GuitarSpec): List

image with no caption

Brain Power

What’s the advantage of using a numStrings property instead of just adding a boolean property to indicate if a guitar is a 12-string?

image with no caption

That’s right—we need to encapsulate the guitar specifications and isolate them from the rest of Rick’s guitar search tool.

Even though you’re adding a property only to the GuitarSpec class, there are two other classes that have to be modified: Guitar and Inventory. The constructor of Guitar has to take an additional property now, and the search() method of Inventory has to do an extra property comparison.

image with no caption

One last test drive (and an app ready for reuse)

Wow, we’ve done a lot of work since Rick showed us that first version of his guitar app. Let’s see if the latest version still works for Rick and his clients, and manages to satisfy our own goal of having a well-designed, easily maintainable application that we can reuse.

image with no caption

Congratulations! You’ve turned Rick’s broken inventory search tool into a well-designed piece of great software.

image with no caption

What we did

Let’s take a quick look back at how we got Rick’s search tool working so well:

image with no caption

Remember this poor guy?

image with no caption

He just wanted to write great software. So what’s the answer? How do you write great software consistently?

You just need a set of steps to follow that makes sure your software works and is well designed. It can be as simple as the three steps we used in working on Rick’s app; you just need something that works, and that you can use on all of your software projects.

Object-Oriented Analysis & Design helps you write great software, every time

Note

We call this OOA&D for short.

All this time that we’ve been talking about the three steps you can follow to write great software, we’ve really been talking about OOA&D.

OOA&D is really just an approach to writing software that focuses on making sure your code does what it’s supposed to, and that it’s well designed. That means your code is flexible, it’s easy to make changes to it, and it’s maintainable and reusable.

OOA&D is about writing great software, not doing a bunch of paperwork!

Customers are satisfied when their apps WORK. We can get requirements from the customer to make sure that we build them what they ask for. Use cases and diagrams are helpful ways to do that, but it’s all about figuring out what the customer wants the app to do.

Note

We’ll talk all about requirements in Chapter 2.

Customers are satisfied when their apps KEEP WORKING. Nobody is happy when an application that worked yesterday is crashing today. If we design our apps well, then they’re going to be robust, and not break every time a customer uses them in unusual ways. Class and sequence diagrams can help show us design problems, but the point is to write well-designed and robust code.

Note

You’ve learned a bit about fragile apps already.

Customers are satisfied when their apps can be UPGRADED. There’s nothing worse than a customer asking for a simple new feature, and being told it’s going to take two weeks and $25,000 to make it happen. Using OO techniques like encapsulation, composition, and delegation will make your applications maintainable and extensible.

Note

Want more on delegation, composition, and aggregation? We’ll talk about all of these in detail in Chapter 5, and then again in Chapter 8.

Programmers are satisfied when their apps can be REUSED. Ever built something for one customer, and realized you could use something almost exactly the same for another customer? If you do just a little bit of analysis on your apps, you can make sure they’re easily reused, by avoiding all sorts of nasty dependencies and associations that you don’t really need. Concepts like the Open-Closed Principle (OCP) and the Single Responsibility Principle (SRP) are big time in helping here.

Note

You’ll get to see these principles really strut their stuff in Chapter 8.

Programmers are satisfied when their apps are FLEXIBLE. Sometimes just a little refactoring can take a good app and turn it into a nice framework that can be used for all sorts of different things. This is where you can begin to move from being a head-down coder and start thinking like a real architect (oh yeah, those guys make a lot more money, too). Big-picture thinking is where it’s at.

Note

Chapter 6 and Chapter 7 are all about looking at the big picture, and really developing a good architecture for your applications.

Note

This is ALL OOA&D! It’s not about doing silly diagrams... it’s about writing killer applications that leave your customer happy, and you feeling like you’ve kicked major ass.

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.