Head First Object-Oriented Analysis and Design

Brett McLaughlin

Gary Pollice

David West

Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo

To all the brilliant people who came up with various ways to gather requirements, analyze software, and design code...

...thanks for coming up with something good enough to produce great software, but hard enough that we needed this book to explain it all.

A Note Regarding Supplemental Files

Supplemental files and examples for this book can be found at http://examples.oreilly.com/9780596008673/. Please use a standard desktop web browser to access these files, as they may not be accessible from all ereader devices.

All code files or examples referenced in the book will be available online. For physical books that ship with an accompanying disc, whenever possible, we’ve posted all CD/DVD content. Note that while we provide as much of the media content as we are able via free download, we are sometimes limited by licensing restrictions. Please direct any questions or concerns to booktech@oreilly.com.

Praise for Head First OOA&D

“Head First Object-Oriented Analysis and Design is a refreshing look at the subject of OOA&D. What sets this book apart is its focus on learning. There are too many books on the market that spend a lot of time telling you why, but do not actually enable the practitioner to start work on a project. Those books are very interesting, but not very practical. I strongly believe that the future of software development practice will focus on the practitioner. The authors have made the content of OOA&D accessible and usable for the practitioner”

—Ivar Jacobson, Ivar Jacobson Consulting

“I just finished reading HF OOA&D, and I loved it! The book manages to get across the essentials of object-oriented analysis and design with UML and use cases, and even several lectures on good software design, all in a fast-paced, easy to understand way. The thing I liked most about this book was its focus on why we do OOA&D—to write great software! By defining what great software is and showing how each step in the OOA&D process leads you towards that goal, it can teach even the most jaded Java programmer why OOA&D matters. This is a great ‘first book’ on design for anyone who is new to Java, or even for those who have been Java programmers for a while but have been scared off by the massive tomes on OO Analysis and Design.”

—Kyle Brown, Distinguished Engineer, IBM

“Finally a book on OOA&D that recognizes that the UML is just a notation and that what matters when developing software is taking the time to think the issues through.”

—Pete McBreen, Author, Software Craftsmanship

“The book does a good job of capturing that entertaining, visually oriented, ‘Head First’ writing style. But hidden behind the funny pictures and crazy fonts is a serious, intelligent, extremely well-crafted presentation of OO Analysis and Design. This book has a strong opinion of how to design programs, and communicates it effectively. I love the way it uses running examples to lead the reader through the various stages of the design process. As I read the book, I felt like I was looking over the shoulder of an expert designer who was explaining to me what issues were important at each step, and why.”

—Edward Sciore, Associate Professor, Computer Science Department Boston College

“This is a well-designed book that delivers what it promises to its readers: how to analyze, design, and write serious object-oriented software. Its contents flow effortlessly from using use cases for capturing requirements to analysis, design, implementation, testing, and iteration. Every step in the development of object-oriented software is presented in light of sound software engineering principles. The examples are clear and illustrative. This is a solid and refreshing book on object-oriented software development.”

—Dung Zung Nguyen, Lecturer Rice University

Praise for other Head First books by the authors

“When arriving home after a 10-hour day at the office programming, who has the energy to plow through yet another new facet of emerging technology? If a developer is going to invest free time in self-driven career development, should it not be at least remotely enjoyable? Judging from the content of O’Reilly’s new release Head Rush Ajax, the answer is yes...Head Rush Ajax is a most enjoyable launchpad into the world of Ajax web applications, well worth the investment in time and money.”

—Barry Hawkins, Slashdot.org

“By starting with simple concepts and examples, the book gently takes the reader from humble beginnings to (by the end of the book) where the reader should be comfortable creating Ajax-based websites... Probably the best web designer centric book on Ajax.”

—Stefan Mischook, Killersites.com

“Using the irreverent style common of the Head First/Head Rush series of books, this book starts at the beginning and introduces you to all you need to know to be able to write the JavaScript that will both send requests to the server and update the page with the results when they are returned... One of the best things about this book (apart form the excellent explanations of how the code works) is that it also looks at security issues... If you learn Ajax from this book you are unlikely to forget much of what you learn.”

—Stephen Chapman, JavaScript.About.com

“Head Rush Ajax is the book if you want to cut through all the hype and learn how to make your web apps sparkled...your users will love you for it!”

—Kristin Stromberg, Aguirre International

“If you know some HTML, a dollop of CSS, a little JavaScript, and a bit of PHP, but you’re mystified about what all the Ajax hype is about, this book is for you... You’ll have a blast learning Ajax with Head Rush Ajax. By the time you’ve reached the end of the book, all those web technologies that didn’t quite fit together in your head will all snap into place and you’ll have The Ajax Power! You’ll know the secrets behind some of the most popular web applications on the Internet. You’ll impress your friends and co-workers with you knowledge of how those interactive maps and web forms really work.”

—Elisabeth Freeman, The Walt Disney Internet Group Co-Author, Head First Design Patterns and Head First HTML with CSS & XHTML

“If you thought Ajax was rocket science, this book is for you. Head Rush Ajax puts dynamic, compelling experiences within reach for every web developer.”

—Jesse James Garrett, Adaptive Path

“This stuff is brain candy; I can’t get enough of it.”

—Pauline McNamara, Center for New Technologies and Education Fribourg University, Switzerland

Praise for other Head First Books

“I *heart* Head First HTML with CSS & XHTML – it teaches you everything you need to learn in a ‘fun coated’ format!”

—Sally Applin, UI Designer and Fine Artist, http://sally.com.

“My wife stole the book. She’s never done any web design, so she needed a book like Head First HTML with CSS & XHTML to take her from beginning to end. She now has a list of web sites she wants to build – for our son’s class, our family, ... If I’m lucky, I’ll get the book back when she’s done.”

—David Kaminsky, Master Inventor, IBM

“Freeman’s Head First HTML with CSS & XHTML is a most entertaining book for learning how to build a great web page. It not only covers everything you need to know about HTML, CSS, and XHTML, it also excels in explaining everything in layman’s terms with a lot of great examples. I found the book truly enjoyable to read, and I learned something new!”

—Newton Lee, Editor-in-Chief, ACM Computers in Entertainment http://www.acmcie.org

From the awesome Head First Java folks, this book uses every conceivable trick to help you understand and remember. Not just loads of pictures: pictures of humans, which tend to interest other humans. Surprises everywhere. Stories, because humans love narrative. (Stories about things like pizza and chocolate. Need we say more?) Plus, it’s darned funny.

—Bill Camarda, READ ONLY

“This book’s admirable clarity, humor and substantial doses of clever make it the sort of book that helps even non-programmers think well about problem-solving.”

—Cory Doctorow, co-editor of Boing Boing Author, “Down and Out in the Magic Kingdom” and “Someone Comes to Town, Someone Leaves Town”

“I feel like a thousand pounds of books have just been lifted off of my head.”

—Ward Cunningham, inventor of the Wiki and founder of the Hillside Group

“I literally love this book. In fact, I kissed this book in front of my wife.”

—Satish Kumar

Other related books from O’Reilly

Practical Development Environments

Process Improvement Essentials

Prefactoring

Ajax Design Patterns

Learning UML

Applied Software Project Management

The Art of Project Management

UML 2.0 in a Nutshell

Unit Test Frameworks

Other books in O’Reilly’s Head First Series

Head First Design Patterns

Head First Java

Head First Servlets and JSP

Head First EJB

Head First HTML with CSS & XHTML

Head Rush Ajax

Head First OOA&D

Head First PMP (2007)

Head First Algebra (2007)

Head First Software Development (2007)

Brett McLaughlin is a guitar player who is still struggling with the realization that you can’t pay the bills if you’re into acoustic fingerstyle blues and jazz. He’s just recently discovered, to his delight, that writing books that help people become better programmers does pay the bills. He’s very happy about this, as are his wife Leigh, and his kids, Dean and Robbie.

Before Brett wandered into Head First land, he developed enterprise Java applications for Nextel Communications and Allegiance Telecom. When that became fairly mundane, Brett took on application servers, working on the internals of the Lutris Enhydra servlet engine and EJB container. Along the way, Brett got hooked on open source software, and helped found several cool programming tools, like Jakarta Turbine and JDOM. Write to him at brett@oreilly.com.

Gary Pollice is a self-labeled curmudgeon (that’s a crusty, ill-tempered, usually old man) who spent over 35 years in industry trying to figure out what he wanted to be when he grew up. Even though he hasn’t grown up yet, he did make the move in 2003 to the hallowed halls of academia where he has been corrupting the minds of the next generation of software developers with radical ideas like, “develop software for your customer, learn how to work as part of a team, design and code quality and elegance and correctness counts, and it’s okay to be a nerd as long as you are a great one.”

Gary is a Professor of Practice (meaning he had a real job before becoming a professor) at Worcester Polytechnic Institute. He lives in central Massachusetts with his wife, Vikki, and their two dogs, Aloysius and Ignatius. You can visit his WPI home page at http://web.cs.wpi.edu/~gpollice/. Feel free to drop him a note and complain or cheer about the book.

Dave West would like to describe himself as sheik geek. Unfortunately no one else would describe him in that way. They would say he is a professional Englishman who likes to talk about software development best practices with the passion and energy of an evangelical preacher. Recently Dave has moved to Ivar Jacobson Consulting, where he runs the Americas and can combine his desire to talk about software development and spread the word on rugby and football, and argue that cricket is more exciting than baseball.

Before running the Americas for Ivar Jacobson Consulting, Dave worked for a number of years at Rational Software (now a part of IBM). Dave held many positions at Rational and then IBM, including Product Manager for RUP where he introduced the idea of process plug-ins and agility to RUP. Dave can be contacted at dwest@ivarjacobson.com.

How to use this Book: Intro

In this section, we answer the burning question: “So why DID they put that in an OOA&D book?”

Who is this book for?

If you can answer “yes” to all of these:

Do you know Java? (You don’t need to be a guru.)

Note

You’ll probably be okay if you know C# instead.

Do you want to learn, understand, remember, and apply object-oriented analysis and design to real world projects, and write better software in the process?

Do you prefer stimulating dinner party conversation to dry, dull, academic lectures?

this book is for you.

Who should probably back away from this book?

If you can answer “yes” to any one of these:

Are you completely new to Java? (You don’t need to be advanced, and even if you don’t know Java, but you know C#, you’ll probably understand almost all of the code examples. You also might be okay with just a C++ background.)

Are you a kick-butt OO designer/developer looking for a reference book?

Are you afraid to try something different? Would you rather have a root canal than mix stripes with plaid? Do you believe that a technical book can’t be serious if programming concepts are anthropomorphized?

this book is not for you.

[note from marketing: this book is for anyone with a credit card.]

We know what you’re thinking

“How can this be a serious programming book?”

“What’s with all the graphics?”

“Can I actually learn it this way?”

And we know what your brain is thinking

Your brain craves novelty. It’s always searching, scanning, waiting for something unusual. It was built that way, and it helps you stay alive.

So what does your brain do with all the routine, ordinary, normal things you encounter? Everything it can to stop them from interfering with the brain’s real job—recording things that matter. It doesn’t bother saving the boring things; they never make it past the “this is obviously not important” filter.

How does your brain know what’s important? Suppose you’re out for a day hike and a tiger jumps in front of you, what happens inside your head and body?

Neurons fire. Emotions crank up. Chemicals surge.

And that’s how your brain knows...

This must be important! Don’t forget it!

But imagine you’re at home, or in a library. It’s a safe, warm, tiger-free zone. You’re studying. Getting ready for an exam. Or trying to learn some tough technical topic your boss thinks will take a week, ten days at the most.

Just one problem. Your brain’s trying to do you a big favor. It’s trying to make sure that this obviously non-important content doesn’t clutter up scarce resources. Resources that are better spent storing the really big things. Like tigers. Like the danger of fire. Like how you should never again snowboard in shorts.

And there’s no simple way to tell your brain, “Hey brain, thank you very much, but no matter how dull this book is, and how little I’m registering on the emotional Richter scale right now, I really do want you to keep this stuff around.”

We think of a “Head First” reader as a learner

So what does it take to learn something? First, you have to get it, then make sure you don’t forget it. It’s not about pushing facts into your head. Based on the latest research in cognitive science, neurobiology, and educational psychology, learning takes a lot more than text on a page. We know what turns your brain on.

Some of the Head First learning principles:

Make it visual. Images are far more memorable than words alone, and make learning much more effective (up to 89% improvement in recall and transfer studies). It also makes things more understandable. Put the words within or near the graphics they relate to, rather than on the bottom or on another page, and learners will be up to twice as likely to solve problems related to the content.

Use a conversational and personalized style. In recent studies, students performed up to 40% better on post-learning tests if the content spoke directly to the reader, using a first-person, conversational style rather than taking a formal tone. Tell stories instead of lecturing. Use casual language. Don’t take yourself too seriously. Which would you pay more attention to: a stimulating dinner party companion, or a lecture?

Get the learner to think more deeply. In other words, unless you actively flex your neurons, nothing much happens in your head. A reader has to be motivated, engaged, curious, and inspired to solve problems, draw conclusions, and generate new knowledge. And for that, you need challenges, exercises, and thought-provoking questions, and activities that involve both sides of the brain, and multiple senses.

Get—and keep—the reader’s attention. We’ve all had the “I really want to learn this but I can’t stay awake past page one” experience. Your brain pays attention to things that are out of the ordinary, interesting, strange, eye-catching, unexpected. Learning a new, tough, technical topic doesn’t have to be boring. Your brain will learn much more quickly if it’s not.

Touch their emotions. We now know that your ability to remember something is largely dependent on its emotional content. You remember what you care about. You remember when you feel something. No, we’re not talking heart-wrenching stories about a boy and his dog. We’re talking emotions like surprise, curiosity, fun, “what the...?”, and the feeling of “I Rule!” that comes when you solve a puzzle, learn something everybody else thinks is hard, or realize you know something that “I’m more technical than thou” Bob from engineering doesn’t.

Metacognition: thinking about thinking

If you really want to learn, and you want to learn more quickly and more deeply, pay attention to how you pay attention. Think about how you think. Learn how you learn.

Most of us did not take courses on metacognition or learning theory when we were growing up. We were expected to learn, but rarely taught to learn.

But we assume that if you’re holding this book, you really want to learn object-oriented analysis and design. And you probably don’t want to spend a lot of time. And since you’re going to develop software, you need to remember what you read. And for that, you’ve got to understand it. To get the most from this book, or any book or learning experience, take responsibility for your brain. Your brain on this content.

The trick is to get your brain to see the new material you’re learning as Really Important. Crucial to your well-being. As important as a tiger. Otherwise, you’re in for a constant battle, with your brain doing its best to keep the new content from sticking.

So just how DO you get your brain to think object-oriented analysis and design is a hungry tiger?

There’s the slow, tedious way, or the faster, more effective way. The slow way is about sheer repetition. You obviously know that you are able to learn and remember even the dullest of topics if you keep pounding the same thing into your brain. With enough repetition, your brain says, “This doesn’t feel important to him, but he keeps looking at the same thing over and over and over, so I suppose it must be.”

The faster way is to do anything that increases brain activity, especially different types of brain activity. The things on the previous page are a big part of the solution, and they’re all things that have been proven to help your brain work in your favor. For example, studies show that putting words within the pictures they describe (as opposed to somewhere else in the page, like a caption or in the body text) causes your brain to try to makes sense of how the words and picture relate, and this causes more neurons to fire. More neurons firing = more chances for your brain to get that this is something worth paying attention to, and possibly recording.

A conversational style helps because people tend to pay more attention when they perceive that they’re in a conversation, since they’re expected to follow along and hold up their end. The amazing thing is, your brain doesn’t necessarily care that the “conversation” is between you and a book! On the other hand, if the writing style is formal and dry, your brain perceives it the same way you experience being lectured to while sitting in a roomful of passive attendees. No need to stay awake.

But pictures and conversational style are just the beginning.

Here’s what WE did

We used pictures, because your brain is tuned for visuals, not text. As far as your brain’s concerned, a picture really is worth 1,024 words. And when text and pictures work together, we embedded the text in the pictures because your brain works more effectively when the text is within the thing the text refers to, as opposed to in a caption or buried in the text somewhere.

We used redundancy, saying the same thing in different ways and with different media types, and multiple senses, to increase the chance that the content gets coded into more than one area of your brain.

We used concepts and pictures in unexpected ways because your brain is tuned for novelty, and we used pictures and ideas with at least some emotional content, because your brain is tuned to pay attention to the biochemistry of emotions. That which causes you to feel something is more likely to be remembered, even if that feeling is nothing more than a little humor, surprise, or interest.

We used a personalized, conversational style, because your brain is tuned to pay more attention when it believes you’re in a conversation than if it thinks you’re passively listening to a presentation. Your brain does this even when you’re reading.

We included more than 80 activities, because your brain is tuned to learn and remember more when you do things than when you read about things. And we made the exercises challenging-yet-do-able, because that’s what most people prefer.

We used multiple learning styles, because you might prefer step-by-step procedures, while someone else wants to understand the big picture first, and someone else just wants to see a code example. But regardless of your own learning preference, everyone benefits from seeing the same content represented in multiple ways.

We include content for both sides of your brain, because the more of your brain you engage, the more likely you are to learn and remember, and the longer you can stay focused. Since working one side of the brain often means giving the other side a chance to rest, you can be more productive at learning for a longer period of time.

And we included stories and exercises that present more than one point of view, because your brain is tuned to learn more deeply when it’s forced to make evaluations and judgements.

We included challenges, with exercises, and by asking questions that don’t always have a straight answer, because your brain is tuned to learn and remember when it has to work at something. Think about it—you can’t get your body in shape just by watching people at the gym. But we did our best to make sure that when you’re working hard, it’s on the right things. That you’re not spending one extra dendrite processing a hard-to-understand example, or parsing difficult, jargon-laden, or overly terse text.

We used people. In stories, examples, pictures, etc., because, well, because you’re a person. And your brain pays more attention to people than it does to things.

We used an 80/20 approach. We assume that if you’re going for a PhD in software design, this won’t be your only book. So we don’t talk about everything. Just the stuff you’ll actually need.

Here’s what YOU can do to bend your brain into submission

So, we did our part. The rest is up to you. These tips are a starting point; listen to your brain and figure out what works for you and what doesn’t. Try new things.

Cut this out and stick it on your refrigerator.

Slow down. The more you understand, the less you have to memorize.

Don’t just read. Stop and think. When the book asks you a question, don’t just skip to the answer. Imagine that someone really is asking the question. The more deeply you force your brain to think, the better chance you have of learning and remembering.

Do the exercises. Write your own notes.

We put them in, but if we did them for you, that would be like having someone else do your workouts for you. And don’t just look at the exercises. Use a pencil. There’s plenty of evidence that physical activity while learning can increase the learning.

Read the “There are No Dumb Questions”

That means all of them. They’re not optional side-bars—they’re part of the core content! Don’t skip them.

Make this the last thing you read before bed. Or at least the last challenging thing.

Part of the learning (especially the transfer to long-term memory) happens after you put the book down. Your brain needs time on its own, to do more processing. If you put in something new during that processing time, some of what you just learned will be lost.

Drink water. Lots of it.

Your brain works best in a nice bath of fluid. Dehydration (which can happen before you ever feel thirsty) decreases cognitive function.

Talk about it. Out loud.

Speaking activates a different part of the brain. If you’re trying to understand something, or increase your chance of remembering it later, say it out loud. Better still, try to explain it out loud to someone else. You’ll learn more quickly, and you might uncover ideas you hadn’t known were there when you were reading about it.

Listen to your brain.

Pay attention to whether your brain is getting overloaded. If you find yourself starting to skim the surface or forget what you just read, it’s time for a break. Once you go past a certain point, you won’t learn faster by trying to shove more in, and you might even hurt the process.

Feel something!

Your brain needs to know that this matters. Get involved with the stories. Make up your own captions for the photos. Groaning over a bad joke is still better than feeling nothing at all.

Design something!

Apply what you read to something new you’re designing, or rework an older project. Just do something to get some experience beyond the exercises and activities in this book. All you need is a problem to solve... a problem that might benefit from one or more techniques that we talk about.

Read Me

This is a learning experience, not a reference book. We deliberately stripped out everything that might get in the way of learning whatever it is we’re working on at that point in the book. And the first time through, you need to begin at the beginning, because the book makes assumptions about what you’ve already seen and learned.

We assume you are familiar with Java.

It would take an entire book to teach you Java (in fact, that’s exactly what it took: Head First Java). We chose to focus this book on analysis and design, so the chapters are written with the assumption that you know the basics of Java. When intermediate or advanced concepts come up, they’re taught as if they might be totally new to you, though.

If you’re completely new to Java, or coming to this book from a C# or C++ background, we strongly recommend you turn to the back of the book and read Appendix B before going on. That appendix has some intro material that will help you start this book off on the right foot.

We only use Java 5 when we have to.

Java 5.0 introduces a lot of new features to the Java language, ranging from generics to parameterized types to enumerated types to the foreach looping construct. Since many professional programmers are just moving to Java 5, we didn’t want you getting hung up on new syntax while you’re trying to learn about OOA&D. In most cases, we stuck with pre-Java 5 syntax. The only exception is in Chapter 1, when we needed an enumerated type—and we explained enums in that section in some detail.

If you’re new to Java 5, you should have no trouble with any of the code examples. If you’re already comfortable with Java 5, then you will get a few compiler warnings about unchecked and unsafe operations, due to our lack of typed collections, but you should be able to update the code for Java 5 on your own quite easily.

The activities are NOT optional.

The exercises and activities are not add-ons; they’re part of the core content of the book. Some of them are to help with memory, some are for understanding, and some will help you apply what you’ve learned. Don’t skip the exercises. The crossword puzzles are the only things you don’t have to do, but they’re good for giving your brain a chance to think about the words and terms you’ve been learning in a different context.

The redundancy is intentional and important.

One distinct difference in a Head First book is that we want you to really get it. And we want you to finish the book remembering what you’ve learned. Most reference books don’t have retention and recall as a goal, but this book is about learning, so you’ll see some of the same concepts come up more than once.

The examples are as lean as possible.

Our readers tell us that it’s frustrating to wade through 200 lines of an example looking for the two lines they need to understand. Most examples in this book are shown within the smallest possible context, so that the part you’re trying to learn is clear and simple. Don’t expect all of the examples to be robust, or even complete—they are written specifically for learning, and aren’t always fully-functional.

In some cases, we haven’t included all of the import statements needed, but we assume that if you’re a Java programmer, you know that ArrayList is in java.util, for example. If the imports are not part of the normal core J2SE API, we mention it. We’ve also placed all the source code on the web so you can download it. You’ll find it at http://www.headfirstlabs.com/books/hfoo/.

Also, for the sake of focusing on the learning side of the code, we did not put our classes into packages (in other words, they’re all in the Java default package). We don’t recommend this in the real world, and when you download the code examples from this book, you’ll find that all classes are in packages.

The ‘Brain Power’ exercises don’t have answers.

For some of them, there is no right answer, and for others, part of the learning experience of the Brain Power activities is for you to decide if and when your answers are right. In some of the Brain Power exercises you will find hints to point you in the right direction.

The Technical Team

Technical Reviewers:

Huge thanks to our amazing trio of technical reviewers. These guys caught mistakes that we missed, let us know when we were moving too fast (or too slow), and even let us know when our jokes sucked. Several times, they turned chapters around in a matter of hours... we’re not sure if that means they’re really helpful, or need to get away from software development a little more. Hannibal in particular made our week when he let us know that the big OOA&D arrow in Chapter 10 was “Hot!” Thanks guys, this book wouldn’t be nearly as solid without your hard work.

Kathy Sierra and Bert Bates:

We continue to be amazed at the insight and expertise that Bert Bates has about cliffs, and that Kathy Sierra has about dog doors. If that doesn’t make much sense, don’t be surprised—everything you know about almost everything gets turned on its head when you meet this pair, and yet we all came out much for the better because of their help.

Bert and Kathy did a ton of review at the eleventh hour, and we’re thankful they did. Their help and guidance continues to be the heart of Head First.

Acknowledgements

My co-authors:

Because I’m doing the typing, I get to step out of “we” mode for a moment and say thanks to my co-authors, Dave West and Gary Pollice. Neither of these guys knew what they were signing up for when they came on board, but I’ve never been so impressed by a couple of guys willing to explain, defend, and even change their opinions and knowledge about software design, requirements and analysis, and lift shafts. They were simply incredible, writing up until the very last day, and even got me to relax and laugh until I cried on several occasions.

Our editor:

This book wouldn’t be in your hands if not for Mary O’Brien. I think it’s fair to say she fought more battles and paved the way for us to work without interruption more times than any of us really are aware of. Most importantly, she made this the single most enjoyable project we’ve worked on in our careers. Frankly, she kicked our asses a number of times, and it made all the difference. She really doesn’t realize how much of an effect she has on the people she works with, because we don’t tell her enough how much we respect her and value her opinions. So there, now you know, Mary. If we could put your name on the cover, we would (oh, wait... we did!).

The O’Reilly team:

These books are a team effort, never more so than on this one. Mike Hendrickson and Laurie Petrycki oversaw this project at various times, and took heated phone calls more than once. Sanders Kleinfeld cut his Head First teeth on this project, and managed to come out alive; better yet, he did a great job, improving the book, and we all are excited that this is just the first of many Head First books he’ll be working on. Mike Loukides found Bert and Kathy way back when, and Tim O’Reilly had the foresight to turn their crazy idea into a series. As always, Kyle Hart is instrumental in getting these books “out there”, and Edie Freedman’s beautiful cover design continues to amaze us all.

A particularly special thanks goes out to Louise Barr, the Head First Design Editor. Lou pulled several 12- and 14-hour days to help us with graphics in this book, and put together the amazing Objectville Subway Map in Chapter 10. Lou, your work has improved the learning quality of this book, and we can’t thank you enough for your contributions.

Special thanks

Near the completion of this book, Laura Baldwin, the CFO of O’Reilly, encountered some personal tragedy. It’s hard to know what to say in these situations, especially because Laura has really become the backbone of O’Reilly in many ways. Laura, we are thinking and praying for you and your family, and we wish you all the very, very best in the days to come. We know you’d want nothing more than to see everyone at O’Reilly working harder than ever while you’re away.

This book is certainly a testament to the people at O’Reilly continuing to deliver, and in many of our conversations, your name came up as someone we wanted to support, and not let down in any way. Your effect on this company is extraordinary, and O’Reilly and the Head First series will all be much better for the day you can return to us in full swing.

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

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.

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:

New to Objectville?

If you’re new to object oriented programming, haven’t heard of UML before, or aren’t sure about the diagram above, it’s OK! We’ve prepared a special Welcome to Objectville care package for you to get you started. Flip to the back of the book, and read Appendix B—we promise you’ll be glad you did. Then come back here, and this will all make a lot more sense.

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.

And Inventory.java...

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?

Sharpen your pencil

How would you redesign Rick’s app?

Look over the last three pages, showing the code for Rick’s app, and the results of running a search. What problems do you see? What would you change? Write down the FIRST thing you’d do to improve Rick’s app in the blanks below.

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

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:

What would you do first?

How do you write great software, every time?

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

Sharpen your pencil

What do you think “great software” means?

You’ve seen what several different types of programmers think great software is... so who is right? Or do you have your own definition of what makes an application great? It’s your turn to write down what you think makes for great software:

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.

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.

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.

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:

So let’s apply our 3 steps

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:

There are no Dumb Questions

Q:

Q: I’ve never seen an enum before. What is that, exactly?

A:

A: Enums are enumerated types. They’re available in C, C++, Java version 5.0 and up, and will even be a part of Perl 6.

Enumerated types let you define a type name, like Wood, and then a set of values that are allowed for that type (like COCOBOLO, SITKA, and MAHOGANY). Then, you refer to a specific value like this: Wood.COCOBOLO.

Q:

Q: And why are enumerated types so helpful here?

A:

A: The cool thing about enums is that methods or classes that use them are protected from any values not defined in the enum. So you can’t misspell or mistype an enum without getting a compiler error. It’s a great way to get not only type safety, but value safety; you can avoid getting bad data for anything that has a standard range or set of legal values.

Q:

Q: I’m using an older version of Java. Am I stuck?

A:

A: No, not at all. Visit the Head First Labs web site at http://www.headfirstlabs.com, where we’ve posted a version of Rick’s Guitars that doesn’t use enums, and will work with older JDKs.

Let’s take a look at the big picture:

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.

Sharpen your pencil

Apply Step 1 to your own project.

It’s time to see how you can satisfy your own customers. In the blank below, write a short description of the current project you’re working on (you can also use a project you finished recently):

_____________________________________________________________________

_____________________________________________________________________

Now, write down the first thing you did when you started working on this project. Did it have anything to do with making sure your code did what the customer wanted it to?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

If you started out focusing on something other than the customer, think about how you might have approached things differently if you knew about the 3 steps to building great software. What would have been different? Do you think your application would be any better or worse than it is right now?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

There are no Dumb Questions

Q:

Q: So it’s OK to do a little design when I’m working on Step 1, right?

A:

A: Yeah, as long as your focus is still on the customer’s needs. You want the basic features of your application in place before you start making big design changes. But while you’re working on functionality, you can certainly use good OO principles and techniques to make sure your application is well designed from the start.

Q:

Q: That diagram over in Note is a class diagram right? Or is it class diagrams, since it’s more than one class?

A:

A: It is a class diagram, and a single diagram can have multiple classes in it. In fact, class diagrams can show a lot more detail than you’ve seen so far, and we’ll be adding to them in the next several chapters.

Q:

Q: So we’re ready to move on to Step 2, and start applying OO principles, right?

A:

A: Not quite... there’s one more thing Rick would like us to help him with before we’re ready to start analyzing our code for places we might be able to improve it. Remember, our first job is to please the customer, and then we really focus on improving our OO design.

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.

Code Magnets

Let’s continue with Step 1, and make sure we’ve got the app working right. Below is the code for the search() method in Rick’s inventory tool, but it’s up to you to fill in the missing pieces. Use the code magnets at the bottom of the page to return all the matching guitars from Rick’s inventory.

Code Magnets

Let’s keep on with Step 1, and make sure we’ve got the app working right. Below is the code for the search() method in Rick’s inventory tool, but it’s up to you to fill in the missing pieces. Use the code magnets at the bottom of the page to return all the matching guitars from Rick’s inventory.

There are no Dumb Questions

Q:

Q: So I’m not done with the first step until the application works like my customer wants it to?

A:

A: Exactly. You want to make sure that the application works like it should before you dive into applying design patterns or trying to do any real restructuring of how the application is put together.

Q:

Q: And why is it so important to finish Step 1 before going on to Step 2?

A:

A: You’re going to make lots of changes to your software when you’re getting it to work right. Trying to do too much design before you’ve at least got the basic functionality down can end up being a waste, because a lot of the design will change as you’re adding new pieces of functionality to your classes and methods.

Q:

Q: You seem sort of hung up on this “Step 1” and “Step 2” business. What if I don’t code my apps that way?

A:

A: There’s nothing that says you have to follow these steps exactly, but they do provide an easy path to follow to make sure your software does what it’s supposed to, and is well-designed and easy to reuse. If you’ve got something similar that accomplishes the same goals, that’s great!

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:

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.

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:

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.

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.

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.

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.

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.

The Mystery of the Mismatched Object Type

In the better-designed areas of Objectville, objects are very particular about their jobs. Each object is interested in doing its job, and only its job, to the best of its ability. There’s nothing a well-designed object hates more than being used to do something that really isn’t its true purpose.

Unfortunately, it’s come to our attention that this is exactly what is happening in Rick’s inventory search tool: somewhere, an object is being used to do something that it really shouldn’t be doing. It’s your job to solve this mystery and figure out how we can get Rick’s application back in line.

To help you figure out what’s gone amiss, here are some helpful tips to start you on your search for the mismatched object type:

Objects should do what their names indicate. If an object is named Jet, it should probably takeOff() and land(), but it shouldn’t takeTicket()—that’s the job of another object, and doesn’t belong in Jet.

Each object should represent a single concept. You don’t want objects serving double or triple duty. Avoid a Duck object that represents a real quacking duck, a yellow plastic duck, and someone dropping their head down to avoid getting hit by a baseball.

Unused properties are a dead giveaway. If you’ve got an object that is being used with no-value or null properties often, you’ve probably got an object doing more than one job. If you rarely have values for a certain property, why is that property part of the object? Would there be a better object to use with just a subset of those properties?

What do you think the mismatched object type is? Write your answer in the blank below:

___________________________________

What do you think you should do to fix the problem? What changes would you make?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

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:

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.

Sharpen your pencil

Create the GuitarSpec object.

Below, you’ll see the class diagram for Guitar, and the new GuitarSpec object that Frank, Jill, and Joe have been discussing. It’s your job to add all the properties and methods that you think you’ll need to GuitarSpec. Then, cross out anything you don’t need anymore in the Guitar class. Finally, we’ve left you some space in the Guitar class diagram in case you think you need to add any new properties or methods. Good luck!

* If you get stuck, think about the things that are common between the Guitar object and what a client would supply to the search() method.

Sharpen your pencil answers

Create the GuitarSpec object.

Below you’ll see the class diagram for Guitar, and the new GuitarSpec object that Frank, Jill, and Joe have been discussing. It’s your job to add all the properties and methods that you think you’ll need to GuitarSpec. See if you made the same changes that we did.

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.

There are no Dumb Questions

Q:

Q: I understand why we need an object for the client to send specs to search()... but why are we using that object to hold properties for Guitar, too?

A:

A: Suppose you just used GuitarSpec to hold client specs for sending to the search() method, and you kept the Guitar class just the same as it was. If Rick started carrying 12-string guitars, and wanted a numStrings property, you’d have to add that property—and code for a getNumStrings() method—to both the GuitarSpec and Guitar classes. Can you see how this would lead to duplicate code?

Instead, we can put all that (potentially) duplicate code into the GuitarSpec class, and then have Guitar objects reference an instance of it to avoid any duplication.

Anytime you see duplicate code, look for a place to encapsulate!

Q:

Q: I still am confused about how this is a form of encapsulation. Can you explain that again?

A:

A: The idea behind encapsulation is to protect information in one part of your application from the other parts of your application. In its simplest form, you can protect the data in your class from the rest of your app by making that data private. But sometimes the information might be an entire set of properties—like the details about a guitar—or even behavior—like how a particular type of duck flies.

When you break that behavior out from a class, you can change the behavior without the class having to change as well. So if you changed how properties were stored, you wouldn’t have to change your Guitar class at all, because the properties are encapsulated away from Guitar.

That’s the power of encapsulation: by breaking up the different parts of your app, you can change one part without having to change all the other parts. In general, you should encapsulate the parts of your app that might vary away from the parts that will stay the same.

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.

Getting ready for another test drive

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

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

Why DO I Matter?

You’ve learned a lot about writing great software, and there’s still more to go! Take a deep breath and think about some of the terms and principles we’ve covered. Connect the words on the left to the purposes of those techniques and principles on the right.

Flexibility

Without me, you’ll never actually make the customer happy. No matter how well-designed your application is, I’m the thing that puts a smile on the customer’s face.

Encapsulation

I’m all about reuse and making sure you’re not trying to solve a problem that someone else has already figured out.

Functionality

You use me to keep the parts of your code that stay the same separate from the parts that change; then it’s really easy to make changes to your code without breaking everything.

Design Pattern

Use me so that your software can change and grow without constant rework. I keep your application from being fragile.

Answers in Why DO I Matter?.

There are no Dumb Questions

Q:

Q: Encapsulation isn’t the only OO principle I can use at this stage, is it?

A:

A: Nope. Other good OO principles that you might want to think about at this stage are inheritance and polymorphism. Both of these relate to duplicate code and encapsulation though, so starting out by looking for places where you could use encapsulation to better your design is always a good idea.

We’ll talk about a lot more OO programming principles throughout this book (and even see a few sing in Chapter 8), so don’t worry if you are still getting a handle on things at this point. You’ll learn a lot more about encapsulation, class design, and more before we’re done.

Q:

Q: But I don’t really see how this encapsulation makes my code more flexible. Can you explain that again?

A:

A: Once you’ve gotten your software to work like it’s supposed to, flexibility becomes a big deal. What if the customer wants to add new properties or features to the app? If you’ve got tons of duplicate code or confusing inheritance structures in your app, making changes is going to be a pain.

By introducing principles like encapsulation and good class design into your code, it’s easier to make these changes, and your application becomes a lot more flexible.

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:

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.

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.

Sharpen your pencil

What would you change about this code?

There’s a big problem with the code shown above, and it’s up to you to figure it out. In the blanks below, write down what you think the problem is, and how you would fix it.

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

See what we said in Sharpen your pencil answers.

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

Sharpen your pencil

Annotate Rick’s class diagram.

Rick wants to be able to sell 12-string guitars. Get out your pencil, and add notes to the class diagram showing the following things:

Where you’d add a new property, called numStrings, to store the number of strings a guitar has.

Where you’d add a new method, called getNumStrings(), to return the number of strings a guitar has.

What other code you think you’d need to change so that Rick’s clients can specify that they want to try out 12-string guitars.

Finally, in the blanks below, write down any problems with this design that you found when adding support for 12-string guitars.

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Note

Here’s a hint: you should get an answer here related to what you wrote down in the blanks back in Let’s make sure Inventory.java is (really) well-designed.

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

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?

Sharpen your pencil answers

Annotate Rick’s class diagram.

Rick wants to be able to sell 12-string guitars. Get out your pencil, and add notes to the class diagram showing the following things:

Where you’d add a new property, called numStrings, to store the number of strings a guitar has.

Where you’d add a new method, called getNumStrings(), to return the number of strings a guitar has.

What other code you think you’d need to change so that Rick’s clients can specify that they want to try out 12-string guitars.

Finally, in the blanks below, write down any problems with this design that you found when adding support for 12-string guitars.

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.

Design Puzzle

It’s not enough to know what’s wrong with Rick’s app, or even to figure out that we need some more encapsulation. Now you need to actually figure out how to fix his app so it’s easier to reuse and extend.

The problem:

Adding a new property to GuitarSpec.java results in changes to the code in Guitar.java and Inventory.java. The application should be restructured so that adding properties to GuitarSpec doesn’t affect the code in the rest of the application.

Your task:

Add a numStrings property and getNumStrings() method to GuitarSpec.java.

Modify Guitar.java so that the properties of GuitarSpec are encapsulated away from the constructor of the class.

Change the search() method in Inventory.java to delegate comparing the two GuitarSpec objects to the GuitarSpec class, instead of handling the comparison directly.

Note

Not sure what delegation is? Check this out...

Update FindGuitarTester.java to work with your new classes, and make sure everything still works.

Note

All you should have to do here is update your code that creates a sample inventory to use the new Guitar constructor.

Compare your answers with ours in Design Puzzle Solution, and then get ready for another test drive to see if we’ve finally got this application finished.

There are no Dumb Questions

Q:

Q: You said I should “delegate” comparisons to GuitarSpec. What’s delegation?

A:

A: Delegation is when an object needs to perform a certain task, and instead of doing that task directly, it asks another object to handle the task (or sometimes just a part of the task).

So in the design puzzle, you want the search() method in Inventory to ask GuitarSpec to tell it if two specs are equal, instead of comparing the two GuitarSpec objects directly within the search() method itself. search() delegates the comparison to GuitarSpec.

Q:

Q: What’s the point of that?

A:

A: Delegation makes your code more reusable. It also lets each object worry about its own functionality, rather than spreading the code that handles a single object’s behavior all throughout your application

One of the most common examples of delegation in Java is the equals() method. Instead of a method trying to figure out if two objects are equal, it calls equals() on one of the objects and passes in the second object. Then it just gets back a true or false response from the equals() method.

Q:

Q: And what does delegation have to do with code being more reusable?

A:

A: Delegation lets each object worry about equality (or some other task) on its own. This means your objects are more independent of each other, or more loosely coupled. Loosely coupled objects can be taken from one app and easily reused in another, because they’re not tightly tied to other objects’ code.

Q:

Q: And what does loosely coupled mean again?

A:

A: Loosely coupled is when the objects in your application each have a specific job to do, and they do only that job. So the functionality of your app is spread out over lots of well-defined objects, which each do a single task really well.

Q:

Q: And why is that good?

A:

A: Loosely coupled applications are usually more flexible, and easy to change. Since each object is pretty independent of the other objects, you can make a change to one object’s behavior without having to change all the rest of your objects. So adding new features or functionality becomes a lot easier.

The Scholar’s Corner

delegation. The act of one object forwarding an operation to another object, to be performed on behalf of the first object.

Design Puzzle Solution

It’s not enough to know what’s wrong with Rick’s app, or even to figure out that you need some more encapsulation. Now we need to actually figure out how to fix his app so we can test it out.

The problem:

Adding a new property to GuitarSpec.java results in changes to the code in Guitar.java and Inventory.java. The application should be refactored so that adding properties to GuitarSpec doesn’t affect the code in the rest of the application.

Your task:

Add a numStrings property and getNumStrings() method to GuitarSpec.java.

Modify Guitar.java so that the properties of GuitarSpec are encapsulated away from the constructor of the class.

Change the search() method in Inventory.java to delegate comparing the two GuitarSpec objects to the GuitarSpec class, instead of handling the comparison directly.

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.

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

What we did

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

Remember this poor guy?

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.

Bullet Points

It takes very little for something to go wrong with an application that is fragile.

You can use OO principles like encapsulation and delegation to build applications that are flexible.

Encapsulation is breaking your application into logical parts that have a clear boundary that allows an object to hide its data and methods from other objects.

Delegation is giving another object the responsibility of handling a particular task.

Always begin a project by figuring out what the customer wants.

Once you’ve got the basic functionality of an app in place, work on refining the design so it’s flexible.

With a functional and flexible design, you can employ design patterns to improve your design further, and make your app easier to reuse.

Find the parts of your application that change often, and try and separate them from the parts of your application that don’t change.

Building an application that works well but is poorly designed satisfies the customer but will leave you with pain, suffering, and lots of late nights fixing problems.

Object oriented analysis and design (OOA&D) provides a way to produce well-designed applications that satisfy both the customer and the programmer.

OOA&D Cross

Let’s put what you’ve learned to use, and stetch out your left brain a bit. All of the words to answer the puzzle below are somewhere in this chapter. Good luck!

Across

Down

4. These help you avoid solving problems sameone else has already solved.

7. Customers focus on this port of your applications.

8. Objects in loosely coupled applications are more ___________ then tightly coupled ones.

9. Flexible applications are usually easy to ________.

10. This is one type of code you don’t want to write.

12. Your applications should be easy to __________.

13. You usually need some sort of process to write great Software __________.

14. Encapsulate what ________.

15. These types of applications satisfy programmers.

1. Once your application works correctly, focus on this.

2. Grouping your application into logical parts.

3. The goal of OOA&D is to help you write this type of Software.

5. Use this to let objects focus on more specific tasks.

6. A good way to avoid duplicate code

7. An application that things can go wrong in easily.

11. This is a four letter word your mom will be proud you know.

Why DO I Matter?

Exercise Solutions

You’ve learned a lot about writing great software, and there’s still more to go! Take a deep breath and think about some of the terms and principles we’ve covered. Connect the words on the left to the purpose of those techniques and principles on the right.

Sharpen your pencil answers

What would you change about this code?

There’s a big problem with the code shown above, and it’s up to you to figure it out. In the blanks below, write down what you think the problem is, and how you would fix it.

Every time a new property is added to GuitarSpec.java, or the methods in GuitarSpec change, the search() method in Inventory.java will have to change, too. We should let GuitarSpec handle comparisons, and encapsulate these properties away from Inventory.______________

Chapter 2. Gathering Requirements: Give Them What They Want

Everybody loves a satisfied customer. You already know that the first step in writing great software is making sure it does what the customer wants it to. But how do you figure out what a customer really wants? And how do you make sure that the customer even knows what they really want? That’s where good requirements come in, and in this chapter, you’re going to learn how to satisfy your customer by making sure what you deliver is actually what they asked for. By the time you’re done, all of your projects will be “satisfaction guaranteed,” and you’ll be well on your way to writing great software, every time.

You’ve got a new programming gig

You’ve just been hired as the lead programmer at a new start-up, Doug’s Dog Doors. Doug’s got a pretty high-tech door under development, and he’s decided you’re the programmer that can write all the software to make his killer hardware work.

Todd and Gina: your first customer

Todd and Gina want more than a “normal” doggie door. Todd has everything from his plasma TV to his surround sound stereo to his garage door operating off of a remote control, and he wants a dog door that responds to the press of a button. Not satisfied with a little plastic flap letting their dog in and out, they’ve given Doug’s Dog Doors a call... and now Doug wants you to build them the dog door of their dreams.

Let’s start with the dog door

The first thing we need is a class to represent the dog door. Let’s call this class DogDoor, and add just a few simple methods:

Code Magnets

Let’s write another class, Remote, to allow a remote control to operate the dog door. Todd and Gina can use the remote to open the dog door without having to get out of bed.

Be careful... you may not need all the magnets.

Note

Yes, we know this is a really easy one. We’re just getting you warmed up, don’t worry.

public class Remote {
  private ___________ door;
  public Remote(_____________ _______) {
    this.door = door;
  }

  public void pressButton() {
    System.out.println("Pressing the remote control button...");
    if (_____._______()) {
      door._________();
    } else {
      door._________();
    }
  }
}

Once you’re done, compare your answer with ours in Code Magnets Solutions.

Test drive

Let’s see if everything works. Go ahead and take your new dog door for a test drive.

Create a class to test the door (DogDoorSimulator.java).

Compile all your Java source code into classes.

Run the code!

But when Gina tried it...

Sharpen your pencil

How do you think the rodents are getting into Gina’s kitchen? In the blanks below, write down what you think is wrong with the current version of the dog door.

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Note

Don’t go to the next page until you’ve written down an answer for this exercise.

But the door doesn’t work the way Todd and Gina want it to!

Todd and Gina didn’t expect to have to close the dog door, so they pressed the button on the remote only once: to let Fido out.

Even worse, in this case, the way they used the door created new problems. Rats and rabbits started coming into their house through the open door, and you’re taking the blame.

Let’s tackle Todd and Gina’s dog door again, but this time, we’ll do things a little bit differently. Here’s our plan:

So what exactly is a requirement, anyway?

The Scholar’s Corner

requirement. A requirement is a singular need detailing what a particular product or service should be or do. It is most commonly used in a formal sense in systems engineering or software engineering.

Listen to the customer

When it comes to requirements, the best thing you can do is let the customer talk. And pay attention to what the system needs to do; you can figure out how the system will do those things later.

Gina: And we want the door to automatically close after a few seconds. I don’t want to have to wake back up in the middle of the night to close the door.

You: Do you want a single button on the remote, or both an “Open” and “Close” button?

Todd: Well, if the door always closes automatically, we really don’t need separate “Open” and “Close” buttons, do we? Let’s just stick with a single button on the remote control.

You: Sure. So the button opens the door if it’s closed, and it can also close the door if it’s open, just in case the door gets stuck.

Note

Don’t worry about your code at this stage-just make sure you know what the system should do.

Todd: Perfect. Gina, anything else you can think of?

Gina: No, I think that’s it. That’s the dog door of our dreams.

Creating a requirements list

Now that we know what Todd and Gina want, let’s write down our new set of requirements. We don’t need anything too fancy...

A special bonus prize

In addition to having a list of things you need to do to complete Todd and Gina’s dog door, now you can show your boss exactly what you’re working on, and what work you think is left to finish the project.

You need to understand how the dog door will be used.

You’ve figured out one of the hardest parts about getting a customer’s requirements—sometimes even the customer doesn’t know what they really want! So you’ve got to ask the customer questions to figure out what they want before you can determine exactly what the system should do. Then, you can begin to think beyond what your customers asked for and anticipate their needs, even before they realize they have a problem.

Note

In Todd and Gina’s case, the system is the dog door and the remote control.

Sharpen your pencil

What sorts of things do you think Todd and Gina might not have thought about when it comes to their new dog door? Make a list of any concerns you might have in making sure Todd and Gina are happy with the new door you’re building them.

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

What does the dog door really need to do?

You know what Todd and Gina want the dog door to do, but it’s your job to make sure that the door actually works. In the process, you may even come across some things that Todd and Gina want, but didn’t think about on their own.

Let’s write down exactly what happens when Fido needs to go outside:

There are no Dumb Questions

Q:

Q: So a requirement is just one of the things that a customer wants the application you build for them to do?

A:

A: Actually, a requirement is a lot more than just what the customer wants—although that’s a good place to start. Begin by finding out what your customer wants and expects, and what they think the system you’re building for them should do. But there’s still a lot more to think about...

Remember, most people expect things to work even if problems occur. So you’ve got to anticipate what might go wrong, and add requirements to take care of those problems as well. A good set of requirements goes beyond just what your customers tell you, and makes sure that the system works, even in unusual or unexpected circumstances.

Q:

Q: And the system for Todd and Gina is just the dog door, right?

A:

A: The system is everything needed to meet a customer’s goals. In the case of the dog door, the system includes the door, but it also includes the remote control. Without the remote, the dog door wouldn’t be complete.

And even though they aren’t part of the system, Todd and Gina and Fido are all things you have to at least think about when designing the system. So there’s a lot more to worry about than just the actual dog door.

Q:

Q: I don’t see why I have to figure out how Todd and Gina are going to use the dog door, and what can go wrong. Isn’t that their problem, not mine?

A:

A: Do you remember the first step we talked about in writing great software? You’ve got to make sure your app works like the customer wants it to—even if that’s not how you would use the application. That means you’ve got to really understand what the system has to do, and how your customers are going to use it.

In fact, the only way to ensure you get Todd and Gina a working, successful dog door is to know the system even better than they do, and to understand exactly what it needs to do. You can then anticipate problems, and hopefully solve them before Todd and Gina ever know something could have gone wrong.

Q:

Q: So I should just come up with all sorts of bad things that might happen when Todd and Gina use their door?

A:

A: Exactly! In fact, let’s do that now...

The best way to get good requirements is to understand what a system is supposed to do.

Plan for things going wrong

Below is a diagram of how Todd and Gina’s dog door should work; all the numbers match up with the steps in our list in What does the dog door really need to do?. But things aren’t always going to go according to plan, so we’ve written down some things that might go wrong along the way.

Alternate paths handle system problems

Now that you’ve figured out some of the things that can go wrong, you need to update your list of things that needs to happen to make the dog door work. Let’s write down what should happen if the door closes before Fido gets back inside.

Yes! You’ve been writing use cases all along

When you wrote down the steps in getting Fido outside to use the bathroom, you were actually writing a use case.

A use case is what people call the steps that a system takes to make something happen. In Todd and Gina’s case, the “something” that needs to happen is getting Fido outside to do his business, and then back inside.

(Re) introducing use cases

You’ve been writing a use case for almost 10 pages now, but let’s take a closer look at exactly what that list of steps—the use case for Todd and Gina’s dog door—is really all about:

The Scholar’s Corner

use case. A use case is a technique for capturing the potential requirements of a new system or software change. Each use case provides one or more scenarios that convey how the system should interact with the end user or another system to achieve a specific goal.

One use case, three parts

There are three basic parts to a good use case, and you need all three if your use case is going to get the job done.

Use Case Magnets

Below is Todd and Gina’s use case, and a magnet for each of the three parts of a good use case (one part, Start and Stop, actually has two magnets). Your job is to identify where each magnet goes and attach it to the right part of the use case.

Todd and Gina’s Dog Door, version 2.0 What the Door Does

Fido barks to be let out.

Todd or Gina hears Fido barking.

Todd or Gina presses the button on the remote control.

The dog door opens.

Fido goes outside.

Fido does his business.

6.1

The door shuts automatically.

6.2

Fido barks to be let back inside.

6.3

Todd or Gina hears Fido barking (again).

6.4

Todd or Gina presses the button on the remote control.

6.5

The dog door opens (again).

Fido goes back inside.

The door shuts automatically.

Use Case Magnet Solutions

Below is Todd and Gina’s use case, along with several use case magnets. Your job was to identify where each magnet goes, and attach it to the right part of the use case.

There are no Dumb Questions

Q:

Q: So a use case is just a list of the steps that a system has to do to work correctly?

A:

A: In most cases, yes. But, remember, one of the key points about a use case is that it is focused on accomplishing one particular goal. If your system does more than one thing—like let Fido outside and track how many times he’s been out in an entire day—then you’ll need more than one use case.

Q:

Q: Then my system will have a use case for every goal it accomplishes, right?

A:

A: Exactly! If your system just does one single thing, you’ll probably only need one use case. If it does ten or fifteen things, then you’re going to have a lot of use cases.

Q:

Q: And a use case is what the system does to accomplish a goal?

A:

A: Now you’ve got it. If you write down what the system needs to do to perform a task, you’ve probably got a use case.

Q:

Q: But the use case isn’t very specific. Why didn’t we talk about the Remote class or the DogDoor class?

A:

A: Use cases are meant to help you understand what a system should do—and often to explain the system to others (like the customer or your boss). If your use case focuses on specific code-level details, it’s not going to be useful to anyone but a programmer. As a general rule, your use cases should use simple, everyday language. If you’re using lots of programming terms, or technical jargon, your use case is probably getting too detailed to be that useful.

Q:

Q: Is a use case the same as a use case diagram?

A:

A: No, use cases are usually a list of steps (although you can write them differently, something we talk about in the Appendix). Use case diagrams are a way to show use cases visually, but we’ve already been working on our own diagram of how the system works (check out page 69 for a refresher). Don’t worry, though, we’ll still look at use case diagrams in Chapter 6.

Q:

Q: Then how do I turn my use case into actual code?

A:

A: That’s another step in the process of writing your application. In fact, we’re going to look at how to take our use case for Todd and Gina and update our code in just a few more pages.

But the purpose of the use case isn’t to detail how you’ll write your code. You’ll probably still have to do some thinking about how you want to actually put the steps of your use case into action.

Q:

Q: If the use case doesn’t help me write my code, then what’s the point? Why spend all this time on use cases?

A:

A: Use cases do help you write your code—they just aren’t specific about programming details. For instance, if you didn’t write a use case for Todd and Gina, you never would have figured out that Fido might get stuck outside, or realize that the dog door needed to close automatically. Those all came from writing a use case.

Remember, you’ll never write great software if you can’t deliver an app that does what the customer wants it to do. Use cases are a tool to help you figure that out—and then you’re ready to write code to actually implement the system your use case describes.

Checking your requirements against your use cases

So far, you’ve got an initial set of requirements and a good solid use case. But now you need to go back to your requirements and make sure that they’ll cover everything your system has to do. And that’s where the use case comes in:

Is anything missing?

Now you need to look over the use case and see if everything the system needs to do is covered by the requirements.

Sharpen your pencil

Do your requirements handle everything?

Below on the left is the list of things that the dog door does, pulled straight from our use case in Checking your requirements against your use cases. Your job is to identify the requirement that handles each step of the use case and write that requirement’s number down in the blank next to that step of the use case. If a step in the use case doesn’t require you to do anything, just write N/A down, for “not applicable”.

Note

Here are the three requirements we have... you can use any of these for each step in the use case.

Todd and Gina’s Dog Door, version 2.0 What the Door Does

1.

Fido barks to be let out.

_____

2.

Todd or Gina hears Fido barking.

_____

3.

Todd or Gina presses the button on the remote control.

_____

4.

The dog door opens.

_____

5.

Fido goes outside.

_____

6.

Fido does his business.

_____

6.1

The door shuts automatically.

_____

6.2

Fido barks to be let back inside.

_____

6.3

Todd or Gina hears Fido barking (again).

_____

6.4

Todd or Gina presses the button on the remote control.

_____

6.5

The dog door opens (again).

_____

7.

Fido goes back inside.

_____

8.

The door shuts automatically.

_____

Note

Write 1, 2, 3, or N/A in each of these blanks.

Todd and Gina’s Dog Door, version 2.0 Requirements List

The dog door opening must be at least 12” tall.

A button on the remote control opens the dog door if the door is closed, and closes the dog door if the door is open.

Once the dog door has opened, it should close automatically if the door isn’t already closed.

Did you find any steps in the use case that you don’t think you have a requirement to handle? If you think you need any additional requirements, write what you think you need to add to the requirements list in the blanks below:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Sharpen your pencil answers

Do your requirements handle everything?

Below on the left is the list of things that the dog door does, pulled straight from our use case in Checking your requirements against your use cases. Your job was to identify the requirement that handles each step of the use case, and write that requirement’s number down in the blank next to that step of the use case. You should have written down N/A for a step that didn’t require our system to do anything.

Did you find any steps in the use case that you don’t think you have a requirement to handle? If you think you need any additional requirements, write what you think you need to add to the requirements list down in the blanks below:

No, our requirements cover everything the system needs to do. We’re ready to actually write code to handle these requirements now, right?______________________

So now can we write some code?

With use case and requirements in hand, you’re ready to write code that you know will make Todd and Gina satisfied customers. Let’s check out our requirements and see exactly what we’re going to have to write code for:

Automatically closing the door

The only requirement left to code is taking care of automatically closing the door after it’s been opened. Let’s go back to our Remote class and handle that now:

There are no Dumb Questions

Q:

Q: What’s all this Timer stuff? Can’t I just use a Java thread to close the door?

A:

A: Sure, there’s nothing wrong with using a Thread to close the dog door. In fact, that’s all the Timer class does: kick off a background Thread. But the Timer class makes running a task in the future easy, so it seemed like a good choice for the Remote class.

Q:

Q: Why did you make the timer variable final?

A:

A: Because we need to call its cancel() method in the TimerTask anonymous class. If you need to access variables in your anonymous class from the enclosing class (that’s Remote in this case), those variables must be final. And, really, just because it makes things work.

Q:

Q: Why are you calling cancel()? Won’t the timer quit automatically after running the TimerTask?

A:

A: It will, but it turns out that most JVMs take forever before they garbage collect the Timer. That ends up hanging the program, and your code will run for hours before it actually quits gracefully. That’s no good, but calling cancel() manually takes care of the problem.

Q:

Q: You lost me on that timer code. What’s going on there again?

A:

A: That’s OK... you don’t need to get too hung up on Java here. The point is that our use case helped us write good requirements, and our requirements made it easy to figure out how to write a working dog door. That’s a lot more important than how—or even in what language—you write the dog door code.

Q:

Q: So the new simulator tests out the main path we figured out, right?

A:

A: That’s right. Flip back to Checking your requirements against your use cases and review what the dog door does... that’s what the new DogDoorSimulator tests out. We want to make sure that Todd and Gina’s new door works just like they want it to.

Q:

Q: Why aren’t we testing out that alternate path we found?

A:

A: That’s a very good question. Let’s test this version of the door, and then we’ll talk more about that...

We need a new simulator!

Our old simulator isn’t that useful anymore... it assumes Todd and Gina are closing the door manually, and not letting the timer do its work. Let’s update our simulator to make it work with the updated Remote class:t

Test drive, version 2.0

It’s time to see if all our hard work is going to pay off. Let’s test out the new and improved dog door.

Compile all your Java source code into classes.

Run the code!

It works! Let’s go show Todd and Gina...

Good catch... we need to test alternate paths as well as the main path.

Wouldn’t it be great if things worked just like you expected them to every time? Of course, in the real world, that almost never happens. Before we can show the new door off to Todd and Gina, let’s take a little extra time to make sure the door works when Fido doesn’t come right back inside after doing his business.

Your system must work in the real world...

...so plan and test for when things go wrong.

Brain Power

How would you change the DogDoorSimulator class to test for Fido staying outside longer?

Super Brain Power

Can you come up with at least one more alternate path for Todd and Gina’s dog door? Write out the use case and update the requirements list for your new alternate path, too.

Reviewing the alternate path

Let’s make sure we understand exactly what happens on the alternate path, and then we can update DogDoorSimulator to test the new path out. Here’s the original main path diagram from Plan for things going wrong, along with the alternate path we figured out and added to our use case:

Code Magnets

It’s time to update the simulator, but this time it’s your job to actually write some code. Below is what we have so far for DogDoorSimulator.

Your job is to match the code magnets at the bottom of the page to where they belong in the simulator. If you get stuck, check the diagram on the last page to see what’s going on at each step of the way. Oh, and there’s a twist... all the magnets for periods, semicolons, and parentheses fell off the fridge, so you’ll have to add those wherever they’re needed, too.

Test drive, version 2.1

Make the changes to your copy of DogDoorSimulator.java, and then recompile your test class. Now you’re ready to test out the alternate path of your use case:

Code Magnets Solution

Here’s what we did to complete the simulator. Make sure you got the same answers that we did.

Delivering the new dog door

Good use cases, requirements, main paths, alternate paths, and a working simulator; we’re definitely on the road to great software. Let’s take the new dog door to Todd and Gina.

Working app, happy customers

Not only did we turn Todd and Gina into satisfied customers, we made sure their door worked when Fido did something they didn’t expect—like stay outside playing.

Use Cases Exposed

This week’s interview: Getting to Know the Happy Path

HeadFirst: Hello there, Main Path.

Happy Path: Actually, I prefer to be called “Happy Path.” I know a lot of books refer to me as “Main Path,” but I find lots more people remember who I am when I go by “Happy Path.”

HeadFirst: Oh, I apologize. Well, in any case, it’s great to have you with us today, Happy Path, and you’re right on time, too.

Happy Path: Thanks... I’m always on time, that’s really important to me.

HeadFirst: Is that right? You’re never late?

Happy Path: Nope, not a single time. I never miss an appointment, either. I never make a mistake, nothing ever goes unexpectedly... you can really count on me to come through just like you want, every time.

HeadFirst: That’s quite a statement to make.

Happy Path: Well, it’s just part of who I am.

HeadFirst: And that’s how you got your name? You make people happy by always being on time and never making a mistake?

Happy Path: No, but that’s close. They call me “Happy Path” because when you’re hanging out with me, everything goes just as you’d hope. Nothing ever goes wrong when the “Happy Path” is at the wheel.

HeadFirst: I have to admit, I’m still a bit amazed that nothing ever goes wrong around you. Are you sure you’re living in the real world?

Happy Path: Well, don’t get me wrong... things definitely go wrong in the real world. But when that happens, I just hand things off to my buddy, Alternate Path.

HeadFirst: Oh, I think I see now... so things can go wrong, but that’s Alternate Path’s job to handle.

Happy Path: Yeah, pretty much. But I don’t worry too much about that. My job is to take care of things when the sun is shining and things are going just like people expect.

HeadFirst: Wow, that must be really satisfying.

Happy Path: Well, most of the time it is. But things do tend to go wrong a lot. It seems like hardly anyone sticks with me from start to finish. Alternate Path usually gets involved at some point, but we get along well, so it’s no big deal.

HeadFirst: Do you ever feel like Alternate Path is butting in? I could imagine some tension there...

Happy Path: No, not at all. I mean, we’re all after the same thing: getting the customer to their goal, and making sure they’re satisfied. And once we’re defined well, actually coding an application is a lot simpler.

HeadFirst: Well, you heard it here folks. Next week, we’ll try and catch up with Alternate Path, and get her side of the story. Until then, try and stay on the Happy Path, but remember to plan for problems!

What’s My Purpose

Below on the left are some of the new terms you’ve learned in this chapter. On the right are descriptions of what those terms mean and how they’re used. Your job is to match the term on the left with that term’s purpose on the right.

External ________

Kicks off the list of steps described in a use case. Without this, a use case never gets going.

____ Case

Something a system needs to do to be a success.

Start ___________

Lets you know when a use case is finished. Without this, use cases can go on forever.

Requirement

Helps you gather good requirements. Tells a story about what a system does.

________ Value

What a system does when everything is going right. This is usually what customers describe when they’re talking about the system.

_______ Condition

This is always the first step in the use case.

_______ Path

Without this, a use case isn’t worth anything to anyone. Use cases without this always fail.

Note

Uh oh... parts of some of the terms on the left have gone missing. You’ve got to use the definitions on the right to match to a term, and fill in the missing part of the term.

Exercise Solutions

What’s My Purpose

Below on the left are some of the new terms you’ve learned in this chapter. On the right are descriptions of what those terms mean, and how they’re used. Your job is to match the term on the left with what that term’s purpose is on the right.

Sharpen your pencil

Time to write some more use cases.

Below are three more potential customers that are interested in Doug’s Dog Doors. For each customer, your job is to write a use case to solve the customer’s problem.

Answers in Sharpen your pencil answers.

Sharpen your pencil answers

Time to write some more use cases!

You’ve seen the customers; now let’s look at the use cases. Here is how we wrote our use cases for the dog-loving folks in Sharpen your pencil. See if your use cases look anything like ours.

More Use Case Magnets

Remember the three parts of a use case? It’s time to put what you’ve learned into action. On these pages, you’ll find several use cases; your job is to match the use case magnets on the bottom of the page to the correct parts of each use case.

Holly and Bruce’s Dog Door

Bruce scratches at the dog door to be let out. The dog door automatically opens, and Bruce goes outside. The dog door closes after a preset time. Bruce goes to the bathroom, and then scratches at the door again. The dog door opens automatically, and Bruce returns inside. The dog door then closes automatically.

If Bruce scratches at the door but stays inside (or stays outside), he can scratch at the door again to re-open it, from inside or outside.

Note

You should be able to follow these alternate use case formats without much trouble. If you get confused, check out Appendix A for the scoop on alternate use case formats.

Kristen and Bitsie’s Dog Door

Kristen enters a code on a keypad.

The dog door and all the windows in the house lock.

John and Tex’s Dog Door

Primary Actor: Tex

Secondary Actor: John

Preconditions: The dog door is open for Tex to go outside.

Goal: Tex uses the bathroom and comes back inside, without getting mud inside the house.

Main Path

Tex goes outside.

The dog door closes automatically.

Tex does his business.

John presses a button.

The dog door opens.

Tex comes back inside.

The door closes automatically.

Extensions

3.1 Tex gets muddy.

3.2 John cleans Tex up.

Answers in Use Case Magnets Solutions.

Use Case Magnets Solutions

Remember the three parts of a use case? It’s time to put what you’ve learned into action. On these pages, you’ll find several use cases (in different formats, no less!); your job is to match the use case magnets on the bottom of the page up to the correct parts of each use case.

Sharpen your pencil

What’s the real power of use cases?

You’ve already seen how use cases help you build a complete requirements list. Below are several more use cases to check out. Your job is to figure out if the requirements list next to each use case covers everything, or if you need to add in additional requirements.

Answers in Sharpen your pencil answers

Sharpen your pencil answers

What’s the real power of use cases?

In each situation below, the use case describes how the dog door should work-but the requirements aren’t complete. Here are the things we saw that were missing from the requirement list, based on the ever-helpful use case.

Be careful! Good use cases make for good requirements, but a bad-or incomplete-use case can result in BAD requirements!

Tools for your OOA&D Toolbox

OOA&D is all about writing great software, and you can’t do that without making sure your apps do exactly what customers want them to.

In this chapter, you learned several tools for making sure your customers are smiling when you show them the systems you’ve built. Here are some key tools to keep handy:

* Readers of Head First Design Patterns will find these categories familiar... that’s because OOA&D and design patterns go hand in hand.

Bullet Points

Requirements are things your system must do to work correctly.

Your initial requirements usually come from your customer.

To make sure you have a good set of requirements, you should develop use cases for your system.

Use cases detail exactly what your system should do.

A use case has a single goal, but can have multiple paths to reach that goal.

A good use case has a starting and stopping condition, an external initiator, and clear value to the user.

A use case is simply a story about how your system works.

You will have at least one use case for each goal that your system must accomplish.

After your use cases are complete, you can refine and add to your requirements.

A requirements list that makes all your use cases possible is a good set of requirements.

Your system must work in the real world, not just when everything goes as you expect it to.

When things go wrong, your system must have alternate paths to reach the system’s goals.

OOA&D Cross

Across

Down

4. The main path is sometimes called the ________ path.

5. A use case must have this (two words) to the user.

8. Requirements ensure that your system works _________.

10. In the dog door system, who was the external initiator?

13. Use cases focus on a ___________ user goal.

14. When Fido is here, the dog door has hit its stop condition.

16. A use case is just a list of things that a system _________.

18. A use case tells a ________ about how a system works.

21. Use cases are easiest to understand when they’re in this kind of language.

22. Good use cases make for ________ requirements.

24. A use case helps you understand how a system will be ______.

25. Use cases help you gather ___________.

1. A use case details how a system __________ with users or others systems.

2. When things go right. you’re on this.

3. Use cases are all about the “______” of your system.

6. Without use cases, you won’t know if your requirements are ___________.

7. If you have four goals in a system, you’ll have at least this many use cases.

9. Good systems work in the _____ ________.

11. Fido does this to signal the start of the dog doors system’s use case.

12. When things go wrong, you end up on an __________ path.

15. Fido isn’t part of this, but his dog door is.

17. This is what you should do to the customer to gather an initial set of requirements.

19. How many use cases are there in Todd and Gina’s dog door?

20. Fido was chasing these when he got stuck outside.

23. A requirement documents this many needs.

Code Magnets Solutions

The DogDoor class is done, so all you need now is to write a class for the remote control. We’ve started this class below, but it’s your job to finish things up. Using the code magnets at the bottom of the page, complete the code for the Remote class.

Be careful... you may not need all the magnets.

Exercise Solutions

Chapter 3. Requirements Change: I Love You, You’re Perfect... Now Change

Think you’ve got just what the customer wanted? Not so fast... So you’ve talked to your customer, gathered requirements, written out your use cases, and delivered a killer application. It’s time for a nice relaxing cocktail, right? Right... until your customer decides that they really wanted something different than what they told you. They love what you’ve done, really, but it’s not quite good enough anymore. In the real world, requirements are always changing, and it’s up to you to roll with these changes and keep your customer satisfied.

You’re a hero!

A nice piña colada to sip on, the sun shining down on you, a roll of hundred dollar bills stuffed into your swim trunks... this is the life of a programmer who’s just made Doug’s Dog Doors a successful venture. The door you built for Todd and Gina was a huge success, and now Doug’s selling it to customers all across the world.

But then came a phone call...

You: Oh, has something gone wrong?

Todd and Gina: No, not at all. The door works just like you said it would.

You: But there must be a problem, right? Is the door not closing quickly enough? Is the button on the remote not functioning?

Todd and Gina: No, really... it’s working just as well as the day you installed it and showed everything to us.

You: Is Fido not barking to be let out anymore? Oh, have you checked the batteries in the remote?

Todd and Gina: No, we swear, the door is great. We just have a few ideas about some changes we’d like you to make...

You: But if everything is working, then what’s the problem?

Back to the drawing board

Time to get working on fixing up Todd and Gina’s dog door again. We need to figure out a way to open the door whenever Fido barks. Let’s start out by...

The customer is always right

Even when requirements change, you’ve got to be ready to update your application and make sure it works like your customers expect. When your customer has a new need, it’s up to you to change your applications to meet those new needs.

Note

Doug loves it when this happens, since he gets to charge Todd and Gina for the changes you make.

Brain Power

You’ve just discovered the one constant in software analysis and design. What do you think that constant is?

The one constant in software analysis and design[1]

Okay, what’s the one thing you can always count on in writing software?

No matter where you work, what you’re building, or what language you are programming in, what’s the one true constant that will always be with you?

(use a mirror to see the answer)

No matter how well you design an application, over time the application will always grow and change. You’ll discover new solutions to problems, programming languages will evolve, or your friendly customers will come up with crazy new requirements that force you to “fix” working applications.

Requirements always change. If you’ve got good use cases, though, you can usually change your software quickly to adjust to those new requirements.

Sharpen your pencil

Requirements change all the time... sometimes in the middle of a project, and sometimes when you think everything is complete. Write down some reasons that the requirements might change in the applications you currently are working on.

My customer decided that they wanted the application to work differently._______________________

My boss thinks my application would be better as a web application than a desktop app._____________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Exercise

Add bark recognition to Todd and Gina’s dog door.

Update the diagram, and add an alternate path where Fido barks, Doug’s new bark recognizer hears Fido, and the dog door automatically opens. The remote control should still work, too, so don’t remove anything from the diagram; just add another path where Fido’s barking opens the door.

Exercise Solutions

Doug’s invented hardware to recognize barks, but it’s up to you to figure out how to use his new hardware in the dog door system.

Here’s how we solved Todd and Gina’s problem, and implemented their bark-recognizing dog door. See if you made similar additions to the diagram.

Optional Path? Alternate Path? Who can tell?

Use cases have to make sense to you

If a use case is confusing to you, you can simply rewrite it. There are tons of different ways that people write use cases, but the important thing is that it makes sense to you, your team, and the people you have to explain it to. So let’s rewrite the use case from page 121 so it’s not so confusing.

Excellent idea!

The main path should be what you want to have happen most of the time. Since Todd and Gina probably want the bark recognizer to handle Fido more than they want to use the remote, let’s put those steps on the main path:

Start to finish: a single scenario

With all the alternate paths in the new use case, there are lots of different ways to get Fido outside to use the bathroom, and then back in again. Here’s one particular path through the use case:

There are no Dumb Questions

Q:

Q: I understand the main path of a use case, but can you explain what an alternate path is again?

A:

A: An alternate path is one or more steps that a use case has that are optional, or provide alternate ways to work through the use case. Alternate paths can be additional steps added to the main path, or provide steps that allow you to get to the goal in a totally different way than parts of the main path.

Q:

Q: So when Fido goes outside and gets stuck, that’s part of an alternate path, right?

A:

A: Right. In the use case, Steps 6.1, 6.2, 6.3, 6.4, and 6.5 are an alternate path. Those are additional steps that the system may go through, and are needed only when Fido gets stuck outside. But it’s an alternate path because Fido doesn’t always get stuck outside—the system could go from Step 6 directly on to Step 7.

Q:

Q: And we use sub-steps for that, like 6.1 and 6.2?

A:

A: Exactly. Because an alternate path that has additional steps is just a set of steps that can occur as part of another step on the use case’s main path. When Fido gets stuck outside, the main path steps are 6 and 7, so the alternate path steps start at 6.1 and go through 6.5; they’re an optional part of Step 6.

Q:

Q: So what do you call it when you have two different paths through part of a use case?

A:

A: Well, that’s actually just another kind of alternate path. When Fido barks, there’s one path that involves Todd and Gina hearing Fido and opening the door, and another path that involves the bark recognizer hearing a bark and opening the door. But the system is designed for one or the other—either the remote opens the door, or the bark recognizer does—not both.

Q:

Q: Can you have more than one alternate path in the same use case?

A:

A: Absolutely. You can have alternate paths that provide additional steps, and multiple ways to get from the starting condition to the ending condition. You can even have an alternate path that ends the use case early... but we don’t need anything that complicated for Todd and Gina’s dog door.

A complete path through a use case, from the first step to the last, is called a scenario.

Most use cases have several different scenarios, but they always share the same user goal.

Use Cases Exposed

This week’s interview: Confessions of an Alternate Path

HeadFirst: Hello, Alternate Path. We’ve been hearing that you’re really unhappy these days. Tell us what’s going on.

Alternate Path: I just don’t feel very included sometimes. I mean, you can hardly put together a decent use case without me, but I still seem to get ignored all the time.

HeadFirst: Ignored? But you just said you’re part of almost every use case. It sounds like you’re quite important, really.

Alternate Path: Sure, it may sound that way. But even when I’m part of a use case, I can get skipped over for some other set of steps. It really sucks... it’s like I’m not even there!

HeadFirst: Can you give us an example?

Alternate Path: Just the other day, I was part of a use case for buying a CD at this great new online store, Musicology. I was so excited... but it turned out that I handled the situation when the customer’s credit card was rejected.

HeadFirst: Well, that sounds like a really important job! So what’s the problem?

Alternate Path: Well, yeah, I guess it’s important, but I always get passed over. It seems like everyone was ordering CDs, but their credit cards were all getting accepted. Even though I was part of the use case, I wasn’t part of the most common scenarios.

HeadFirst: Oh, I see. So unless someone’s credit card was rejected, you were never involved.

Alternate Path: Exactly! And the finance and security guys loved me, they just went on and on about how much I’m worth to the company, but who wants to sit there unused all the time?

HeadFirst: I’m starting to get the picture. But you’re still helping the use case, right? Even if you’re not used all the time, you’re bound to get called on once in a while.

Alternate Path: That’s true; we all do have the same goal. I just didn’t realize that I could be important to the use case and still hardly ever get noticed.

HeadFirst: Well, just think... the use case wouldn’t be complete without you.

Alternate Path: Yeah, that’s what 3.1 and 4.1 keep telling me. Of course, they’re part of the alternate path for when customers already have an account on the system, so they get used constantly. Easy for them to say!

HeadFirst: Hang in there, Alternate Path. We know you’re an important part of the use case!

Sharpen your pencil

How many scenarios are in Todd and Gina’s use case?

How many different ways can you work your way through Todd and Gina’s use case? Remember, sometimes you have to take one of multiple alternate paths, and sometimes you can skip an alternate path altogether.

Check out our answers on the next page

Sharpen your pencil answers

How many scenarios are in Todd and Gina’s use case?

How many different ways can you work your way through Todd and Gina’s use case? Remember, sometimes you have to take one of multiple alternate paths, and sometimes you can skip an alternate path altogether.

Let’s get ready to code...

Now that our use case is finished up, and we’ve figured out all the possible scenarios for using the dog door, we’re ready to write code to handle Todd and Gina’s new requirements. Let’s figure out what we need to do...

Any time you change your use case, you need to go back and check your requirements.

Remember, the whole point of a good use case is to get good requirements. If your use case changes, that may mean that your requirements change, too. Let’s review the requirements and see if we need to add anything to them.

Todd and Gina’s Dog Door, version 2.2

Requirements List

The dog door opening must be at least 12” tall.

A button on the remote control opens the dog door if the door is closed, and closes the dog door if the door is open.

Once the dog door has opened, it should close automatically if the door isn’t already closed.

Note

Go ahead and write in any additional requirements that you’ve discovered working through the scenarios for the new dog door in Sharpen your pencil answers.

Finishing up the requirements list

So we need to handle the two new alternate paths by adding a couple extra requirements to our requirements list. We’ve gone ahead and crossed off the steps that our requirements already handle, and it looks like we need a few additions to our requirements list:

Now we can start coding the dog door again

With new requirements comes new code. We need some barking, a bark recognizer to listen for barking, and then a dog door to open up:

Was that a “woof” I heard?

We need some software to run when Doug’s hardware “hears” a bark. Let’s create a BarkRecognizer class, and write a method that we can use to respond to barks:

There are no Dumb Questions

Q:

Q: That’s it? It sure seems like the BarkRecognizer doesn’t do very much.

A:

A: Right now, it doesn’t. Since the requirements are simple—when a dog barks, open the door—your code is pretty simple, too. Any time the hardware hears a bark, it calls recognize() in our new BarkRecognizer class, and we open the dog door. Remember, keep things as simple as you can; there’s no need to add complexity if you don’t need it.

Q:

Q: But what happens if a dog other than Fido is barking? Shouldn’t the BarkRecognizer make sure it’s Fido that is barking before opening the dog door?

A:

A: Very interesting question! The BarkRecognizer hears all barks, but we really don’t want it to open the door for just any dog, do we? We may have to come back and fix this later. Maybe you should think some more about this while we’re testing things out.

First, let’s make sure we’ve taken care of Todd and Gina’s new requirements for their door:

Power up the new dog door

Use cases, requirements, and code have all led up to this. Let’s see if everything works like it should.

Update the DogDoorSimulator source code:

Note

* The authors of this book sincerely wanted to include hardware that could hear dogs barking... but marketing insists that nobody would buy a book priced at $299.95. Go figure!

Recompile all your Java source code into classes.

Run the code and watch the humanless dog door go into action.

Brain Power

There’s a big problem with our code, and it shows up in the simulator. Can you figure out what the problem is? What would you do to fix it?

Sharpen your pencil

Which scenario are we testing?

Can you figure out which scenario from the use case we’re testing? Write down the steps this simulator follows (flip back to Use cases have to make sense to you to see the use case again):

_____________________________________________________________________

Sharpen your pencil answers

Which scenario are we testing?

Did you figure out which scenario from the use case we’re testing? Here are the steps from the use case in Use cases have to make sense to you that we followed:

1, 2, 3, 4, 5, 6, 6.1, 6.2, 6.3, 6.4, 6.5, 7, 8

Brain Power

There’s a big problem with our code, and it shows up in the simulator. Can you figure out what the problem is? What would you do to fix it?

Note

Did you figure out what was wrong with our latest version of the dog door?

In our new version of the dog door, the door doesn’t automatically close!

In the scenarios where Todd and Gina press the button on the remote control, here’s the code that runs:

But in BarkRecognizer, we open the door, and never close it:

What do YOU think about Doug’s idea?

Duplicate code is a bad idea. But where should the code that closes the door go?

Let’s have the dog door close automatically all the time.

Since Gina never wants the dog door left open, the dog door should always close automatically. So we can move the code to close the door automatically into the DogDoor class. Then, no matter what opens the door, it will always close itself.

Note

Even though this is a design decision, it’s part of getting the software to work like the customer wants it to. Remember, it’s OK to use good design as you’re working on your system’s functionality.

Updating the dog door

Let’s take the code that closed the door from the Remote class, and put it into our DogDoor code:

Simplifying the remote control

You’ll need to take this same code out of Remote now, since the dog door handles automatically closing itself:

A final test drive

You’ve made a lot of changes to Todd and Gina’s dog door since they first called you up. Let’s test things out and see if everything works. Make the changes to Remote.java and DogDoor.java so that the door closes itself, compile all your classes again, and run the simulator:

Brain Power

What would happen if Todd and Gina decided they wanted the door to stay open longer? Or to close more quickly? See if you can think of a way to change the DogDoor so that the amount of time that passes before the door automatically closes can be set by the customer.

Sometimes a change in requirements reveals problems with your system that you didn’t even know were there.

Change is constant, and your system should always improve every time you work on it.

Sharpen your pencil

Write your own design principle!

You’ve used an important design principle in this chapter related to duplicating code, and the dog door closing itself. Try and summarize the design principle that you think you’ve learned:

More Tools for your OOA&D Toolbox

You’ve learned a lot in this chapter, and now it’s time to add what you’ve picked up to your OOA&D toolbox. Review what you’ve learned on this page, and then get ready to put it all to use in the OOA&D cross on the next page.

Bullet Points

Requirements will always change as a project progresses.

When requirements change, your system has to evolve to handle the new requirements.

When your system needs to work in a new or different way, begin by updating your use case.

A scenario is a single path through a use case, from start to finish.

A single use case can have multiple scenarios, as long as each scenario has the same customer goal.

Alternate paths can be steps that occur only some of the time, or provide completely different paths through parts of a use case.

If a step is optional in how a system works, or a step provides an alternate path through a system, use numbered sub-steps, like 3.1, 4.1, and 5.1, or 2.1.1, 2.2.1, and 2.3.1.

You should almost always try to avoid duplicate code. It’s a maintenance nightmare, and usually points to problems in how you’ve designed your system.

OOA&D Cross

The puzzles keep coming. Make sure you’ve gotten all the key concepts in this chapter by working this crossword. All the answer words are somewhere in this chapter.

Across

Down

2. We made this responsible for closing the dag door.

4. This is what you follow in a use case most of the time.

5. When your use case changes, these often changes as well.

6. Requirements always change over ______.

8. We had to add this to our dog door to satisfy Tadd and Gina.

10. When your system changes, you should always update this before writing code.

11. Use cases often have __________ Scenarios.

12. Many real-world applications involve both software and this.

13. The one constant in software analysis and design.

1. If a step is optional, use this in your use case.

2. Always avoid ____________ code.

3. A set of steps that don’t always occur in your use case.

7. Do this to things that vary.

9. The main path is also called this.

10. Every scenario in a use case shares the same _____ _____.

Exercise Solutions

[1] If you’ve read Head First Design Patterns, this page might look a bit familiar. They did such a good job describing change that we decided to just rip off their ideas, and just CHANGE a few things here and there. Thanks, Beth and Eric!

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:

Sharpen your pencil

What’s wrong with this diagram?

It’s your job to figure out how you would fix the dog door. You can add steps, remove steps, or change steps... it’s up to you. Write down what you think you need to change, and then mark your changes on the diagram above.

_____________________________________________________________________

_____________________________________________________________________

Sharpen your pencil answers

What’s wrong with this diagram?

There are no Dumb Questions

Q:

Q: I came up with a different solution. Does that mean my solution is wrong?

A:

A: No, as long as your solution kept all the dogs except for Bruce from going in and out of the dog door. That’s what makes talking about software so tricky: there’s usually more than one way to solve a problem, and there’s not always just one “right” solution.

Q:

Q: In my solution, I turned step 3 of the original use case into two steps, instead of just replacing the existing step. Where did I go wrong?

A:

A: You didn’t go wrong. Just as there is usually more than one solution to a problem, there is usually more than one way to write that solution in a use case. If you use more than one step, but have the scenario with other dogs barking handled, then you’ve got a working use case.

Q:

Q: So these use cases really aren’t that precise, are they?

A:

A: Actually, use cases are very precise. If your use case doesn’t detail exactly what your system is supposed to do, then you could miss an important requirement or two and end up with unhappy customers.

But, use cases don’t have to be very formal; in other words, your use case may not look like ours, and ours might not look like anyone else’s. The important thing is that your use case makes sense to you, and that you can explain it to your co-workers, boss, and customers.

Write your use cases in a way that makes sense to you, your boss, and your customers.

Analysis and your use cases let you show customers, managers, and other developers how your system works in a real world context.

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.

Sharpen your pencil

Add a new use case to store a bark.

You need a use case to store the owner’s dog’s bark; let’s store the sound of the dog in the dog door itself (Doug’s hardware guys tell us that’s no problem for their door technology). Use the use case template below to write a new use case for this task.

Sharpen your pencil answers

Add a new use case to store a bark.

You need a use case to store the owner’s dog’s bark; let’s store the sound of the dog in the dog door itself (Doug’s hardware guys tell us that’s no problem for their door technology). Use the use case template below to write a new use case for this task.

There are no Dumb Questions

Q:

Q: Do we really need a whole new use case for storing the owner’s dog’s bark?

A:

A: Yes. Each use case should detail one particular user goal. The user goal for our original use case was to get a dog outside and back in without using the bathroom in the house, and the user goal of this new use case is to store a dog’s bark. Since those aren’t the same user goal, you need two different use cases.

Q:

Q: Is this really the result of good analysis, or just something we should have thought about in the last two chapters?

A:

A: Probably a bit of both. Sure, we probably should have figured out that we needed to store the owner’s dog’s bark much earlier, but that’s what analysis is really about: making sure that you didn’t forget anything that will help your software work in a real world context.

Q:

Q: How are we representing the dog’s bark?

A:

A: That’s a good question, and it’s one you’re going to have to answer next...

Design Puzzle

You know what classes you already have, and you’ve got two use cases that tell you what your code has to be able to do. Now it’s up to you to figure out how your code needs to change:

Your task:

Add any new objects you think you might need for the new dog door.

Add a new method to the DogDoor class that will store a dog’s bark, and another new method to allow other classes to access the bark.

If you need to make changes to any other classes or methods, write in those changes in the class diagram below.

Add notes to the class diagram to remind you what any tricky attributes or operations are used for, and how they should work.

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:

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:

Sharpen your pencil

Writing code based on a class diagram is a piece of cake.

You’ve already seen that class diagrams give you a lot of information about the attributes and operations of a class. Your job is to write the code for Sam’s Bark class based on his class diagram. We’ve written just a bit of the code to help get you started.

public class ____________ {
  private ___________ _________;

  public _____________(__________ ___________) {
    this._________ = ___________;
  }

  public ________ ___________() {
    __________ _________;
  }

  _________ _____________ ______________(________ ________) {
    if (________ instanceof _________) {
      Bark otherBark = (_________)_________;
      if (this._________.equalsIgnoreCase(_______._______)) {
        return __________;
      }
    }
    return ____________;
  }
}

Sharpen your pencil answers

Writing code based on a class diagram is a piece of cake.

Your job was to write the code for Sam’s Bark class based on his class diagram. Here’s what we did:

Note

Sam’s Bark class diagram.

Bark

sound: String

getSound(): String

equals(Object bark): boolean

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:

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

Sam: I’ll delegate bark comparison

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

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

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.

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

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.

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:

Randy AND Sam: It works!

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

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:

UML Up Close

We’ve added something new to our class diagrams:

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.

Sharpen your pencil

Your job is to circle each noun (that’s a person, place, or thing) in the use case below. Then, in the blanks at the bottom of the page, list all the nouns that you found (just write each one a single time; don’t duplicate any nouns). Be sure to do this exercise before turning the page!

Sharpen your pencil answers

Your job was to circle each noun (that’s a person, place, or thing) in the use case below. Here’s the use case with all the nouns circled.

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?

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.

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!

There are no Dumb Questions

Q:

Q: So you’re telling me as long as I write use cases, all my software will work like it should?

A:

A: Well, use cases are certainly a good start towards writing good software. But there’s a lot more to it than that. Remember, analysis helps you figure out the classes from your use case, and in the next chapter, we’ll spend some time talking about good design principles in writing those classes.

Q:

Q: I’ve never used use cases before, and I’ve never had any problems. Are you saying that I have to write use cases to create good software?

A:

A: No, not at all. There are plenty of programmers who are good at their jobs, and don’t even know what a use case is. But if you want your software to satisfy the customer more often, and you want your code to work correctly with less rework, then use cases can really help you nail your requirements down... before you make embarrassing mistakes in front of your boss or a customer.

Q:

Q: It seems like this stuff about nouns and analysis is pretty tricky, and I’m not any good at English grammar. What can I do?

A:

A: You really don’t need to focus too much on grammar. Just write your use cases in conversational English (or whatever language you speak and write in). Then figure out what the “things” are in your use case—those are generally the nouns. For each noun, think about if you need a class to represent it, and you’ve got a good start on a real-world analysis of your system.

Q:

Q: But what if I make a mistake like Randy did, and use a noun in my use case when I shouldn’t?

A:

A: Randy’s mistake—using “bark” as a noun in step 3 of his use case—had nothing to do with Randy’s grammar. He didn’t think through the use case, and how his system would work in the real world. Instead of focusing on getting the owner’s dog outside, he was worrying about one specific bark. He focused on the wrong thing!

When you write your use case, reread it, and make sure that it makes sense to you. You might even want to let a couple of friends or co-workers read through it, too, and make sure it will work in the real world, not just in a controlled environment.

A good use case clearly and accurately explains what a system does, in language that’s easily understood.

With a good use case complete, textual analysis is a quick and easy way to figure out the classes in your system.

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.

Sharpen your pencil

Why is there no Dog class?

When you picked the nouns out of the use case, one that kept showing up was “the owner’s dog.” But Maria decided not to create a Dog object. Why not? Below, write down three reasons you think Maria didn’t create a Dog class in her system.

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Answers in Sharpen your pencil answers.

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:

Code Magnets

It’s time to do some more textual analysis. Below is the use case for the dog door you’ve been developing. At the bottom of the page are magnets for most of the classes and methods we’ve got in our system so far. Your job is to match the class magnets up with the nouns in the use case, and the method magnets up with the verbs in the use case. See how closely the methods line up with the verbs.

Code Magnets Solutions

It’s time to do some more textual analysis. Below is the use case for the dog door you’ve been developing. At the bottom of the page are magnets for most of the classes and methods we’ve got in our system so far. Your job is to match the class magnets up with the nouns in the use case, and the method magnets up with the verbs in the use case. See how closely the methods line up with the verbs.

Sharpen your pencil answers

Why didn’t Maria create a Dog class?

When you picked the nouns out of the use case, one that kept showing up was “the owner’s dog.” But Maria decided not to create a Dog object. Why not? Here are three reasons we think Maria made the right choice.

There are no Dumb Questions

Q:

Q: So the nouns in the use case turn into classes, and the verbs turn into methods?

A:

A: That’s almost it. Actually, the nouns are candidates for classes... not every noun will be a class. For instance, “the owner” is a noun in the use case (check out Steps 2.1 and 3.1, for example), but we don’t need a class for that noun. So even though “the owner” is a candidate for a class, it doesn’t become a class in the actual system.

In the same way, the verbs are candidates for operations. For example, one verb phrase is “does his business,” but we just couldn’t bear to write a pee() or poop() method. We hope you’ll agree that we made the right choice! Still, textual analysis is a really good start to figuring out the classes and methods you’ll need in your system.

Q:

Q: It looks like the nouns that are outside the system don’t get turned into classes. Is that always true?

A:

A: Most of the time it is. The only common exception is when you have to interact with something outside the system—like when there’s some state or behavior that the system needs to work with on a recurring basis.

In the dog door system, for example, we didn’t need a class for the owner because the Remote class took care of all the owner-related activity. If we ever needed to track owner state, though—like if the owner was asleep or awake—then we might have to create an Owner class.

From good analysis to good classes...

Maria’s Dog Door Class Diagram

UML Investigation

Maria’s gone pretty crazy with her UML diagrams... do you think you can figure out what all she’s done? On the diagram below, add notes to all the new things she’s added, and try and figure out what the lines, numbers, and additional words all mean. We’ve written a few notes of our own to get you started.

Answers in UML Investigation Complete.

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.

Sharpen your pencil

Based on the class diagram below, what types could you use for the barks member variable in your DogDoor class? Write your ideas in the blank below:

Note

Answers to this exercise are in Sharpen your pencil answers.

_____________________________________________________________________

UML Investigation Complete

Maria’s gone pretty crazy with her UML diagrams... see if you can figure out everything that she’s done.

Exercise Solutions

Sharpen your pencil answers

Based on the class diagram below, what types could you use for the barks member variable in your DogDoor class? Write your ideas in the blank below:

List, Array, Vector, etc._________________________________

Note

You could write any type that supports multiple values... most of the Java Collection classes would work.

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

What’s Missing

Class diagrams are great for modeling the classes you need to create, but they don’t provide all the answers you’ll need in programming your system. You’ve already seen that the dog door class diagram doesn’t tell us much about matching up return types; what other things do you think are unclear from this diagram that you might need to know to program the dog door?

Add notes to the diagram below about what you might need to figure out in order to program the door. We’ve added a note about comparing barks to get you started.

Answer in What’s Missing

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:

Exercise Solutions

What’s Missing

Add notes to the diagram about what you might need to figure out to program the door.

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

Bullet Points

Analysis helps you ensure that your software works in the real world context, and not just in a perfect environment.

Use cases are meant to be understood by you, your managers, your customers, and other programmers.

You should write your use cases in whatever format makes them most usable to you and the other people who are looking at them.

A good use case precisely lays out what a system does, but does not indicate how the system accomplishes that task.

Each use case should focus on only one customer goal. If you have multiple goals, you will need to write multiple use cases.

Class diagrams give you an easy way to show your system and its code constructs at a 10,000-foot view.

The attributes in a class diagram usually map to the member variables of your classes.

The operations in a class diagram usually represent the methods of your classes.

Class diagrams leave lots of detail out, such as class constructors, some type information, and the purpose of operations on your classes.

Textual analysis helps you translate a use case into code-level classes, attributes, and operations.

The nouns of a use case are candidates for classes in your system, and the verbs are candidates for methods on your system’s classes.

Design Puzzle

Maria’s old computer screwed up all the code she wrote for her dog door except for DogDoorSimulator.java, shown on the next page. All we’ve got to go on are the code fragments from her solution in this chapter, her class diagrams, and what you’ve learned about good analysis, requirements and OO programming. It’s your turn to be a hero...

The problem:

You need to code the dog door application so that it satisfies all of Doug’s new customers (that’s a lot of potential sales), especially the ones with more than one dog in the neighborhood. The door should operate just as the use cases in this chapter describe the system.

Your task:

Start out by re-creating the dog door application as it was described in Chapter 3. You can download this code from the Head First Labs web site if you want a jump start.

Copy or download DogDoorSimulator.java, shown on the next page. This is the only file that survived Maria’s laptop meltdown.

Make your code match up with Maria’s class diagram, shown in From good analysis to good classes....

Start coding! First concentrate on getting all of your classes to compile, so you can begin testing.

Use the DogDoorSimulator class to see if things are working like they should.

Keep up the analysis and coding until your test class’s output matches the output shown on the next page. Don’t give up!

Once you think you’ve got a working dog door, check your code against ours at the Head First Labs web site. We’ll be waiting.

What’s My Definition

UML and use cases have a lot of terms that are similar to, but not quite the same as, the programming terms you’re already familiar with. Below are several OOA&D-related terms, and their definitions... but everything is all mixed up. Connect the term to the definition, and unscramble the mess.

Noun Analysis

Lists all the code-level constructs, along with their attributes and operations.

Multiplicity

This is the UML term that usually represents a method in one of your classes.

Attribute

Helps you figure out the candidates for methods on the objects in your system.

Class Diagram

Visually shows that one class has a relation to another class, often through an attribute.

Operation

Equivalent to a member variable in a class.

Association

Describes how many of a specific type can be stored in an attribute of a class.

Verb Analysis

You do this to your use case to figure out what classes you need in your system.

OOA&D Cross

You know you love it... try another puzzling crossword to get those new concepts lodged firmly in your brain.

Across

Down

1. Use cases should use this kind of language.

2. Analysis makes sure your application works in this place.

5. Every class diagram has one of these for each member variable.

3. An operation is UML-ese for this

10. This focuses on putting your application into the correct context.

4. You do this to your use cases to figure out the classes and operation in your system.

12. Software always works better in the testing lab than here.

6. He replaced Fido as this chapter’s star.

13. Maria won the laptop because she paid attention to the

7. Class diagrams are a great way to get this of your system.

14. This relates one class to another

8. How many of a type an attribute can hold is its ____________.

16. You write your use case so you can ____________ your customers

9. These types of diagrams are worth a thousand words to a programmer.

17. Use cases should be ________ as well as easily understood.

11. Use cases aren’t formal, but they are ________.

18. UML is this type of modeling language.

15. Verb is to operation as this is to attribute.

Exercise Solutions

What’s My Definition

UML and use cases have a lot of terms that are similar to, but not quite the same as, the programming terms you’re already familiar with. Below are several OOA&D-related terms, and their definitions... but everything is all mixed up. Connect the term to the definition, and unscramble the mess.

Chapter 5. (Part 1) Good Design = Flexible Software: Nothing Ever Stays the Same

Change is inevitable. No matter how much you like your software right now, it’s probably going to change tomorrow. And the harder you make it for your software to change, the more difficult it’s going to be to respond to your customer’s changing needs. In this chapter, we’re going to revisit an old friend, try and improve an existing software project, and see how small changes can turn into big problems. In fact, we’re going to uncover a problem so big that it will take a TWO-PART chapter to solve it!

Rick’s Guitars Stringed Instruments is expanding

Fresh off the heels of selling three guitars to the rock group Augustana, Rick’s guitar business is doing better than ever—and the search tool you built Rick back in Chapter 1 is the cornerstone of his business.

Let’s put our design to the test

We’ve talked a lot about good analysis and design being the key to software that you can reuse and extend... and now it looks like we’re going to have to prove that to Rick. Let’s figure out how easy it is to restructure his application so that it supports mandolins.

Sharpen your pencil

Add support for mandolins to Rick’s search tool.

Below is the completed class diagram for Rick’s guitar search app, just like it was when we finished up with Chapter 1. It’s up to you to add to this diagram so that Rick can start selling mandolins, and your search tool can help him find mandolins that match his clients’ preferences, just like he already can with guitars.

Note

HINT: Do a Guitar and Mandolin have anything in common? If so, maybe a little inheritance might be the way to go.

Sharpen your pencil partial answers

Add support for mandolins to Rick’s search tool.

Below is the completed class diagram for Rick’s guitar search app, just like it was when we finished up with Chapter 1. Here’s what we did first to add support for mandolins (we’ll make some more changes over the next few pages).

Did you notice that abstract base class?

Take a close look at the new Instrument class that we created:

Abstract classes are placeholders for actual implementation classes.

Instrument is an abstract class: that means that you can’t create an instance of Instrument. You have to define subclasses of Instrument, like we did with Mandolin and Guitar:

The abstract class defines behavior, and the subclasses implement that behavior.

We made Instrument abstract because Instrument is just a placeholder for actual instruments like Guitar and Mandolin. An abstract class defines some basic behavior, but it’s really the subclasses of the abstract class that add the implementation of those behaviors. Instrument is just a generic class that stands in for your actual implementation classes.

We’ll need a MandolinSpec class, too

Mandolins and guitars are similar, but there are just a few things different about mandolins... we can capture those differences in a MandolinSpec class:

It’s OK if you don’t know anything about mandolins, or didn’t figure out the different properties in the MandolinSpec class. The main thing is that you realized we probably need a new class for mandolins and their specs. If you came up with using an Instrument interface or abstract class, all the better!

Brain Power

What do you think about this design? Will it do what the customer wants it to do? How flexible is it? Do you think software designed like this will be easy to extend and maintain?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

There are no Dumb Questions

Q:

Q: We made Instrument abstract because we abstracted the properties common to Guitar and Mandolin into it, right?

A:

A: No, we made Instrument abstract because in Rick’s system right now, there’s no such thing as an actual “instrument.” All it does is provide a common place to store properties that exist in both the Guitar and Mandolin classes. But since an instrument currently has no behavior outside of its subclasses, it’s really just defining common attributes and properties that all instruments need to implement.

So while we did abstract out the properties common to both instrument types, that doesn’t necessarily mean that Instrument has to be abstract. In fact, we might later make Instrument a concrete class, if that starts to make sense in our design...

Q:

Q: Couldn’t we do the same thing with GuitarSpec and MandolinSpec? It looks like they share a lot of common attributes and operations, just like Guitar and Mandolin.

A:

A: Good idea! We can create another abstract base class, called InstrumentSpec, and then have GuitarSpec and MandolinSpec inherit from that base class:

Let’s put everything together...

Behold: Rick’s new application

It looks like all that work on design back in Chapter 1 has paid off; it took us less than 10 pages to add support for mandolins to Rick’s search tool. Here’s the completed class diagram:

Whenever you find common behavior in two or more places, look to abstract that behavior into a class, and then reuse that behavior in the common classes.

Note

Here’s the principle that led to us creating both the Instrument and InstrumentSpec abstract base classes.

Class diagrams dissected (again)

Now that you’ve added abstract classes, subclasses, and a new kind of association, it’s time to upgrade your UML and class diagram skills.

Note

Fold this page down so you can refer back to it when you forget some of UML’s notation and symbols.

UML Cheat Sheet

What we call it in Java

What we call it in UML

How we show it in UML

Abstract Class

Abstract Class

Italicized Class Name

Relationship

Association

Inheritance

Generalization

Aggregation

Aggregation

There are no Dumb Questions

Q:

Q: Are there lots more types of symbols and notations that I’m going to have to keep up with to use UML?

A:

A: There are a lot more symbols and notations in UML, but it’s up to you how many of them you use, let alone memorize. Many people use just the basics you’ve already learned, and are perfectly happy (as are their customers and managers). But other folks like to really get into UML, and use every trick in the UML toolbox. It’s really up to you; as long as you can communicate your design, you’ve used UML the way it’s intended.

Let’s code Rick’s new search tool

We can start off by creating a new class, Instrument, and making it abstract. Then we put all the properties common to an instrument in this class:

Next we need to rework Guitar.java, and create a class for mandolins. These both extend Instrument to get the common instrument properties, and then define their own constructors with the right type of spec class:

Create an abstract class for instrument specifications

With the instruments taken care of, we can move on to the spec classes. We need to create another abstract class, InstrumentSpec, since so many instruments have common specifications:

Let’s code GuitarSpec...

With InstrumentSpec coded up, it’s pretty simple to write the GuitarSpec class:

... and MandolinSpec, too

After seeing GuitarSpec, MandolinSpec is pretty simple. It’s very similar, with the addition of a member variable to reference the mandolin’s style (like “A” or “F” style), and a slightly different matches() method:

Finishing up Rick’s search tool

All that’s left is to update the Inventory class to work with multiple instrument types, instead of just the Guitar class:

At this point, you’re ready to try out Rick’s improved app. See if you can update FindGuitarTester on your own, and see how things are working with these design changes.

There are no Dumb Questions

Q:

Q: Guitar and Mandolin only have a constructor. That seems sort of silly. Do we really need a subclass for each type of instrument just for that?

A:

A: We do, at least for now. Otherwise, how could you tell a mandolin from a guitar? There’s no other way to figure out what type of instrument you’re working with than by checking the type of the class. Besides, those subclasses allow us to have constructors that ensure that the right type of spec is passed in. So you can’t create a Guitar, and pass a MandolinSpec into its constructor.

Note

These are little indicators that we may have a design problem. When things just don’t seem to make sense in your application, you may want to investigate a little further... which is exactly what we’re about to do.

Q:

Q: But with Instrument as an abstract class, the addInstrument() method in Inventory.java becomes a real pain!

A:

A: You’re talking about addInstrument() in Uh oh... adding new instruments is not easy!, aren’t you? Yes, with Instrument as an abstract class, you do have some extra code to deal with. But it’s still a fairly small price to pay to ensure that you can’t create an Instrument, which really doesn’t exist in the real world.

Q:

Q: Isn’t there some middle ground, though? I mean, even if there’s no such thing as an “instrument” that isn’t a guitar or mandolin or whatever, it still seems like we must have a design problem somewhere. Right?

A:

A: Well, you may be onto something. It does seem like parts of our code would benefit from a concrete Instrument class, while other parts wouldn’t. Sometimes this means you have to make a decision one way or the other, and just accept the trade-off. But maybe there’s more going on here that we’re not thinking about...

Q:

Q: Why do we have two different versions of search()? Can’t we combine those into a single method that takes an InstrumentSpec?

A:

A: Since InstrumentSpec is an abstract class, like Instrument, Rick’s clients will have to give either a GuitarSpec or a MandolinSpec to the search() method in Inventory. And since a spec will match only other specs of the same instrument type, there’s never a case where both mandolins and guitars would be returned in the list of matching instruments. So even if you consolidated the two search() methods into one, you wouldn’t get any functionality benefit—and even worse, it might look like the method would return both mandolins and guitars (since the return type of search() would be Instrument [*]), even though it never actually would.

You’ve made some MAJOR improvements to Rick’s app

You’ve done a lot more than just add support for mandolins to Rick’s application. By abstracting common properties and behavior into the Instrument and InstrumentSpec classes, you’ve made the classes in Rick’s app more independent. That’s a significant improvement in his design.

Great software isn’t built in a day

Along with some major design improvements, we’ve uncovered a few problems with the search tool. That’s OK... you’re almost always going to find a few new problems when you make big changes to your design.

So now our job is to take Rick’s better-designed application, and see if we can improve it even further... to take it from good software to GREAT software.

3 steps to great software (revisited)

Is Rick’s search tool great software?

Remember the three things we talked about that you can do to write great software? Let’s review them to see how well we’ve done on the latest version of Rick’s search tool.

Does the new search tool do what it’s supposed to do?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Have you used solid OO principles, like encapsulation, to avoid duplicate code and make your software easy to extend?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

How easy is it to reuse Rick’s application? Do changes to one part of the app force you to make lots of changes in other parts of the app? Is his software loosely coupled?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Note

Be sure to answer these questions, and then turn the page to see what we wrote down.

Exercise Solutions

Is Rick’s search tool great software?

Remember the three things we talked about that you can do to write great software? Let’s review them to see how well we’ve done on the latest version of Rick’s search tool.

Does the new search tool do what it’s supposed to do?

Absolutely. It finds guitars and mandolins, although not at the same time. So maybe it just mostly does what it’s supposed to do. Better ask Rick to be sure...

Have you used solid OO principles, like encapsulation, to avoid duplicate code and make your software easy to extend?

We used encapsulation when we came up with the InstrumentSpec classes, and inheritance when we developed an Instrument and InstrumentSpec abstract superclass. But it still takes a lot of work to add new instrument types...

How easy is it to reuse Rick’s application? Do changes to one part of the app force you to make lots of changes in other parts of the app? Is his software loosely coupled?

It’s sort of hard to use just parts of Rick’s application. Everything’s pretty tightly connected, and InstrumentSpec is actually part of Instrument (remember when we talked about aggregation?).

Note

It’s OK if you got some different answers and had different ideas than we did on these questions... just make sure you thought things through, and that you understand why we answered how we did.

One of the best ways to see if software is well-designed is to try and CHANGE it.

If your software is hard to change, there’s probably something you can improve about the design. Let’s see how hard it is to add a couple of new instruments to Rick’s app:

Uh oh... adding new instruments is not easy!

If ease of change is how we determine if our software is well-designed, then we’ve got some real issues here. Every time we need to add a new instrument, we have to add another subclass of Instrument:

Then, we need a new subclass of InstrumentSpec, too:

Then things start to really get nasty when you have to update the Inventory class’s methods to support the new instrument type:

So what are we supposed to do now?

It looks like we’ve definitely still got some work to do to turn Rick’s application into great software that’s truly easy to change and extend. But that doesn’t mean the work you’ve done isn’t important... lots of times, you’ve got to improve your design to find some problems that weren’t so apparent earlier on. Now that we’ve applied some of our OO principles to Rick’s search tool, we’ve been able to locate some issues that we’re going to have to resolve if we don’t want to spend the next few years writing new Banjo and Fiddle classes (and who really wants to do that?).

Before you’re ready to really tackle the next phase of Rick’s app, though, there are a few things you need to know about. So, without further ado, let’s take a quick break from Rick’s software, and tune in to...

OO CATASTROPHE: Objectville’s Favorite Quiz Show

there are no Dumb Answers

A: It might not seem like it, but we are working on Rick’s search tool, in a manner of speaking. We’re going to need some pretty advanced OO techniques to make his application flexible and reusable, and we wanted to give you a chance to get a handle on these principles before you had to start applying them to a pretty complicated problem.

Q: Why are we playing a game show? Shouldn’t we be fixing Rick’s search tool?

A: The questions that match up with the answers in this chapter aren’t easy, but you should be able to reason them all out. Take your time; it’s important that you come up with these questions on your own if at all possible, and only then turn the page to get a little more information on each question and the OO principle it involves. Besides, we think you’re getting to be a pretty kick-ass developer, so we have lots of confidence in you.

Q: If these are new OO principles, how am I supposed to figure out what the questions are? That’s asking a lot, isn’t it?

“What is an INTERFACE?”

Note

Did you get this? You should have asked this as the question for the answer in OO CATASTROPHE: Objectville’s Favorite Quiz Show.

Suppose you’ve got an application that has an interface, and then lots of subclasses that inherit common behavior from that interface:

Coding to an interface, rather than to an implementation, makes your software easier to extend.

Anytime you’re writing code that interacts with these classes, you have two choices. You can write code that interacts directly with a subclass, like FootballPlayer, or you can write code that interacts with the interface, Athlete. When you run into a choice like this, you should always favor coding to the interface, not the implementation.

By coding to an interface, your code will work with all of the interface’s subclasses—even ones that haven’t been created yet.

Why is this so important? Because it adds flexibility to your app. Instead of your code being able to work with only one specific subclass—like BaseballPlayer—you’re able to work with the more generic Athlete. That means that your code will work with any subclass of Athlete, like HockeyPlayer or TennisPlayer, and even subclasses that haven’t even been designed yet (anyone for CricketPlayer?).

“What is_______________________?”

“What is ENCAPSULATION?”

We’ve talked a fair bit about encapsulation already, in terms of preventing duplicate code. But there’s more to encapsulation than just avoiding lots of copy-and-paste. Encapsulation also helps you protect your classes from unnecessary changes.

Anytime you have behavior in an application that you think is likely to change, you want to move that behavior away from parts of your application that probably won’t change very frequently. In other words, you should always try to encapsulate what varies.

It looks like Painter has two methods that are pretty stable, but that paint() method is going to vary a lot in its implementation. So let’s encapsulate what varies, and move the implementation of how a painter paints out of the Painter class.

“What is_______________________?”

“What is CHANGE?”

You already know that the one constant in software is CHANGE. Software that isn’t well-designed falls apart at the first sign of change, but great software can change easily.

The easiest way to make your software resilient to change is to make sure each class has only one reason to change. In other words, you’re minimizing the chances that a class is going to have to change by reducing the number of things in that class that can cause it to change.

When you see a class that has more than one reason to change, it is probably trying to do too many things. See if you can break up the functionality into multiple classes, where each individual class does only one thing—and therefore has only one reason to change.

Final Catastrophe!

Final Catastrophe! Answers

There are no Dumb Answers

A: You’ve seen several times already that when you see a potential for duplicate code, you should look to encapsulate. In this case, it’s reasonable to assume that serving a Sundae probably isn’t that different from serving a Cone.

So you could create a new class, called DessertService, and put the serve() method in that class. Then, all of your Dessert, IceCream, and Topping classes could simply refer to DessertService.serve(). If serve() changes, you’ve got to update code in only one place: DessertService.

So you’re encapsulating what might vary—the code in the serve() method—and you’re making sure that each class has only a single reason to change. That’s a double win!

Q: How did you know to encapsulate the serve() methods out of all those different classes? I missed that.

You’re ready to tackle Rick’s inflexible code now

With a few new OO tools and techniques under your belt, you’re definitely ready to go back to Rick’s software, and make it a lot more flexible. By the time you’re done, you’ll have used everything you’ve just learned on OO Catastrophe, and made it easy to change Rick’s application, too.

Note

OO Principles

Encapsulate what varies.

Code to an interface rather than to an implementation.

Each class in your application should have only one reason to change.

These three principles are HUGE! Take note of them, as we’ll be using them a lot in the upcoming chapters.

(part 2) good design = flexible software: Give Your Software a 30-minute Workout

Ever wished you were just a bit more flexible? When you run into problems making changes to your application, it probably means that your software needs to be more flexible and resilient. To help stretch your application out, you’re going to do some analysis, a whole lot of design, and learn how OO principles can really loosen up your application. And for the grand finale, you’ll see how higher cohesion can really help your coupling. Sound interesting? Turn the page, and let’s get back to fixing that inflexible application.

Back to Rick’s search tool

Loaded up with some new OO principles, we’re ready to tackle making Rick’s application well-designed and flexible. Here’s where we left off, and some of the problems we’ve discovered:

Frank: Yeah, it’s a pain, but I don’t see any way to get around it. We have to let Rick’s clients search for each different type of instrument somehow.

Jim: I still don’t see why we can’t have just one search() method that takes in an InstrumentSpec. Wouldn’t that cut down on all those different versions of search()?

Joe: Well, it would, but we still don’t have any way to return multiple types of instruments. If the client provides a GuitarSpec, it’s never going to match a BanjoSpec or MandolinSpec. So the list returned from search() will always have only the type of instrument that the client’s spec is for.

Jim: Because we can’t instantiate InstrumentSpec, right? It’s an abstract class, so we have to create a MandolinSpec, or a BanjoSpec, or whatever.

Frank: So maybe that’s the problem... besides, shouldn’t we be coding to an interface like InstrumentSpec, not an implementation like GuitarSpec or BanjoSpec?

Joe: Hmmm. I hadn’t thought about that, but you’re right; we really should be focusing on the interface, and not all those implementation classes.

A closer look at the search() method

It seems pretty clear that there’s a problem with the way we’re handling searches for Rick’s clients. We could make InstrumentSpec a concrete class, but would that solve all our problems?

The benefits of our analysis

Let’s take what we’ve figured out about turning InstrumentSpec into a concrete class, and see if it makes the design of Inventory any better.

Sharpen your pencil

One of these things is not like the other... or is it?

The search() method isn’t the only thing that makes adding new instruments to Rick’s application difficult. You also have to add a new subclass of Instrument for each new instrument type. But why? Let’s do a little more analysis.

Why is there a need for an Instrument class in Rick’s application?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

What things are common to all instruments?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

What things are different between instruments?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

If you have any ideas for how you might change Rick’s application so that you don’t need all the instrument-specific subclasses, mark those changes on the class diagram below. Feel free to add or remove classes and properties; it’s up to you to decide how you can improve Rick’s design.

Sharpen your pencil answers

One of these things is not like the other... or is it?

The search() method isn’t the only thing that makes adding new instruments to Rick’s application difficult. You also have to add a new subclass of Instrument for each new instrument type. But why? Let’s do a little more analysis.

If you have any ideas for how you might change Rick’s application so that you don’t need all the instrument-specific subclasses, mark those changes on the class diagram below. Feel free to add or remove classes and properties; it’s up to you how you can improve Rick’s design.

A closer look at the instrument classes

Even though search() is looking better, there are still some real problems with all the instrument subclasses, and the addInstrument() method in Inventory.

Remember, we originally made Instrument abstract because each instrument type was represented by its own subclass:

But classes are really about behavior!

But the reason you usually create a subclass is because the behavior of the subclass is different than the superclass. In Rick’s application, is the behavior of a Guitar different than that of an Instrument? Does it function differently in his application than a Mandolin or Banjo?

All the instruments—at least from Rick’s perspective—behave the same. So that leaves only two reasons to have subclasses for each instrument type:

Note

If we were writing a system that represented how these instruments played, we might need subclasses to handle behavior like pluck(), strum(), or frail().

Because the Instrument class represents a concept, and not an actual object, it really should be abstract. So we have to have subclasses for each instrument type.

Note

This is a good OO principle, but it sure is causing headaches with all the subclasses. We’ll come back to this one in a moment.

Each different type of instrument has different properties, and uses a different subclass of InstrumentSpec, so we need an instrument-specific constructor for each type of instrument.

Note

This looks like another case where we’re coding to an implementation instead of an interface. So this isn’t a good reason to keep Instrument abstract.

These seem like pretty good reasons (well, at least the first one does), but we’re ending up with lots of extra classes that don’t do much... and that makes our software inflexible and difficult to change. So what do we do?

Remember the second step in writing great software, from back in Chapter 1:

Note

Since Rick’s app already does what it needs to do (Step 1), we’re ready to try and make his software more flexible.

Apply basic OO principles to add flexibility.

Note

How can we take this step and apply it to the problems we’re finding in Rick’s app?

Sharpen your pencil

Object-Oriented Principles to the rescue!

There’s definitely a problem with Rick’s app, but we’re not sure what it is. When you don’t know what to do to solve a design problem, just run through the OO principles you know, and see if any of them might help improve your software’s design.

For each principle, check the box if you think it could help us out. Then, if you checked the box for a principle, it’s up to you to write down how you could use that principle to improve Rick’s search tool design.

Inheritance

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Polymorphism

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Abstraction

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Encapsulation

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

See what we thought on the next page.

Sharpen your pencil answers

Object-Oriented Principles to the rescue!

There’s definitely a problem with Rick’s app, but we’re not sure what it is. When you don’t know what to do to solve a design problem, just run through the OO principles you know, and see if any of them might help improve your software’s design.

Inheritance

We’re using inheritance already with the Instrument and InstrumentSpec classes, and their subclasses. But it does seem like the instrument-specific subclasses don’t actually do anything but inherit from Instrument... they just have slightly different constructors.

Polymorphism

We use polymorphism in the search() method to treat all instruments as instances of Instrument, instead of worrying about whether they’re a Guitar or a Mandolin. So searching is a lot easier... but it would be nice to be able to use this in addInstrument(), too, and cut down on some repetitive code.

Abstraction

InstrumentSpec abstracts the details about each instruments specifications away from the Instrument class itself, so that we can add new instrument properties without affecting the basic Instrument class.

Encapsulation

We’re using encapsulation a lot, but maybe we can use it even more... remember, encapsulate what varies! Since the properties in each instrument type are what varies, can we somehow encapsulate those properties away from Instrument and InstrumentSpec completely?

Joe: Yeah, you’re talking about encapsulating what varies, right?

Frank: Exactly! And we know that the properties for each instrument are what varies in the application.

Jim: I thought we’d been over this; that’s why we have all those subclasses of Instrument, like Guitar and Mandolin. So we can represent the differences between each instrument.

Frank: But that really didn’t help... and besides, the behavior of each instrument doesn’t vary, so do we really need subclasses for each one?

Joe: So you’re saying we would make Instrument a concrete class, instead of being abstract, right? And then we can get rid of all those instrument-specific subclasses.

Jim: But... I’m totally confused. What about the properties that vary across each instrument?

Frank: What about them? The Instrument class has a reference to an InstrumentSpec, and all the property differences can be handled by those classes. Look:

Death of a design (decision)

One of the hardest things you will ever do is to let go of mistakes you made in your own designs. In Rick’s search tool, it doesn’t make sense to have separate Instrument subclasses for each type of instrument. But it took us almost 30 pages (and 2 parts of Chapter 5) to figure that out. Why?

Because it seemed to make sense at the time, and it’s HARD to change something you thought was already working!

Note

Code once, look twice (or more!)

Keep looking over your designs when you run into problems. A decision you made earlier may be what’s causing you headaches now.

It’s easy to rip apart someone else’s code, but you’ve got to learn to look at your own code, and identify problems. This is also where peer review, having fellow programmers look at your code, can really be a lifesaver. Don’t worry if you have to make changes; a better-designed application will save you tons of time in the long run.

Design is iterative... and you have to be willing to change your own designs, as well as those that you inherit from other programmers.

Watch it!

Pride kills good design

Never be afraid to examine your own design decisions, and improve on them, even if it means backtracking.

Let’s turn some bad design decisions into good ones

Let’s kill all those instrument-specific subclasses:

We also probably need a new property in each instrument to let us know what type of instrument it is:

One more cubicle conversation (and some help from Jill)

Joe: But we just did that... we made Instrument concrete, and got rid of all the instrument-specific subclasses.

Jill: Actually, I think that’s really only the first step. What really varies in Rick’s software?

What varies in Rick’s app?

Frank: We’ve gone through this already: the properties for each instrument are what vary.

Jill: So can we encapsulate them somehow?

Joe: We already have: we used the InstrumentSpec class for that.

Frank: Wait a second, Joe. We used InstrumentSpec because those properties were used by both clients and instruments. So that was more about duplicate code...

Jill: Yes! That’s my point... the properties inside InstrumentSpec vary, too. So maybe we need to add another layer of encapsulation.

Joe: So since the properties of each instrument vary, we should pull those out of InstrumentSpec? It’s almost like double-encapsulation or something.

Jill: Sort of... we encapsulate the specifications common across client requests and instruments from the Instrument class, and then we encapsulate the properties that vary from the InstrumentSpec class.

“Double encapsulation” in Rick’s software

Note

This really isn’t an OOA&D term, so don’t be surprised if your professor looks at you funny if you use it in class.

Let’s look at the layer of encapsulation we already have, and then see how we can add a little more encapsulation to get those properties that vary out of the InstrumentSpec class.

Since some of these properties vary, we want to move them out of the InstrumentSpec class. We need a way to refer to properties and their values, but not have those properties hardcoded into the InstrumentSpec class. Any ideas for how we could do that?

What type(s) do you think you could use to represent properties and access their values, but not have to change your InstrumentSpec class to support new properties?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

By encapsulating what varies, you make your application more flexible, and easier to change.

Getting dynamic with instrument properties

What did you come up with on the last page to store properties? We decided that using a Map would be a great way to handle various types of properties, and still be able to easily add new properties at any time:

What we did: a closer look

Anytime you see something that varies, you should look for a way to encapsulate. In the case of InstrumentSpec, we realized that the properties of an instrument vary.

When you have a set of properties that vary across your objects, use a collection, like a Map, to store those properties dynamically.

You’ll remove lots of methods from your classes, and avoid having to change your code when new properties are added to your app.

Using the new Instrument and InstrumentSpec classes

Let’s take one last look at how our new Instrument and InstrumentSpec classes work in practice. Here’s where we are with the design right now:

If you were accessing a guitar, and wanted to know who built it, here’s how you could do that:

Code Magnets

Using a Map for storing properties seems like a good idea, but let’s see how things look once we actually code up a new version of InstrumentSpec. Your job is to finish off the code below using the magnets at the bottom of the page.

import java.util.________;
import java.util.________;
import java.util.________;

public class InstrumentSpec {

  private ______ properties;

  public InstrumentSpec(______ ___________) {
    if (properties == ______) {
      this.properties = new _________();
    } else {
      this.properties = new _________(___________);
    }
  }

  public ________ getProperty(String ____________) {
    return properties.get(___________);
  }

  public ______ getProperties() {
    return ______________;
  }

  public boolean matches(______________ otherSpec) {
    for (__________ i = otherSpec._____________().keySet().___________();
         i._________(); ) {
      String _____________ = (String)i.______();
      if (!properties.get(_____________).equals(
           otherSpec.getProperty(____________))) {
        return _________;
      }
    }
    return _________;
  }
}

Code Magnets Solutions

Using a Map for storing properties seems like a good idea, but let’s see how things look once we actually code up a new version of InstrumentSpec. Your job was to finish off the code below:

There are no Dumb Questions

Q:

Q: So now both Instrument and InstrumentSpec are concrete classes?

A:

A: Right. Instrument isn’t just a concept anymore; it represents actual instruments in Rick’s inventory. And InstrumentSpec is what clients use to pass in their specs when they’re searching, and what Instrument uses to store properties for an instrument.

Q:

Q: So I can get rid of my Guitar and Mandolin subclasses?

A:

A: Yup. As well as Banjo, Dobro, and any other instrument-specific subclasses of Instrument you may have created.

Q:

Q: And that’s because we use the Instrument class directly now, right?

A:

A: You got it! Remember, you typically subclass because behavior changes. In the Instrument subclasses, no behavior was changing; in fact, all we did for each instrument subclass was create a new constructor. That added a ton of classes, reduced the flexibility of our app, and really didn’t give us any helpful functionality.

Q:

Q: I understood getting rid of Guitar and Mandolin, but I’m confused about why we don’t need the different subclasses of InstrumentSpec anymore.

A:

A: It’s OK; that’s one of the trickiest parts of the design of Rick’s application. Remember, one of the key principles in any OO design is to encapsulate what varies. In Rick’s app, the properties of each instrument varied. So we pulled those properties out of InstrumentSpec, and put them into a Map. Now, when you add another instrument with a new property, you can just add the new property as a name/value pair in the properties Map.

Q:

Q: And with less classes to deal with, our software is more flexible?

A:

A: In this case, that’s true. There are certainly times where adding classes will make your design more flexible, though. Remember, adding an InstrumentSpec class helped separate instruments from their properties, and that was good; but in this chapter, we’ve been removing classes, and that’s made it easier to add new instruments to Rick’s software.

Q:

Q: I never would have figured out that we didn’t need subclasses for instruments or their specs. How am I supposed to ever get good at this?

A:

A: The best way to get good at software design is to write software! In Rick’s application, we had to go down some wrong paths—like adding Guitar and Mandolin classes—to figure out what the right thing to do was.

Most good designs come about through bad designs; almost nobody gets it all right the first time. So just do what makes sense, and then start applying your OO principles and patterns to see if you can make improvements to what you’ve got.

Most good designs come from analysis of bad designs.

Never be afraid to make mistakes and then change things around.

Finishing up Rick’s app: the InstrumentType enum

We’ve almost got ourselves a great piece of software. Let’s follow through on our new design ideas, starting with a new enumerated type for each instrument type:

Let’s update Inventory, too

With the changes to Instrument and InstrumentSpec, our Inventory class starts to get much simpler:

Sharpen your pencil

Let’s see what we’ve really done.

We’ve made a ton of changes to Rick’s software, all in the name of “more flexibility.” Let’s see how things look now. Flip back to the class diagram of Rick’s app in Back to Rick’s search tool, and recall what things looked like when we started. Then, below, draw a class diagram for how Rick’s application looks now.

Answers on the next page!

Behold: Rick’s flexible application

We’ve made a ton of changes to Rick’s application... and it’s easy to forget what we’ve been working towards. Look at the class diagram below, though, and see how much simpler Rick’s application is now:

But does the application actually work?

Rick’s software looks a lot better than it did way back at the beginning of this chapter—and it sure looks better than when we added all those subclasses for banjos and mandolins. But we’ve still got to make sure his search tool actually works! So let’s update our test class, and check out how searches work with the new version of Rick’s software:

Inventory Roundup

To see if the new version of Rick’s software works, we need to run a search on more than just guitars. Your job is to write code for the initializeInventory() method in FindInstrument.java, and add several guitars, mandolins, and banjos to Rick’s inventory. Below, we’ve listed the instruments Rick currently has, and even written code to add the first guitar to help you get started.

Answers in Inventory Roundup Solutions

Test driving Rick’s well-designed software

Be sure you’ve added all the instruments shown on the last page to your initializeInventory() method in FindInstrument.java, and then compile all your classes. Now you’re ready to take Rick’s software for a test drive...

...well, almost. First, you need to figure out what a search based on the current version of FindInstrument should return. Here’s the set of preferences that Rick’s current client has supplied:

Based on those specs, look over the instruments shown on the last page, and write in which guitars, mandolins, and banjos you think Rick’s search tool should return:

Inventory Roundup Solutions

To see if the new version of Rick’s software works, we need to run a search on more than just guitars. Your job was to write code for the initializeInventory() method in FindInstrument.java, and add several guitars, mandolins, and banjos to Rick’s inventory.

Rick’s got working software, his client has three choices

There are no Dumb Questions

Q:

Q: My output isn’t the same as yours. What did I do wrong?

A:

A: If your version of Rick’s tool returned different guitars, or output the same guitars but with different properties, then you should be sure you have the same instruments in your inventory as we do. Check the exercise in Inventory Roundup, and the answers in Test driving Rick’s well-designed software, and make sure the instruments you have in Rick’s inventory match ours.

Q:

Q: Is this really a good test since we only have one banjo and one mandolin?

A:

A: That’s a great question, and you’re right, it would be better to have a few more mandolins and banjos to really make sure Rick’s search tool picks only matching mandolins and banjos. Go ahead and add a few non-matching banjos or mandolins, and try testing out Rick’s search tool with the additional instruments.

How easy is it to change Rick’s software?

Is Rick’s software really well-designed?

And what the heck does cohesive mean?

The Great Ease-of-Change Challenge

How easy is it to change Rick’s search tool?

Let’s add support for dobros and fiddles back into Rick’s application. We tried to do that earlier, back in the first part of Chapter 5, and it turned into a total mess. Things should be much easier this time, right? Below is the class diagram for the current version of Rick’s software.

Let’s apply the ease-of-change test to our software:

How many classes did you have to add to support Rick’s new instrument types?

_____________________________________________________________________

_____________________________________________________________________

How many classes did you have to change to support Rick’s new instrument types?

_____________________________________________________________________

_____________________________________________________________________

Suppose that Rick decided that he wanted to start keeping up with what year an instrument was made in. How many classes would you need to change to support keeping up with this new information?

_____________________________________________________________________

_____________________________________________________________________

Rick also wants to add a new property, neckWood, that tracks what wood is used in the neck of an instrument. How many classes would you need to change to support this property?

_____________________________________________________________________

_____________________________________________________________________

Answers in The Great Ease-of-Change Challenge

The Great Ease-of-Change Challenge

How easy is it to change Rick’s search tool?

Let’s add support for dobros and fiddles back into Rick’s application. We tried to do that earlier, and it turned into a total mess. Things should be much easier this time, right?

Let’s apply the ease-of-change test to our software:

How many classes did you have to add to support Rick’s new instrument types?

None! We got rid of all the instrument-specific subclasses of Instrument and InstrumentSpec.

How many classes did you have to change to support Rick’s new instrument types?

One: we need to add any new instrument types to the InstrumentType enumerated type.

Suppose that Rick decided that he wanted to start keeping up with what year an instrument was made in. How many classes would you need to change to support keeping up with this new information?

None! You can just store the year that an instrument was made in the properties Map in InstrumentSpec.

Rick also wants to add a new property, neckWood, that tracks what wood is used in the neck of an instrument. How many classes would you need to change to support this property?

One in the worst case, and maybe none! neckWood is just another property we can store in the InstrumentSpec map... but we might need to add new wood enumerated values to the Wood enum.

Sweet! Our software is easy to change... but what about that “cohesive” thing?

The Scholar’s Corner

Cohesion. Cohesion measures the degree of connectivity among the elements of a single module, class, or object. The higher the cohesion of your software is, the more well-defined and related the responsibilities of each individual class in your application. Each class has a very specific set of closely related actions it performs.

Cohesion, and one reason for a class to change

You may not realize it, but we’ve already talked about cohesion in this book. Remember this?

Cohesion is really just a measure of how closely related the functionality of the classes in an application are. If one class is made up of functionality that’s all related, then it has only one reason to change... which is what we already talked about in OO CATASTROPHE!

Here are the classes we talked about when we made sure each class had only a single reason to change:

There are no Dumb Questions

Q:

Q: So cohesion is just a fancy word for how easy it is to change my application?

A:

A: Not exactly. Cohesion focuses on how you’ve constructed each individual class, object, and package of your software. If each class does just a few things that are all grouped together, then it’s probably a highly cohesive piece of software. But if you have one class doing all sorts of things that aren’t that closely related, you’ve probably got low cohesion.

Q:

Q: So highly cohesive software is loosely coupled, right?

A:

A: Exactly! In almost every situation, the more cohesive your software is, the looser the coupling between classes. In Rick’s application, the Inventory class really worries just about managing inventory—and not about how instruments are compared or what properties are stored in an instrument spec. That means that Inventory is a highly cohesive class. That also means it’s loosely coupled with the rest of the application—changes to Instrument, for example, don’t have a lot of effect on the Inventory class.

Q:

Q: But all that means the software will be easier to change, doesn’t it?

A:

A: Most of the time, yes. But remember the version of Rick’s application that we started with in this chapter? It only supported guitars, and we didn’t even have Instrument or InstrumentSpec classes. That was pretty cohesive software—Guitar was very loosely coupled with Inventory. However, it took a lot of work and redesign to support mandolins.

When you fundamentally change what an application does—like going from selling only one type of instrument to multiple types—you may have to make lots of changes to a design that’s already cohesive and loosely coupled. So cohesion isn’t always a test of how easy it is to change software; but in cases where you’re not dramatically changing how software works, highly cohesive software is usually easy to change.

Q:

Q: And high cohesion is better than low cohesion?

A:

A: Right. Good OO design is when each class and module in your software does one basic thing, and that one thing really well. As soon as one class starts doing two or three different things, you’re probably moving away from cohesion, and good OO design.

Q:

Q: Wouldn’t software that’s cohesive be easier to reuse, as well as change?

A:

A: You got it. High cohesion and loose coupling adds up to software that can easily be extended, or even broken up and reused, because all the objects in the software aren’t interdependent.

Think about it this way: the higher the cohesion in your application, the better defined each object’s job is. And the better defined an object (and its job) is, the easier it is to pull that object out of one context, and have the object do the same job in another context. The object is happy to just keep on doing its very specific job, no matter where it’s being used.

Q:

Q: And we’ve been making Rick’s application more cohesive throughout his chapter, haven’t we?

A:

A: For the most part, yes. But let’s look a little bit closer at that question...

Rick’s software, in review

So have our changes to Rick’s software resulted in high cohesion? Are our objects loosely coupled? And can we make changes easily? Let’s take a look:

Great software is usually about being good enough.

It’s hard to know when to stop designing software. Sure, you can make sure that your software does what it’s supposed to do, and then start working on increasing the flexibility and cohesion of your code. But then what?

Sometimes you just have to stop designing because you run out of time... or money... and sometimes you just have to recognize you’ve done a good enough job to move on.

If your software works, the customer is happy, and you’ve done your best to make sure things are designed well, then it just might be time to move on to the next project. Spending hours trying to write “perfect software” is a waste of time; spending lots of time writing great software and then moving on, is sure to win you more work, big promotions, and loads of cash and accolades.

Knowing when to say “It’s good enough!”

Make sure the customer is happy

Note

Before you ever leave a project, you always want to make sure your software does what it’s supposed to do.

Make sure your design is flexible

Note

Once you’ve got functionality down, move on to making good design decisions, using solid OO principles to add flexibility.

If you’ve done both of these things, it may just be time to move on... to the next project, the next application, even the next chapter!

Tools for your OOA&D Toolbox

Wow, you’ve really come a long way since we started working with Rick way back in Chapter 1. You’ve learned a ton about design, so let’s do a quick review of what you’ve added to your toolbox.

OOA&D Cross

This one is a particularly tough puzzle: almost all the answers are more than one word, and they’re spread across both parts of Chapter 5. Good luck, and keep that left brain working.

Across

Down

3. Never code to this if you can help it.

8. Great software is easy to ______________.

12. software that’s easy to change is _____________.

13. Do this to what varies.

15. Never be afraid to do this to your designs.

17. This will kill good design.

18. Classes are about this.

19. When one thing is mode up of another.

1. Always code to this if possible.

2. Most good designs come from analysis of these.

4. Abstract classes are written this way in UML class diagrams.

5. When a class inherits behavior from another class.

6. This was the type of group ensuring your software was highly cohesive.

7. Apply these to add flexibility to your software.

9. Cohesive classes do this really well.

10.Don’t be afraid to do this: It will help you find better solutions

11. We used this test to see if Rick’s application was cohesive.

14. Highly cohesive software is also almost always_____________ coupled.

16. Great software must always do what it is __________________ to do.

Exercise Solutions

Chapter 6. Solving Really Big Problems: “My Name is Art Vandelay... I am an Architect”

It’s time to build something REALLY BIG. Are you ready?

You’ve got a ton of tools in your OOA&D toolbox, but how do you use those tools when you have to build something really big? Well, you may not realize it, but you’ve got everything you need to handle big problems. We’ll learn about some new tools, like domain analysis and use case diagrams, but even these new tools are based on things you already know about—like listening to the customer and understanding what you’re going to build before you start writing code. Get ready... it’s time to start playing the architect.

You solve big problems the same way you solve small problems.

We’ve been working with fairly simple applications so far... Rick’s guitar shop had less than fifteen classes in its worst state, and Doug’s dog door never had more than five. But everything you’ve learned so far applies to working with big applications, too.

It’s all in how you look at the big problem

Think about how you work on big problems, in big software applications. You usually look at the big picture, but then start working on just one part of the application’s functionality.

The best way to look at a big problem is to see it as lots of individual pieces of functionality.

You can treat each of those pieces as an individual problem to solve, and apply the things you already know.

Once you get one part of an application working like you want it to, then you can move on to another piece of functionality within the app. At each step, though, you’re applying the same basic principles we’ve been talking about for the last 250 pages or so.

You can solve a big problem by breaking it into lots of functional pieces, and then working on each of those pieces individually.

The things you already know...

You’ve already learned a lot of things that will help you solve big software problems... you just may not have realized it. Let’s take a quick look at some of the things we already know about how to write great (big) software:

By encapsulating what varies, you make your application more flexible, and easier to change.

Note

Using encapsulation helps with big problems, too. The more you encapsulate things, the easier it will be for you to break a large app up into different pieces of functionality.

Coding to an interface, rather than to an implementation, makes your software easier to extend.

Note

This is even more important in big apps. By coding to an interface, you reduce dependencies between different parts of your application... and “loosely coupled” is always a good thing, remember?

The best way to get good requirements is to understand what a system is supposed to do.

Note

If you know what each small piece of your app’s functionality should do, then it’s easy to combine those parts into a big app that does what it’s supposed to do.

Analysis helps you ensure your system works in a real-world context.

Note

Analysis is even more important with large software... and in most cases, you start by analyzing individual pieces of functionality, and then analyzing the interaction of those pieces.

Great software is easy to change and extend, and does what the customer wants it to do.

Note

This sure doesn’t change with bigger problems. In fact, the higher the cohesion of your app, the more independent each piece of functionality is, and the easier it is to work on those pieces one at a time.

So let’s solve a BIG problem!

Enough about what you already know; let’s see how we can apply these things to a brand new, really big piece of software. Turn the page to learn a bit about Gary, his new game company, and a large software project.

Gary’s Games Vision Statement

Note

Here’s the big problem we’re going to be working on for the next few chapters.

Gary’s Games provides frameworks that game designers can use to create turn-based strategy games. Unlike arcade-style shoot-’em-up games and games that rely on audio and video features to engage the player, our games will focus on the technical details of strategy and tactics. Our framework provides the bookkeeping details to make building a particular game easy, while removing the burden of coding repetitive tasks from the game design.

The game system framework (GSF) will provide the core of all of Gary’s Games. It will be delivered as a library of classes with a well-defined API that should be usable by all board game development project teams within the company. The framework will provide standard capabilities for:

Defining and representing a board configuration

Defining troops and configuring armies or other fighting units

Moving units on the board

Determining legal moves

Conducting battles

Providing unit information

The GSF will simplify the task of developing a turn-based strategic board game so that the users of the GSF can devote their time to implementing the actual games.

Sharpen your pencil

What should we do first?

Below are several things that you might start out doing to get going on Gary’s Games. Check the boxes next to the things you think we should start with.

Talk to Gary.

Talk to people who might use the framework.

Gather requirements.

Write use cases.

Start a class diagram.

Start a package diagram.

Requirements and use cases are a good place to start...

Starting out working on a system by building a requirements list and writing use cases is a great idea. You can figure out what a system is supposed to do, and just go down your list adding functionality bit by bit... solving lots of small problems to solve one really big problem.

...but what do we really know about the system so far?

That vision statement seemed to have a lot of information about what Gary wants, but it leaves a lot open to interpretation.

What kind of board did Gary have in mind? And who’s the customer, really? Game players or game designers? And will all the games be historically based, or do we have to support things like lasers and spaceships? It sounds like there’s a lot more we need to know before we can write a very good set of requirements.

We need a lot more information

All we’ve got to go on with Gary’s system so far is a vision statement... and that didn’t tell us very much at all. So now we’ve got to figure out what the system is supposed to do. So how do we do that?

What is the system like?

Note

This is called commonality... what things are similar?

One way you can find out more about a system is to figure out what the system is like. In other words, are there some things that you do know about that the system functions or behaves like?

What is the system not like?

Note

This is called variability... what things are different?

Another great way to find out what a system should do is to figure out what it’s not like. This helps you determine what you don’t need to worry about in your system.

So let’s listen in on one of Gary’s meetings, and see what we can find out...

Customer Conversation

We need to listen in a little more on what Gary and his team are planning before we can get started on the game system framework he wants us to build.

Tom: Yeah, Gary loves text-based games. And people are getting a little tired of all the fancy graphics in games like Star Wars episode 206 (or whatever the heck they’re up to these days).

Note

Here’s some variability. The system is not a graphic-rich game.

Bethany: And we need all sorts of different time periods. We could have a Civil War version, with battles at Antietam and Vicksburg, and a World War I version over in Europe... players will love all the historical stuff, I’ll bet.

Susan: Nice idea, Beth! I’ll bet we can let game designers create add-on packs, too, so you could buy a World War II: Allies game, and then buy an add-on for other forces that the core game didn’t include.

Bob: That’s a cool marketing point, too... if our system supports different time periods, unit types, uniforms, and offensives, we’re going to be able to sell this to almost anyone developing games.

Note

Flexbililty is going to be key if we’re going to support all these variations.

Bethany: Do you think we need to worry about battles that aren’t historical? I mean, we could sell our system to the folks that make the fancy starship games, and let them create sci-fi battles, right?

Tom: Hmmm... I’ll bet Gary would go for that, if they’re still creating turn-based games. Why not clean up on that market as well as the history buffs?

Bob: Do you think we could market this as a system to create everything from online Risk to a modern-day Stratego? Those were both killer strategy board games back in the day... I’d love to sell our system to people that make those sorts of games.

Note

A little more commonality... so we’re really aiming at turn-based wargames.

Bethany: So let’s talk details. We know we’ve got to sell this to lots of game designers, so we need it to be really flexible. I’m thinking we start with a nice square board, and fill it up with square tiles.

Tom: We can let the game designers pick how many tiles on the board, right? They can choose a height and width, or something like that?

Bethany: Yeah. And then we should support all different types of terrains: mountains, rivers, plains, grass...

Susan: ...maybe space or craters or asteroid or something for the space games...

Note

OK, now we’re starting to get some ideas about actual features of the game system.

Bob: Even underwater tiles, like seaweed or silt or something, right?

Bethany: Those are great ideas! So we just need a basic tile that can be customized and extended, and a board that we can fill with all the different tiles.

Susan: Do we have to worry about all those movement rules and things that these games usually have?

Tom: I think we have to, don’t we? Don’t most of these strategy games have all sorts of complicated rules, like a unit can only move so many tiles because he’s carrying too much weight, or whatever?

Note

Strategy games again... we definitely have some commonality with that type of game to pay attention to.

Bethany: I think most of the rules depend on the specific game, though. I think we should leave that up to the game designers who use our framework. All our framework should do is keep track of whose turn it is to move, and handle basic movement stuff.

Susan: This is great. We can build a framework for challenging, fun strategy games, and make a ton of money, too.

Bob: This is starting to sound pretty cool! Let’s get this to Gary and those software guys he’s hired, so they can get started.

Figure out the features

You’ve learned a lot about what Gary and his team want the game system framework to do, so let’s take that information and figure out the features of the system.

But what is a feature, anyway?

A feature is just a high-level description of something a system needs to do. You usually get features from talking to your customers (or listening in on their conversations, like we just did on the last few pages).

A lot of times, you can take one feature, and come up with several different requirements that you can use to satisfy that feature. So figuring out a system’s features is a great way to start to get a handle on your requirements.

Note

Starting with the features of a system is really helpful in big projects-like Gary’s game system-when you don’t have tons of details, and just need to get a handle on where to start.

Get features from the customer, and then figure out the requirements you need to implement those features.

Sharpen your pencil

We need a list of features for Gary’s game system.

You’ve got plenty of information from Gary and his team, and now you know how to turn that information into a set of features. Your job is to fill in the blanks below with some of the features you think Gary’s game system framework should have.

__________________________________

__________________________________

__________________________________

__________________________________

__________________________________

__________________________________

__________________________________

__________________________________

__________________________________

__________________________________

__________________________________

__________________________________

Sharpen your pencil answers

We need a list of features for Gary’s game system.

You’ve got plenty of information from Gary and his team, and now you know how to turn that information into a set of features. Your job is to fill in the blanks below with some of the features you think Gary’s game system framework should have.

Don’t get hung up on the “difference” between a feature and a requirement.

Lots of people use “feature” to mean different things, so it’s not a term you should get too worked up about. For some people, a feature is a requirement; and you’ll even hear some people say “feature requirement,” which really can get confusing.

Others think of features as higher-level than requirement, which is how we’ve been talking about them. So it might take several requirements to satisfy one feature of a system.

The main thing is that if you’re stuck on where to get started, especially with a big project, you can gather features (or requirements!) to get a handle on the high-level things you know you’ll need to take care of in the system you’re building.

There are no Dumb Questions

Q:

Q: So there’s no difference between a feature and a requirement?

A:

A: Well, this really depends on who you ask. For some people, a feature is a “big” thing that a system does, like “support different types of terrain.” But to put that feature into place, there are lots of “small” things that the system must do, like “define a base terrain type” and “allow developers to extend the base terrain type” and “allow each tile to contain multiple terrain types.” All of these little things are considered requirements. So a single feature is satisfied by several requirements, like this:

Q:

Q: You said, “some people.” So there are other ways to look at features and requirements?

A:

A: Right. A lot of other people don’t make such a distinction between a feature and a requirement. One feature might be “supports different time periods” (which is a pretty big thing), and another might be “allow for water as a type of terrain” (which is a pretty small, specific thing). In this approach, there’s not really a big difference between what a feature is and what a requirement is. So these people see things a lot more like this:

Q:

Q: So which is right?

A:

A: Both! Or neither, if you prefer. There’s no “one right way” to think about features and requirements, especially if you don’t want to waste lots of time arguing over definitions with your programmer buddies. You’re better off thinking about both features and requirements as the things your system needs to do. If you want to consider features the “big picture” things, and requirements the “smaller, more detailed” things, that’s OK... just don’t get into any barroom fights over it, alright?

Use cases don’t always help you see the big picture.

When you start to write use cases, you’re really getting into a lot of detail about what the system should do. The problem is that can cause you to lose sight of the big picture. In Gary’s game system, we’re really not ready for a lot of detail... we’re just trying to figure out what the framework actually is at this point.

So even though you could start writing use cases, that probably won’t help you figure out exactly what you’re trying to build, from the big-picture point of view. When you’re working on a system, it’s a good idea to defer details as long as you can... you won’t get caught up in the little things when you should be working on the big things.

Always defer details as long as you can.

Brain Power

If we did write use cases for Gary’s game system, who would the actors be?

You still need to know what your system is supposed to do... but you need a BIG-PICTURE view.

Even though use cases might be a little too focused on the details for where we are in designing the system right now, you still need to have a good understanding of what your system needs to do. So you need a way to focus on the big picture, and figure out what your system should do, while still avoiding getting into too much detail.

Ever hear that a picture is worth a thousand words? Let’s see if we can show what the system is supposed to do.

Use case diagrams

Sometimes you need to know what a system does, but don’t want to get into all the detail that use cases require. When you’re in a situation like this, a use case diagram could be just what you need:

Use case diagrams are the blueprints for your system.

Remember, our focus here is on the big picture. That use case diagram may seem sort of vague, but it does help you keep your eye on the fundamental things that your system must do. Without it, you could easily get so caught up in the details of how a designer creates a new game that you completely forget that they need to actually deploy that game. With a use case diagram, you’ll never forget about the big picture.

Use your feature list to make sure your use case diagram is complete.

Once you have your features and a use case diagram, you can make sure you’re building a system that will do everything it needs to. Take your use case diagram, and make sure that all the use cases you listed will cover all the features you got from the customer. Then you’ll know that your diagram—the blueprints for your system—is complete, and you can start building the system.

Feature Magnets

It’s time to match up the game framework’s features to the use cases in your use case diagram. Place the magnet for each feature on the use case that will handle that feature. If your use case diagram is complete, then you should be able to attach each feature magnet to a use case on your diagram. Good luck!

There are no Dumb Questions

Q:

Q: So an actor is a person that uses the system?

A:

A: An actor is actually any external entity (it doesn’t have to be a person) that interacts with the system. So in a cash machine, you’d obviously have a person that uses the system as an actor, but you might also have the bank as an actor, because it deposits money in the system. If it’s not part of the system but acts on the system, it’s an actor.

Q:

Q: What’s the box around everything for? And why are the actors outside of the box?

A:

A: The box shows the boundaries of the system. So you have to code up everything inside the box, but you don’t have to worry about the stuff outside the box. The actors—the game designers using your framework—are outside of the box because they use your system; they’re not part of it.

Q:

Q: And each circle is a use case?

A:

A: Right. That’s part of why use case diagrams are great for getting a handle on the big picture: they can show you multiple use cases, and how all those use cases work together to do really big tasks. It also helps you avoid getting into details about a particular requirement too early (like now, when you should be worrying about the overall system design).

Q:

Q: I’ve seen use case diagrams with lines marked with <<include>> and <<extend>>. What’s that about?

A:

A: UML and use case diagrams do define ways to specify what kinds of relationships exist between use cases. So you could say that one use case includes another, or that one use case extends another. That’s what the <<include>> and <<extend>> keywords mean.

However, it’s easy to spend a lot of time arguing over whether a use case extends this use case, or includes that one. And suddenly, you’re spending your time on how a tile can support mountains or units need to carry a backpack, instead of focusing on the bigger picture. You can use <<include>> and <<extend>>, but it’s really not that big of a deal, and those keywords should never distract from the overall design process.

Q:

Q: So use case diagrams are more about a general picture of the system than including lots of little details?

A:

A: Now you’ve got it! If you’re worrying too much about what to call a use case, or whether you should use a particular relationship between use cases, you’ve lost sight of the big picture. Use your use case diagrams to get a clear 10,000-foot view of your system, nothing more.

Feature Magnets Solutions

Note

Well, it’s a “mostly done” solution this time.

It’s time to match up the game framework’s features to the use cases in your use case diagram. Were you able to find a use case for each feature in the game framework?

But there’s one feature still left... what up with that?

There’s probably one feature you had some trouble placing on the use case diagram. Think about this feature carefully: it’s really not something the game designer directly interacts with or worries about, because the functionality is already taken care of.

So how is this feature related to the system? And what actors are involved? And are we missing some use cases in our diagram?

What do you think?

The Little Actor

A small Socratic exercise in the style of The Little Lisper

What system are you designing?

A game framework, duh!

So what is the point of the framework?

To let game designers build games.

So the game designer is an actor on the system?

Yes. I’ve got that in my use case diagram.

And what does the game designer do with the framework?

Design games. I thought we established that!

Is the game the same as the framework?

Well, no, I suppose not.

Why not?

The game is complete, and you can actually play it. All the framework provides is a foundation for the game to be built on.

So the framework is a set of tools for the game designer?

No, it’s more than that. I mean, the feature I’m stuck on is something the framework handles for each individual game. So it’s more than just tools for the designer.

Interesting. So the framework is part of the game, then?

Well, I guess so. But it’s like a lower level, like it just provides some basic services to the game. The game sort of sits on top of the framework.

So the game actually uses the framework?

Yes, exactly.

Then the game actually uses the system you’re building?

Right, that’s just what I said. Oh, wait... then...

...if the game uses the system, what is it?

An actor! The game is an actor!

Actors are people, too (well, not always)

It turns out that in addition to the game designer, the game itself is an actor on the framework you’re building. Let’s see how we can add a new actor to our use case diagram:

Do these new use cases take care of the feature we couldn’t find a place for?

Use case diagram... check! Features covered... check!

With a new actor in place, we can finally take our use case diagrams and our features, and match them all up.

Sharpen your pencil

That last feature is still a little funny...

The second part of that last feature, about movement, fits in with the “Move Units” use case... but what about keeping up with whose turn it is to move? It seems like there’s something still missing from our use case diagram. It’s your job to figure out two things:

Who is the actor on “The framework keeps up with whose turn it is?”

_____________________________________________________________________

What use case would you add to support this partial feature?

_____________________________________________________________________

Note

* BONUS CREDIT: Make these changes to the use case diagram above.

Sharpen your pencil answers

That last feature is still a little funny...

The second part of that last feature, about movement, fits in with the “Move Units” use case... but what about keeping up with whose turn it is to move? It seems like there’s something still missing on our use case diagram. It’s your job to figure out two things:

Who is the actor on “The framework keeps up with whose turn it is?”

The game is still the actor... it’s using the framework to handle managing whose turn it is.

What use case would you add to support this partial feature?

We need a use case for “Take Turn” where the framework handles basic turn duties, and lets the custom game handle the specifics of that process.

So what exactly have we done?

You’ve got a list of features that Gary’s game system framework needs to support, and that tells you all the major pieces of the system you need to build. This is a lot like the requirements list you built way back in Chapter 2 for Todd and Gina’s dog door... except it focuses on the big picture.

Use a feature or requirement list to capture the BIG THINGS that your system needs to do.

Once you’ve got your features and requirements mapped out, you need to get a basic idea of how the system is going to be put together. Use cases are often too detailed at this stage, so a use case diagram can help you see what a system is like at 10,000 feet... kind of like a blueprint for your application.

Draw a use case diagram to show what your system IS without getting into unnecessary detail.

Gary’s Game System Framework Feature List

Note

Here’s our feature list... the system has to do these things.

1. The framework supports different types of terrain.

2. The framework supports different time periods, including fictional periods like sci-fi and fantasy.

3. The framework supports multiple types of troops or units that are game-specific.

4. The framework supports add-on modules for additional campaigns or battle scenarios.

5. The framework provides a board made up of square tiles, and each tile has a terrain type.

6. The framework keeps up with whose turn it is.

7. The framework coordinates basic movement.

Cubicle Conversation

Frank: I don’t know, Jim. I think we have been talking about code.

Jim: How do you figure that? I mean, what line of code is “framework supports different types of terrain” really going to turn into?

Frank: You’re talking about those features we figured out, right? Well, that’s not just one line of code, but it certainly is a big chunk of code, right?

Jim: Sure... but when do we get to talk about what classes we need to write, and the packages we put those classes into?

Frank: We’re getting to that, definitely. But the customer really doesn’t understand what most of that stuff means... we’d never be sure we were building the right thing if we started talking about classes and variables.

Jim: What about class diagrams? We could use those to show what we’re going to code, couldn’t we?

Frank: Well, we could... but do you think the customer would understand that much better? That’s really what domain analysis is all about. We can talk to the customer about their system, in terms that they understand. For Gary, that means talking about units, and terrain, and tiles, instead of classes, objects, and methods.

Domain analysis lets you check your designs, and still speak the customer’s language.

Let’s do a little domain analysis!

Let’s put all these things we’ve figured out about the game system together, in a way that Gary, our customer, will actually understand. This is a process called domain analysis, and just means that we’re describing a problem using terms the customer will understand.

The Scholar’s Corner

domain analysis. The process of identifying, collecting, organizing, and representing the relevant information of a domain, based upon the study of existing systems and their development histories, knowledge captured from domain experts, underlying theory, and emerging technology within a domain.

What most people give the customer...

What we’re giving the customer...

Now divide and conquer

With the customer onboard, and a nice completed set of blueprints, you’re ready to start breaking up your big problem into different pieces of functionality—and then you can use what you’ve learned already to tackle each of those pieces of functionality, one at a time.

The Big Break-Up

It’s time to break up our big problem—Gary’s game framework—into lots of smaller pieces of functionality. You’ve already seen how we can divide the game and its features into some basic groups of functionality, so you’re already well on your way.

Below are the features and diagrams we’ve been using throughout this chapter to show what Gary’s system needs to do. You need to look at these, and figure out what modules you want to use to handle all this functionality, and how you want to split the features and requirements up. Make sure your modules cover everything you think the game framework will need to do!

Our Big Break-Up

Here’s what we did to handle all the features of Gary’s system, and to break the big problem up into several smaller, more manageable pieces of functionality.

Relax

There’s no single RIGHT answer to this exercise!

It’s OK if your answers don’t match up with ours exactly. There are lots of ways to design a system, and this is just the one we chose. What you do need to worry about is that you’ve covered all the features and use cases with your design, and that it makes sense... you don’t want a module to have just one class in it, or one that will have one or two hundred.

Don’t forget who your customer really is

It might seem like Tony has a good point... until you remember who the customer for Gary’s game system framework really is. Your job is to write a framework for game designers, not to create actual games. Every game’s user interface will be different, so it’s up to the game designer to take care of graphics, not you.

Domain analysis helps you avoid building parts of a system that aren’t your job to build.

Patterns Puzzle

Take a close look at the modules and groupings in the game system framework. Do you recognize a commonly used design pattern?

What’s a design pattern? And how do I use one?

We’ve all used off-the-shelf libraries and frameworks. We take them, write some code against their APIs, compile them into our programs, and benefit from a lot of code someone else has written. Think about the Java APIs and all the functionality they give you: network, GUI, IO, etc. Libraries and frameworks go a long way towards a development model where we can just pick and choose components and plug them right in. But... they don’t help us structure our own applications in ways that are easier to understand, more maintainable and flexible. That’s where Design Patterns come in.

Design patterns don’t go directly into your code, they first go into your BRAIN. A design pattern is just a way to design the solution for a particular type of problem. Once you’ve loaded your brain with a good working knowledge of patterns, you can then start to apply them to your new designs, and rework your old code when you find it’s degrading into an inflexible mess of jungle spaghetti code.

Keep going! Design patterns are one of the last steps of design.

It’s OK if you’re not familiar with design patterns. Design patterns help you take those last steps of design—once you’ve used OO principles like encapsulation and delegation to make your software flexible, a well-chosen design pattern can add just that extra bit of flexibility to your design, and save you some time, too.

But it’s no big deal if you’re not familiar with design patterns. You can still work through this book, and get a handle on really solid design. Then, we’d recommend you pick up Head First Design Patterns, and see how other people have been handling some classic design problems, and learn from them.

Feeling a little bit lost?

We’ve done a lot of things in this chapter, and some of them don’t even seem to be related...

Gathering features

Domain analysis

Breaking Gary’s system into modules

Figuring out Gary’s system uses the MVC pattern.

But how does any of this really help us solve BIG problems?

Remember, the whole point of all this was to get a handle on how to deal with really large applications—like Gary’s game system framework—that involve a lot more than some basic design and programming.

But here’s the big secret: you’ve already done everything you need to handle Gary’s BIG problem.

The power of OOA&D (and a little common sense)

Tools for your OOA&D Toolbox

You’ve taken on a huge problem, and you’re still standing! Review some of the things you’ve learned about handling big problems, and then you’re ready for the return of the OOA&D crossword puzzle.

Bullet Points

The best way to look at a big problem is to view it as a collection of smaller problems.

Just like in small projects, start working on big projects by gathering features and requirements.

Features are usually “big” things that a system does, but also can be used interchangeably with the term “requirements.”

Commonality and variability give you points of comparison between a new system and things you already know about.

Use cases are detail-oriented; use case diagrams are focused more on the big picture.

Your use case diagram should account for all the features in your system.

Domain analysis is representing a system in language that the customer will understand.

An actor is anything that interacts with your system, but isn’t part of the system.

OOA&D Cross

It’s time for another left-brain workout. Below is a puzzle with lots of blank squares; to the right are some clues. You know what to do, so go for it!

Across

2. This helps you speak to the customer in their language (2 words)

3. You can use your feature list to make sure your use case diagram is this.

5. Use cases don’t always help you see this (2 words).

7. These aren’t always people.

8. A feature is a ____ ____ description of something a system needs to do (2 words)

10. Art Vandelay’s “real” last name.

12. A use case diagram acts as this for your system.

14. You can figure out these based on your features.

16. This is the measure of how things are similar.

Down

1. An oval in a use case diagram represents one of these.

2. We applied ones of these to your Gary’s framework.

4. The measure of how things are different.

6. You should solve a big problem by doing this to it (3 words)

9. You can figure out a system’s features by ___________ to the customer.

11. You solve big problems the ______ ______ you solve small problems (2 words).

13. Defer these as long as possible.

15. He wasn’t the customer.

Exercise Solutions

Chapter 7. Architecture: Bringing Order to Chaos

You have to start somewhere, but you better pick the right somewhere! You know how to break your application up into lots of small problems, but all that means is that you have LOTS of small problems. In this chapter, we’re going to help you figure out where to start, and make sure that you don’t waste any time working on the wrong things. It’s time to take all those little pieces laying around your workspace, and figure out how to turn them into a well-ordered, well-designed application. Along the way, you’ll learn about the all-important 3 Qs of architecture, and how Risk is a lot more than just a cool war game from the ‘80s.

Feeling a little overwhelmed?

So you’ve got lots of small pieces of functionality that you know how to take care of... but you’ve also got use case diagrams, feature lists, and a whole lot of other things to think about.

Gary’s Game System Framework Feature List

The framework supports different types of terrain.

The framework supports different time periods, including fictional periods like sci-fi and fantasy.

The framework supports multiple types of troops or units that are game-specific.

The framework supports add-on modules for additional campaigns or battle scenarios.

The framework provides a board made up of square tiles, and each tile has a terrain type.

The framework keeps up with whose turn it is.

The framework coordinates basic movement.

We have feature lists...

...high-level views of what we need to build...

...the customer’s vision...

...and even some design patterns to apply.

Brain Power

Do you think it matters what you should try to do first? If you do, why? And what would you work on first?

We need an architecture

It’s really not enough to just figure out the individual pieces of a big problem. You also need to know a little bit about how those pieces fit together, and which ones might be more important than others; that way, you’ll know what you should work on first.

The Scholar’s Corner

architecture. Architecture is the organizational structure of a system, including its decomposition into parts, their connectivity, interaction mechanisms, and the guiding principles and decisions that you use in the design of a system.

Architecture takes a big chaotic mess...

... and helps us turn it into a well-ordered application

You write great software the same way, whether you’re working on a small project, or a huge one. You can still apply the three steps we talked about way back in Chapter 1.

Let’s start with functionality

The first step is always to make sure an application does what it’s supposed to do. In small projects, we used a requirements list to write down functionality; in big projects, we’ve been using a feature list to figure those things out:

But which of these are the most important?

Even if we know to start by focusing on functionality, we still need to figure out which pieces are the most important. Those are the pieces we want to focus on first.

Sharpen your pencil

What do YOU think are the most important features?

Even though our feature list has only seven things on it, there’s a lot of work in those seven features. It’s your job to figure out which features you think are the most important, and then in what order you’d work on those things.

Note

Write down the 4 things you’d do first, in order, in these blanks.

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

The things in your application that are really important are architecturally significant, and you should focus on them FIRST.

You gotta start somewhere!

It’s awfully hard to talk about the relationships between parts of a system if you don’t have any of the parts themselves. So say you wanted to talk about how the Board module interacted with the Units module:

To figure out how these modules interact, you’d need to have at least the basics of the two modules in place first.

So architecture isn’t just about the relationships between parts of your app; it’s also about figuring out which parts are the most important, so you can start building those parts first.

The three Qs of architecture

When you’re trying to figure out if something is architecturally significant, there are three questions you can ask:

1. Is it part of the essence of the system?

Is the feature really core to what a system actually is? Think about it this way: can you imagine the system without that feature? If not, then you’ve probably found a feature that is part of the essence of a system.

2. What the fuck does it mean?

Note

Note from marketing: suggest replacing profanity with “heck.”

If you’re not sure what the description of a particular feature really means, it’s probably pretty important that you pay attention to that feature. Anytime you’re unsure about what something is, it could take lots of time, or create problems with the rest of the system. Spend time on these features early, rather than late.

3. How the “heck” do I do it?

Another place to focus your attention early on is on features that seem really hard to implement, or are totally new programming tasks for you. If you have no idea how you’re going to tackle a particular problem, you better spend some time up front looking at that feature, so it doesn’t create lots of problems down the road.

BE the Architect

To the right, you’ll find the feature list we figured out in the last chapter. Your job is to play like you’re the architect, and figure out what’s architecturally significant by using the three Qs of architecture we just talked about.

Gary’s Game System Framework Feature List

The framework supports different types of terrain.

The framework supports different time periods, including fictional periods like sci-fi and fantasy.

The framework supports multiple types of troops or units that are game-specific.

The framework supports add-on modules for additional campaigns or battle scenarios.

The framework provides a board made up of square tiles, and each tile has a terrain type.

The framework keeps up with whose turn it is.

The framework coordinates basic movement.

BE the Architect Solutions

To the right, you’ll find the feature list we figured out in the last chapter. Below are the things we thought were architecturally significant, and which of the three Qs we used to make our decisions.

Gary’s Game System Framework Feature List

The framework supports different types of terrain.

The framework supports different time periods, including fictional periods like sci-fi and fantasy.

The framework supports multiple types of troops or units that are game-specific.

The framework supports add-on modules for additional campaigns or battle scenarios.

The framework provides a board made up of square tiles, and each tile has a terrain type.

The framework keeps up with whose turn it is.

The framework coordinates basic movement.

There are no Dumb Questions

Q:

Q: I’m a little confused about what you mean by the “essence” of the system. Can you say more about that?

A:

A: The essence of a system is what it is at its most basic level. In other words, if you stripped away all the bells and whistles, all the “neat” things that marketing threw in, and all the cool ideas you had, what would the system really be about? That’s the essence of a system.

When you’re looking at a feature, ask yourself: “If this feature wasn’t implemented, would the system still really be what it’s supposed to be?” If the answer is no, you’ve found yourself an “essence feature.” In Gary’s system, we decided that the game wouldn’t really be a game without a board and some units, and there are some more examples in the Brain Power at the bottom of the page.

Q:

Q: If you don’t know what something means, isn’t that a sign that you’ve got bad requirements?

A:

A: No, but it is a sign that you might need to get some additional requirements, or at least some clarification. In the early stages, you can leave some details out to get a basic sense of a system. But at this stage, it’s time to fill in some of those details, and that’s what the second Q of architecture is all about.

Q:

Q: If I’m working on a new system, I probably won’t know how to do anything on my feature list. So won’t the 3rd Q of architecture about not knowing how to do something always apply?

A:

A: No, not at all. For instance, even if you’ve never written code to decide whether a player typed in the letter “q” or the letter “x,” you know how to write a basic if/else statement, and it’s easy to grab keyboard input from a player. So a feature like getting keyboard input isn’t something you don’t know how to do, even if you’ve never written code specifically for that task before. It’s just a few new details, really.

But if you had to write a multi-threaded chat server, and you’re new to threads and network programming, then that would be something that you don’t know how to do. Those are the things to look out for: particularly hard tasks that you’re unsure about how to handle.

Q:

Q: Doesn’t this all end up just being a judgment call, anyway?

A:

A: In a lot of cases, yes. But as long as you choose to start working on the things that seem the most important to the system, you’re going to get off to a good start.

What you don’t want to do is see some things that look familiar—perhaps you’ve solved the same problem in another project—and start there. Start with the core pieces of the system, and the things that look like they might be particularly hard, and you’ll be on the road to success.

The essence of a system is what that system is at its most basic level.

Brain Power

What do you think the essence of each of these systems is:

A weather-monitoring station?

A home automation remote control?

A beat-controlling, music-mixing DJ application?

We’ve got a lot less chaos now...

Using the three Qs of architecture, we’ve started to add some order to all that confusion we started out with:

... but there’s still plenty left to do

We’ve gotten Gary’s system down to three key features, but the big question remains: which one should you work on first?

Cubicle Argument Conversation

Jim: What in the world are you guys thinking? What good is it starting with anything that isn’t the essence of the system?

Joe: That’s ridiculous. Even if that’s the essence of the system, you’ve got to figure out what game-specific units are. That could take weeks to write if it’s harder than we think!

Frank: Maybe... but we know that coordinating movement will be tough, because we don’t have a clue how to do it! How can you possibly work on anything else when you know the movement deal is going to be difficult?

Joe: But the game-specific units might be difficult, too! We just don’t know, and that’s my point. We’ve got to figure out the parts of the system we don’t know anything about, or they could be real trouble!

Jim: You guys go on and write movement engines and deal with units. Me, I’m gonna write a board, because... well... something tells me Gary will want to see a board for his board game system. And I’m not about to leave the board for later... I’m taking it on first.

Frank: You’re both nuts. While you’re putting off the hard tasks, I’m gonna make sure the things that I don’t have any real idea about are taken care of, right away.

The reason that these features are architecturally significant is that they all introduce RISK to your project. It doesn’t matter which one you start with—as long as you are working towards reducing the RISKS in succeeding.

Take another look at our key features:

The point here is to REDUCE RISK, not to argue over which key feature you should start with first. You can start with ANY of these, as long as you’re focused on building what you’re supposed to be building.

Sharpen your pencil

Find the risk in your own project.

Think about the project you’re working on in your day job right now. Now write down the first thing you started working on when you started the project:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Now think about the 3 Qs of architecture that we talked about back in The three Qs of architecture. If you applied those to your project, write down a few features that you think would be architecturally significant:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

If you look at those features closely, you’ll probably see that they all have a lot of RISK connected to them. They’re the things that could cause you lots of problems, or delay you getting your project done. In the blanks below, write down which of those features you think you should have worked on first, and why. What risks did it create? What risks could you have reduced by working on it first?

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Architecture Puzzle

For Gary’s game system, let’s start out by working on the board module. Your job is to write a Board interface that game designers can then use and extend to build their own games.

The problem:

You need a Board base type that game designers can use to create new games. The board’s height and width are supplied by the game designers for their games. Additionally, the board can return the tile at a given position, add units to a tile, and return all the units at a given X-Y position.

Note

Here are some detailed requirements that we got from Gary and his design team.

Your task:

Create a new class called Board.java.

Add a constructor to Board that takes in a width and height, and creates a new board with that height and width. The constructor also needs to fill the board with square tiles, one at each X-Y position.

Write a method that will return the tile at a given position, given that tile’s X- and Y-position.

Write methods to add units to a tile based on that tile’s X- and Y-position.

Write a method to return all the units on a tile, given the X- and Y-position of the tile.

Answers in Architecture Puzzle Solution

Use Cases Exposed

This week’s interview: Scenarios help reduce risk

HeadFirst: Hi there, Scenario, we appreciate you taking the time to talk with us today.

Scenario: I’m really happy to be here, especially in a chapter that isn’t just about use cases.

HeadFirst: Well, yes, to tell the truth, I was rather surprised when I was told we’d be interviewing you. We’re really focusing on architecture here, and working on features that would reduce risk.

Scenario: Absolutely! Well, that sounds like a very good way to approach big problems.

HeadFirst: Yes, well... ahem... then why are you here?

Scenario: Oh! I’m sorry, I just assumed you knew. I’m here to help reduce risk, also.

HeadFirst: But I thought you were just a particular path through a use case. We haven’t even written any use cases yet!

Scenario: That’s no problem, I can still be a real help. I mean, look, let’s be honest, lots of developers just don’t ever really take the time to sit down and write out use cases. Good grief, it took you something like four pages in Chapter 6 to convince people to even use a use case diagram, and that’s much easier to draw than it is to write a use case!

HeadFirst: Well, that’s true... there is a lot of resistance to writing out use cases. But they’re really helpful, I thought they saved the day with Todd and Gina’s dog door.

Scenario: Oh, I agree! But in cases where developers just don’t have the time, or a use case is too formal for what’s needed, I can really give you a lot of the advantages of a use case, without all the paperwork.

HeadFirst: Hmmm, that is appealing. So tell me how that works.

Scenario: Well, take that board you’ve been writing. Suppose you wanted to reduce the risks of Gary seeing it, and thinking of something important you forgot to add to it...

HeadFirst: Ahh, yes, forgetting an important requirement is always a risk!

Scenario: Well, you could come up with a simple scenario for how the board would be used—that’s where I come in—and then make sure the board works with everything in your scenario.

HeadFirst: But there’s no use case... what steps do we pick in the scenario we make up?

Scenario: It doesn’t have to be that formal. You might say, “The game designer creates a new board 8 squares wide by 10 squares high,” and “Player 1 kills Player 2’s troops at (4, 5) so the board removes Player 2’s troops from that tile.”

HeadFirst: Oh, so just little descriptions of how the board is used?

Scenario: You’ve got it! Then you run through each description, and make sure your board handles those cases. It’s not quite as thorough as a use case, but I really can help you make sure you don’t forget any big requirements.

HeadFirst: This is fantastic! We’ll be right back with more from Scenario.

Scenario Scramble

Write a scenario for the Board interface you just coded.

Reducing risk is the name of the game in this chapter. You’ve coded a Board interface based on a few requirements we gave you, but it’s your job to figure out if we forgot anything—before Gary sees your work and finds a mistake.

Note

This is the risk we’re trying to reduce or eliminate using a scenario.

Your job is to take the fragments of a scenario from the bottom of this page, and put them into an order that makes sense on the bulletin board. The scenario should run through a realistic portion of a game. When you’re done, see if you left out anything on the Board interface, and if you did, add the missing functionality into your code. You may not need all the scenario fragments; good luck!

Use Cases Exposed

This week’s interview: Scenarios help reduce risk (cont.)

HeadFirst: We’re back with Scenario, again. Scenario, we’re getting quite a few calls. Would you mind taking some of our listener’s questions?

Scenario: Sure, I’d be happy to.

HeadFirst: Great. First, here’s one we’re getting a lot. This is from Impatient in Idaho: “So you’re saying I don’t need to write use cases, anymore, right? I can just use scenarios?”

Scenario: Oh, thanks, Impatient, I actually get that question often. I firmly believe you should still write use cases whenever possible. I’m helpful for quick problems, and to find the most common requirements, but remember, I’m only one path through a use case. If there are lots of alternate paths, you might miss some important requirements if you used just a scenario for your requirements.

HeadFirst: That’s right, we’ve actually had Happy Path and Alternate Path on our show before.

Scenario: Well, they’re really just specialized versions of me, if you want the truth. We try not to talk much about our family relationships, we all wanted to make it in this world on our own. But we’re really all part of the Scenario family. And you really need all of us to be sure you’ve got a system completely right. But if you’re just getting started, and a use case seems like it might be premature, just using me is a good way to get started.

HeadFirst: OK, here’s another question, from Nervous in Nebraska: “You said you would help me reduce risk, and I hate risk. Could you tell me exactly how you can help me avoid risk?”

Scenario: Another good question. Remember, when you’re figuring out requirements, whether you’re using a use case, a use case diagram, or a scenario, you’re trying to make sure you are building just what the customer wants. Without good requirements, the risk is letting down or upsetting the customer by building the wrong thing.

HeadFirst: So you’re reducing risk in the requirements phase?

Scenario: A lot of the time, yes. That’s when you’re writing use cases, putting together a requirements list, and using lots of scenarios to chart out all the paths through a use case.

HeadFirst: But you also help out in big project architecture, right? That’s why we’re interviewing you now?

Scenario: Exactly. Sometimes, you don’t have a complete requirements list and a bunch of use cases, but you still need to get some basic work done to see how a system is going to work. That’s what we’ve been doing here: using a scenario to get the basics of a module or piece of code down, so you can get the basic building blocks of your application in place.

HeadFirst: So you’re really a handy guy, aren’t you?

Scenario: I’d like to think so. I help in gathering requirements, in being sure your use cases are complete, but also in architecture, helping you reduce risk and reduce the chaos and confusion around what a particular module or piece of code does.

Scenario Scramble Solution

Write a scenario for the Board interface you just coded.

Below is the scenario we came up with. Yours might be a bit different, but you should at least have the game designer creating the board, a battle occuring between Player 1 and Player 2, and units being both added to and removed from

There are no Dumb Questions

Q:

Q: Where did those requirements for the Architecture Puzzle in Architecture Puzzle come from?

A:

A: From Gary, with some common sense added in. If you think about what Gary’s asked for, a game system framework, and then read back over the customer conversation in Chapter 6, you could probably come up with these requirements on your own. We did add a few specifics, like being able to add a unit to a specific tile, but that’s really just thinking through the problem.

Q:

Q: But why didn’t we write a use case to figure out the requirements?

A:

A: We could have. But remember, we’re not trying to complete the Board module, as much as get the basic pieces in place. That’s all we need to reduce the risk of completing this piece of Gary’s system. In fact, if we got into too much detail, we might actually add risk to the project, by working on details that really aren’t important at this stage of things.

Q:

Q: Now you’re telling me that use cases add risk? That can’t be right!

A:

A: No, use cases don’t add risk when used at the right time. Right now, we’ve come up with some key features that could cause us headaches if we don’t figure them out. But that doesn’t mean we need to perfect the Board interface; we just need to get an understanding of how it works, so if there are any potential problem spots, we can catch them and avoid problems down the line. So at this point, the details you’d need to write a good use case are a bit of overkill.

But once we’ve got the key features sketched out, and handled the major risks, we’ll go back to each module and really start to add detail in. At that point, a use case is very helpful.

Q:

Q: So that’s why we used a scenario, right? To avoid getting into lots of unnecessary detail?

A:

A: Exactly. A scenario gives us lots of the advantages of a use case, without forcing us to get into lots of detail that we don’t need to worry about right now.

Architecture Puzzle (Revisited)

What’s missing in Board.java?

Look closely at the scenario on the previous page. Did the requirements we used in Architecture Puzzle cover everything in the completed scenario? If you think something is missing, write it in the blank below, and then add code to Board.java to handle the missing functionality.

_____________________________________________________________________

_____________________________________________________________________

Architecture Puzzle Solution

For Gary’s game system, let’s start out by working on the Board module. Below is the interface we wrote to handle what we thought the basic tasks of a board would be. See how your solution compares with ours.

There are no Dumb Questions

Q:

Q: Doesn’t using an array of arrays limit you to a square board?

A:

A: No, although it does limit you to a board that uses (x, y) coordinates. For example, you can use (x, y) coordinates in a board made up of hexagon-shaped tiles, if you structure the hexagon tiles correctly. But for the most part, an array of arrays is more ideally suited to a square-tiled, rectangular board.

Q:

Q: So isn’t that limiting? Why not use a graph, or even a Coordinate class, so you’re not tied to (x, y) coordinates and a rectangular board?

A:

A: If you wanted maximum flexibility, that might be a good idea. For this situation, though, our requirements (back in Architecture Puzzle) actually specified (x, y) coordinates. So we chose a solution that wasn’t quite as flexible, but certainly was simpler. Remember, at this stage, we’re trying to reduce risk, not increase it by going with a solution that is a lot more complex than we really need.

The Tile and Unit classes

To actually make Board compile and work, we need to create a Tile and Unit class. Here’s how we wrote those classes:

Keep the right focus

You don’t need to worry about everything that Tile and Unit will eventually need to do. Your focus is on making Board and its key features work, not on completing Tile or Unit. That’s why we left Unit so bare, and added only a few methods to Tile.

Focus on one feature at a time to reduce risk in your project.

Don’t get distracted with features that won’t help reduce risk.

There are no Dumb Questions

Q:

Q: If the Tile class handles adding and removing units, and you can get the tile at a coordinate from the Board using getTile(), why add those addUnit() and removeUnit() methods to Board. Couldn’t you just call getTile(), and then use the Tile to do those things?

A:

A: You could take that approach, and let all the Unit-related operations be handled directly through the Tile object returned from getTile(). We decided to add the Unit-related methods to Board, and have Board be the entry point for game designers. In fact, you’ll see on the next page that we made Tile’s methods protected, so that only classes in the same package as Tile—like Board—could call addUnit() and removeUnit() directly. So we’ve really ensured that Board is the object used to work with tiles, units, and eventually terrain.

Q:

Q: I still think it would be easy to go ahead and add some more of the methods we know we’ll need to Unit and Tile. Why not spend a little time on those classes now?

A:

A: You’re not trying to code the entire game system framework at this point; you’re just trying to tackle a few key features, and reduce the major risks to your project. Spending time writing the Unit class, or fleshing out the Tile class, really isn’t going to help you reduce risk. Instead, do just enough to get the Board class working, because it’s the Board class that we decided was part of the essence of the system, and where we had a risk of failing if we didn’t get that piece in place.

Once you’ve handled your key features, and reduced or eliminated the big risks to your project, then you’ll have plenty of time to work on other features, like the Unit class. At this stage, though, you’re trying to avoid spending time on anything that doesn’t help you reduce the risks to your project succeeding.

Get online

You can download these Board-related classes for Gary’s framework at http://www.headfirstlabs.com. Just look for Head First OOA&D, and find “Gary’s Game System - Board classes.”

More order, less chaos

Our architecture and key feature list has helped us get the basic Board in place, and make sure we’re capturing the essence of the system for the customer. Let’s look back at our key feature list:

We’ve got structure now, too...

Even better, we’ve got some basic classes in place, and we can start to think about our next key feature, and how it fits into this structure.

Which feature should we work on next?

Build on what you’ve already got done whenever possible.

When you’ve got nothing but requirements and diagrams, you’ve just got to pick a place to start. But now that we do have some code and classes, it’s easiest to pick another key feature that relates to what we’ve already built. And remember our definition for architecture?

You really can’t talk about the relationships between parts if you don’t have two parts that have a relationship. We know Board and Unit are related, and that “game-specific units” are a key feature, so that’s the obvious thing to work on next.

Game-specific units... what does that mean?

The simplest way to understand a bit more about what “game-specific units” means is to talk to some of Gary’s customers, the game designers who will be using his framework. Let’s listen in on what they have to say:

Sharpen your pencil

What does “game-specific units” mean?

Now that you’ve heard from several of the game designers who want to use Gary’s game system framework, you should have a good idea of what our second key feature is all about. Write down in the blanks below your idea of what you need to do to support “game-specific units.”

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

When you’re done, compare your answers with ours on the next page.

Sharpen your pencil answers

Exercise Solutions

What does “game-specific units” mean?

Now that you’ve heard from several of the game designers who want to use Gary’s game system framework, you should have a good idea of what our second key feature is all about. Write down in the blanks below your idea of what you need to do to support “game-specific units.”

Each game based on the framework has different types of units, with different attributes and capabilities. So we need to be able to have properties for a unit that are different for each game, and support multiple data types for those properties.___________

Commonality revisited

We’re starting to learn more about what “game-specific units” means, but we still need to figure out how to actually add support for this feature to our game system framework. Let’s start by taking a look at the different types of units the customers mentioned, and figure out what’s common between them.

Design Puzzle

It’s your job to figure out what’s common, and should be a part of the basic Unit class, and what varies, and belongs in the game-specific subclasses of Unit. Write any properties and methods that you think belong in Unit in the class diagram for that class below, and then add properties and methods that you think belong in the game-specific subclasses to those diagrams.

Solution #1: It’s all different!

At first glance, you might have come up with a solution that looks something like this:

Commonality is about more than just the names of properties... you need to look a little bit deeper.

It might seem like there’s not anything common across all the units used in different games, but let’s take a step back from focusing on the actual names of the properties for each unit. What’s really the same for each unit?

Solution #2: It’s all the same!

At first glance, you might have come up with a solution that looks something like this:

Commonality analysis: the path to flexible software

Wondering why we spent all that time on commonality analysis? Look back at the first solution in Which feature should we work on next?, and then again at the second solution, on the left, and then fill out the table below to see what commonality has really bought us in terms of our design:

Note

This first row is what we’ve looked at so far: 3 different unit types.

Number of unit types

Number of unit classes - Solution #1

Number of unit classes - Solution #2

3

5

10

25

50

100

Note

100 may seem like a lot, but in massive war games, it’s not so far-fetched.

Which solution do you think is better? _______________________________________

Why? _______________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

We identified what was common, and put it in the Unit base class. The result was that game designers now only have to keep up with ONE unit class, instead of 25, 50, or 100!

There are no Dumb Questions

Q:

Q: I can see how this would help me with my design, but what does any of this have to do with reducing risk?

A:

A: Good design always reduces risk. By figuring out how best to design the Unit class, we can get it right the first time... before we’re deep into working on the entire game system framework, and might have to make drastic changes to Unit that affect lots of other code.

Not only have we figured out what “game-specific units” means, but we’ve defined the basic Unit class, and now other classes like Board can relate to it without worrying about its design drastically changing in the middle or near the end of the project’s development cycle.

Good design will always reduce risk.

And still more order...

We’ve figured out another key feature, reduced risk to our project even further, and only have one feature left to worry about.

We’re focusing on doing just the things that reduce risk.

Remember, the point of architecture is to reduce risk, and to create order. There are plenty of other things to work on in your application, but those are for after you’ve got a handle on how your application will be structured, and have the major risks reduced to the point where they are manageable.

We were trying to get a handle on the Unit class, and what “game-specific units” meant; at this point, we’ve done that:

There are no Dumb Questions

Q:

Q: When we worked on the Board, we did code the Board class, but now you say we shouldn’t code the Unit class. What gives?

A:

A: The question you need to be always asking at this stage of a project is, “Will this reduce the risk to my project succeeding?” If the answer is yes, you should go ahead; if it’s no, you probably can leave the task for a later stage of the project.

In the case of the Board, we needed to have a basic understanding of what the game board does, so we went ahead and coded a basic implementation. But for Unit, a class diagram and understanding its basic functionality was all we really needed to do. In both cases, we were reducing risk to our project, rather than focusing on coding or not coding a certain class or package.

Q:

Q: But couldn’t we have just done a class diagram for Board, like we did for Unit, and stopped there?

A:

A: You probably could have just done a class diagram. It’s really a judgment call, and as long as you feel you’re focusing on reducing the risk in your project, it’s OK to stop with a class diagram, or take things a level or two deeper.

Q:

Q: Is it really good to ask the customer and users of a system about what it should do? Couldn’t they lead us astray, or distract us?

A:

A: It’s usually a good idea to ask the customer, because it is their system that you’re building. And really, the customer is only going to confuse you, or get you working on the wrong thing, if you’re unsure of what you’re supposed to be working on. As long as you go into a conversation clear on what your goals are, and you’re listening for something specific, you should be able to filter out anything that might confuse or distract you.

Q:

Q: I’m still not sure I would have ever come up with using a Map for storing properties in the Unit class on my own.

A:

A: That’s OK; that’s what tools like commonality and the three Qs of architecture are for. They help you get to solutions that you might not think of on your own, in a way that works on any type of project.

In the case of the Unit class, the point isn’t that we used a Map to store properties. It’s that we figured out that all units are basically just a unit type and a set of name/value pairs. Once we figured that out, the details about how we stored those name/value pairs were a piece of cake.

Q:

Q: So there’s really not a lot of code involved in OOA&D, is there?

A:

A: OOA&D is all about code—it’s about writing great software, every time. But the way you get to good code isn’t always by sitting down and writing it right away. Sometimes the best way to write great code is to hold off on writing code as long as you can. Plan, organize, architect, understand requirements, reduce risks... all these make the job of actually writing your code very simple.

Sometimes the best way to write great code is to hold off on writing code as long as you can.

BE the Author

All that’s left is to handle coordinating game movement. But what would you do next to figure that out? Your job is to outline the next few pages of Head First OOA&D, and figure out how you’d take care of this last key feature.

*Hint: check out what we did for the last key feature that we weren’t clear on how to get started.

What does it mean? Ask the customer

Note

Want to see the answers to the BE the Author exercise? Read the next four pages and see how close your pages are to what we did.

When you’re not sure what a feature really means, one of the best things you can do is ask the customer. We did this with the game-specific units, so let’s try the same thing for figuring out what coordinating movement means.

Do you know what “coordinating movement” means?

Listening to the customers should have given you a pretty good idea of what the third key feature of Gary’s game system framework is all about. Write what you think that feature really means in the blanks below:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Now do some commonality analysis

Next you need to try and figure out what’s common about the different movement scenarios that the customers in Solution #2: It’s all the same! have been talking about. Are there some basic things that apply to all the different types of movement? If you think that there are, write those common things in the blanks below:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

So now what would you do?

If you have an understanding of what “coordinating movement” means, and you know what things are common across all games, you should have an idea about what you need to do to the game framework to make this feature work. Write your ideas down in this final set of blanks:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Is there anything common here?

Here’s what we thought we needed to do based on what Gary’s customers were saying about movement:

Units should be able to move from one tile on the board to another. Movement is based on a calculation or algorithm specific to each game, and sometimes involves the game-specific properties of a unit.

So what exactly is common among all the different possible movement scenarios? Remember what the customers said?

It’s “different for every game”

Did you see what kept showing up in our chart? Every time we found some commonality, the variability column had the same words: “different for every game.”

When you find more things that are different about a feature than things that are the same, there may not be a good, generic solution.

There are no Dumb Questions

Q:

Q: How is this really that different from game-specific units?

A:

A: With units, we did find some commonality: every unit had a type, and then name/value properties. With movement, every single game looked like it would handle things differently. So it made sense to leave movement to the game designers, rather than come up with a solution that was so generic that it was essentially useless.

Q:

Q: But there is some commonality, isn’t there? A movement algorithm, and a check to see if a move is legal, right?

A:

A: You’re right. So, in theory, you could write a Movement interface, with a method like move() that took in a MovementAlgorithm and a LegalMoveCheck, or something similar. And then each game designer could extend MovementAlgorithm and LegalMoveCheck. If you thought of something like this, nice work! You’re really ahead of the game.

But then ask yourself: what does this really gain? Game designers are going to have to learn your interfaces, and if they don’t have a legality check, they might pass in null for the LegalMoveCheck parameter, and what would the interface for MovementAlgorithm look like, and... well, you’re probably adding complexity, rather than really removing it.

Your job is to reduce risk and complexity, not increase it. We decided that it would be simpler to let game designers handle movement, and just change the position of units on the board (using methods on Board, which we did take care of for them).

Customers don’t pay you for great code, they pay you for great software.

Absolutely! Remember, great software is more than just great code.

Great code is well-designed, and generally functions like it’s supposed to. But great software not only is well-designed, it comes in on time and does what the customer really wants it to do.

That’s what architecture is about: reducing the risks of you delivering your software late, or having it not work like the customer wants it to. Our key feature list, class diagrams, and those partially done classes all help make sure we’re not just developing great code, but that we’re developing great software.

Reducing risk helps you write great software

With all three key features figured out, we’ve got a handle on the major risks to our project succeeding. Look at how each step we’ve taken in this chapter has reduced the risks to our project:

Bullet Points

Architecture helps you turn all your diagrams, plans, and feature lists into a well-ordered application.

The features in your system that are most important to the project are architecturally significant.

Focus on features that are the essence of your system, that you’re unsure about the meaning of, or unclear about how to implement first.

Everything you do in the architectural stages of a project should reduce the risks of your project failing.

If you don’t need all the detail of a use case, writing a scenario detailing how your software could be used can help you gather requirements quickly.

When you’re not sure what a feature is, you should ask the customer, and then try and generalize the answers you get into a good understanding of the feature.

Use commonality analysis to build software solutions that are flexible.

Customers are a lot more interested in software that does what they want, and comes in on time, than they are in code that you think is really cool.

OOA&D Cross

The march of the crossword continues. Have you gotten every answer so far? Here’s another set of clues to help you store all this architectural info in your brain for good.

Across

Down

6. Focus on the things in your system that are architecturally ___________ first.

9. These are the features that you should focus on first.

11. Use cases add risk when used at this time.

12. The essence of a system is what the system is at its most ________.

13. Focusing on more than one feature at a time does this to the risk in your project.

15. Use this type of analysis when you’re not sure how to implement a confusing set of features.

16. Architecture highlights these parts of your application. (2 words)

17. Commonality analysis is one path to this type of software.

1. Always start a project by focusing on this.

2. The second Q of architecture is about the ___________ of a feature.

3. The first Q of architecture is about this.

4. You focus on key features to reduce this in your project.

5. These are a way to get basic requirements without the detail of a use case.

7. This is not the same as great code.

8. You usually trade off flexibility for this in your project’s design.

10. You use architecture to turn a mess into this kind of application.

14. You write this type of software the same way, whether it’s a big system or a small one.

Sharpen your pencil answers

What’s missing in Board.java?

Look closely at the scenario on the last page. Did the requirements we used in Architecture Puzzle cover everything in the completed scenario? If you think something is missing, write it in the blank below, and then add code to Board.java to handle the missing functionality.

Note

We added a removeUnit() and removeUnits() method to Board.java to handle this requirement.

The scenario talks about removing units, but there is no requirement to remove units in Architecture Puzzle.

Chapter 8. Design Principles: Originality is Overrated

Imitation is the sincerest form of not being stupid.

There’s nothing as satisfying as coming up with a completely new and original solution to a problem that’s been troubling you for days—until you find out someone else solved the same problem, long before you did, and did an even better job than you did! In this chapter, we’re going to look at some design principles that people have come up with over the years, and how they can make you a better programmer. Lay aside your thoughts of “doing it your way”; this chapter is about doing it the smarter, faster way.

Design principle roundup

So far, we’ve really been concentrating on all the things that you do before you start coding your application. Gathering requirements, analysis, writing out feature lists, and drawing use case diagrams. Of course, at some point you actually are going to have to write some code. And that’s where design principles really come into play.

Note

A design principle is a basic tool or technique that can be applied to designing or writing code to make that code more maintainable, flexible, or extensible.

You’ve already seen a few design principles in earlier chapters:

Using proven OO design principles results in more maintainable, flexible, and extensible software.

OO Principles

Encapsulate what varies.

Code to an interface rather than to an implementation.

Each class in your application should have only one reason to change.

Classes are about behavior and functionality.

In this chapter, we’re going to look at several more key design principles, and how each one can improve the design and implementation of your code. We’ll even see that sometimes you’ll have to choose between two design principles... but we’re getting ahead of ourselves. Let’s begin by looking at the first of our design principles.

Principle #1: The Open-Closed Principle (OCP)

Our first design principle is the OCP, or the Open-Closed principle. The OCP is all about allowing change, but doing it without requiring you to modify existing code. Here’s how we usually define the OCP:

Note

Open-Closed Principle

Classes should be open for extension, and closed for modification.

Closed for modication...

Suppose you have a class with a particular behavior, and you’ve got that behavior coded up just the way you want it. Make sure that nobody can change your class’s code, and you’ve made that particular piece of behavior closed for modification. In other words, nobody can change the behavior, because you’ve locked it up in a class that you’re sure won’t change.

... but open for extension

But then suppose someone else comes along, and they just have to change that behavior. You really don’t want them messing with your perfect code, which works well in almost every situation... but you also want to make it possible for them to use your code, and extend it. So you let them subclass your class, and then they can override your method to work like they want it to. So even though they didn’t mess with your working code, you still left your class open for extension.

Remember working on Rick’s Stringed Instruments?

You probably didn’t realize it, but we were using the Open-Closed Principle when we wrote those InstrumentSpec classes for Rick’s Stringed Instruments, back in Chapter 5:

InstrumentSpec is closed for modification; the matches() method is defined in the base class and doesn’t change.

But it’s open for extension, because all of the subclasses can change the behavior of matches().

The OCP, step-by-step

Let’s take what we did back in Chapter 5, and look at in terms of the OCP, one step at a time.

We coded matches() in InstrumentSpec.java, and closed it for modification.

This version of matches() works just fine, and we don’t want anyone messing with it. In other words, once we’re done coding InstrumentSpec and this version of matches(), they shouldn’t change.

But we needed to modify matches() to work with instrument-specific spec classes.

Even though matches() works great for other InstrumentSpec objects, it doesn’t quite do what it should for guitars and mandolins. So even though matches() is closed for modification, we need a way to extend and change it... otherwise, InstrumentSpec isn’t very flexible, which is a big problem.

So we extended InstrumentSpec, and overrode matches() to change its behavior.

We don’t want to change the code in InstrumentSpec, but we can extend it, with GuitarSpec and MandolinSpec, and then override matches() in each of those classes to add instrument-specific behavior.

The OCP is about flexibility, and goes beyond just inheritance.

It’s certainly true that inheritance is a simple example of the open-closed principle, but there’s a lot more to it than just subclassing and overriding a method. Anytime you write working code, you want to do your best to make sure that code stays working... and that means not letting other people change that code.

But there are going to be times when that code still needs to be changed, maybe for just one or two particular situations. Rather than just diving into your code and making a bunch of changes, the OCP lets you extend your working code, without changing that code.

There are lots of different ways to accomplish this, and while inheritance is often the easiest to implement, it’s certainly not the only option. In fact, we’ll talk about another great way to achieve this later in the chapter, when we talk about composition.

Sharpen your pencil

Find the OCP in your own project.

Think about the project you’re currently working on. Can you find any places where you’ve used the OCP already? If so, write how you used the OCP in the blanks below:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Now think about a place in your project where you should be using the Open-Closed Principle, but you aren’t yet. Write down in the blanks below what you think you need to do to put the OCP into place in your current project:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

There are no Dumb Questions

Q:

Q: What’s the big deal about modifying code in a base class, or a class that you’ve already written?

A:

A: Once you have a class that works, and is being used, you really don’t want to make changes to it unless you have to. But remember, CHANGE is the great constant in software development. With the OCP, we allow for change through extension, rather than having to go back and modify your existing code. Subclasses can add and extend the base class’s behavior, without messing around with code that you already know is working and making the customer happy.

Q:

Q: Isn’t the OCP just another form of encapsulation?

A:

A: It’s really a combination of encapsulation and abstraction. You’re finding the behavior that stays the same, and abstracting that behavior away into a base class, and then locking that code up from modification. But then when you need new or different behavior, your subclasses handle the changes by extending the base class. That’s where encapsulation comes in: you’re encapsulating what varies (behavior in the subclasses) away from what stays the same (the common behavior in the base class).

Q:

Q: So the only way to use the OCP is by extending another class?

A:

A: No, anytime your code is closed for modification but open for extension, you’re using the OCP. So for example, if you had several private methods in a class, those are closed for modification—no other code can mess with them. But then you could add several public methods that invoked those private methods in different ways. You’re extending the behavior of the private methods, without changing them. That’s another example of the OCP in action.

Principle #2: The Don’t Repeat Yourself Principle (DRY)

Next up is the Don’t Repeat Yourself principle, or DRY for short. This is another principle that looks pretty simple, but turns out to be critical in writing code that’s easy to maintain and reuse.

Note

Don’t Repeat Yourself

Avoid duplicate code by abstracting out things that are common and placing those things in a single location.

A prime place to apply DRY...

You’ve seen the DRY principle in action, even if you didn’t realize it. We used DRY back in Chapter 2, when Todd and Gina wanted us to close the dog door automatically after it had been opened.

1. Let’s abstract out the common code

Using DRY, we first need to take the code that’s common between Remote and BarkRecognizer, and put it in a single place. We figured out back in Chapter 2 the best place for it was in the DogDoor class:

2. Now remove the code from other locations...

3. ...and reference the code from Step #1

The next two steps happen at the same time. Remove all the code that you put in a single place in Step #1, and then reference the code you abstracted out explicitly if you need to:

DRY is really about ONE requirement in ONE place

Abstracting out duplicate code is a good start to using DRY, but there’s more to it than just that. When you’re trying to avoid duplicate code, you’re really trying to make sure that you only implement each feature and requirement in your application one single time.

In the dog door we just looked at, the feature we were trying to implement was automatically closing the door.

Originally, though, we implemented that single feature in two places: Remote.java and BarkRecognizer.java.

By using DRY, we removed the duplicate code. But more importantly, we moved the implementation of this requirement, automatically closing the door, into one place, instead of two places:

There are no Dumb Questions

Q:

Q: So DRY isn’t about duplicate code, and avoiding copy-and-paste?

A:

A: DRY is about avoiding duplicate code, but it’s also about doing it in a way that won’t create more problems down the line. Rather than just tossing code that appears more than once into a single class, you need to make sure each piece of information and behavior in your system has a single, clear place where it exists. That way, your system always knows exactly where to go when it needs that information or behavior.

Q:

Q: If DRY is related to our features and requirements, then shouldn’t we apply it to gathering those features and requirements as well as writing our code?

A:

A: Absolutely, and that’s a great idea! Whether you’re writing requirements, developing use cases, or coding, you want to be sure that you don’t duplicate things in your system. A requirement should be implemented one time, use cases shouldn’t have overlap, and your code shouldn’t repeat itself. DRY is about a lot more than just code.

Q:

Q: And this is all to avoid maintenance problems later, right?

A:

A: Right. But it’s more than just avoiding a need to update code in more than one place. Remember, DRY is about having a single source for a particular piece of information or behavior. But that single source has to make sense! You wouldn’t want the bark recognizer to be the single source for closing the dog door, would you? Do you think the dog door should be asking the recognizer to close itself?

So DRY is not just removing duplication, it’s also about making good decisions about how to break up your system’s functionality.

DRY is about having each piece of information and behavior in your system in a single, sensible place.

Design Puzzle

DRY is about a lot more than just finding duplicate code in your system. It also applies to your features and requirements. It’s time to put DRY into action on your own now, and to do it in more than just code.

The problem:

Todd and Gina have come up with yet more features for their dog door. It’s your job to make sure the feature list we’ve assembled doesn’t have any duplication issues, and that each feature is handled once and only once in the system you’re designing for them.

Your task:

Read through the requirements and features list on the right. We’ve bolded the requirements and features that have been added since you last worked on the dog door.

Look through the new features and requirements, and see if you see any possible duplication in the new things you’d need to build.

Annotate the requirements and features list indicating what you think has been duplicated.

Rewrite the duplicate requirements at the bottom of the list so that there is no more duplication.

Write a new definition for the DRY principle in the space below, and make sure you talk about more than just duplicate code.

Note

Don’t Repeat Yourself

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Write your own definition for DRY that includes what you’ve learned over the last few pages.

Solutions on the next page.

Design Puzzle Solutions

DRY is about a lot more than just finding duplicate code in your system. It also applies to your features and requirements. Your job was to put DRY into action on your own, in the context of requirements rather than just code.

The problem:

Todd and Gina have come up with yet more features for their dog door. It’s your job to make sure the feature list we’ve assembled doesn’t have any duplication issues, and that each feature is handled once and only once in the system you’re designing for them.

Your task:

Read through the requirements and features list on the right. We’ve bolded the requirements and features that have been added since you last worked on the dog door.

Look through the new features and requirements, and see if you see any possible duplication in the new things you’d need to build.

Annotate the requirements and features list indicating what you think has been duplicated.

Rewrite the duplicate requirements at the bottom of the list so that there is no more duplication.

Write a new definition for the DRY principle in the space below, and make sure you talk about more than just duplicate code.

Principle #3: The Single Responsibility Principle (SRP)

The SRP is all about responsibility, and which objects in your system do what. You want each object that you design to have just one responsibility to focus on—and when something about that responsibility changes, you’ll know exactly where to look to make those changes in your code.

Note

Single Responsibility Principle

Every object in your system should have a single responsibility, and all the object’s services should be focused on carrying out that single responsibility.

You’ve implemented the Single Responsibility Principle correctly when each of your objects has only one reason to change.

There are no Dumb Questions

Q:

Q: SRP sounded a lot like DRY to me. Aren’t both about a class doing the one thing it’s supposed to do?

A:

A: They are related, and often appear together. DRY is about putting a piece of functionality in a single place, such as a class; SRP is about making sure that a class does only one thing, and that it does it well.

In good applications, one class does one thing, and does it well, and no other classes share that behavior.

Q:

Q: Isn’t having each class do only one thing kind of limiting?

A:

A: It’s not, when you realize that the one thing a class does can be a pretty big thing. For example, the Board class in Gary’s Games does a lot of different small tasks, but they’re all related to a single big thing: handling the board in a game. It does that one thing, and that’s all the Board class does, so it’s a great example of using the SRP.

Q:

Q: And using SRP will help my classes stay smaller, since they’re only doing one thing, right?

A:

A: Actually, the SRP will often make your classes bigger. Since you’re not spreading out functionality over a lot of classes—which is what many programmers not familiar with the SRP will do—you’re often putting more things into a class.

But using the SRP will usually result in less classes, and that generally makes your overall application a lot simpler to manage and maintain.

Q:

Q: This sounds a lot like cohesion, are they the same thing?

A:

A: Cohesion is actually just another name for the SRP. If you’re writing highly cohesive software, then that means that you’re correctly applying the SRP.

Spotting multiple responsibilities

Most of the time, you can spot classes that aren’t using the SRP with a simple test:

On a sheet of paper, write down a bunch of lines like this: The [blank] [blanks] itself. You should have a line like this for every method in the class you’re testing for the SRP.

In the first blank of each line, write down the class name; in the second blank, write down one of the methods in the class. Do this for each method in the class.

Read each line out loud (you may have to add a letter or word to get it to read normally). Does what you just said make any sense? Does your class really have the responsibility that the method indicates it does?

If what you’ve just said doesn’t make sense, then you’re probably violating the SRP with that method. The method might belong on a different class... think about moving it.

Sharpen your pencil

Apply the SRP to the Automobile class.

Do an SRP analysis on the Automobile class shown below. Fill out the sheet with the class name methods in Automobile, like we’ve described on the last page. Then, decide if you think it makes sense for the Automobile class to have each method, and check the right box.

Sharpen your pencil answers

Apply the SRP to the Automobile class.

Your job was to do an SRP analysis on the Automobile class shown below. You should have filled out the sheet with the class name methods in Automobile, and decided if you think it makes sense for the Automobile class to have each method.

Going from multiple responsibilities to a single responsibility

Once you’ve done an analysis, you can take all the methods that don’t make sense on a class, and move those methods to classes that do make sense for that particular responsibility.

There are no Dumb Questions

Q:

Q: How does SRP analysis work when a method takes parameters, like wash(Automobile) on the CarWash class?

A:

A: Good question! For your SRP analysis to make any sense, you need to include the parameter of the method in the method blank. So you would write “The CarWash washes [an] automobile itself.” That method makes sense (with the Automobile parameter), so it would stay on the CarWash class.

Q:

Q: But what if CarWash took in an Automobile parameter as part of its constructor, and the method was just wash()? Wouldn’t SRP analysis give you a wrong result?

A:

A: It would. If a parameter that might cause a method to make sense, like an Automobile for the wash() method on CarWash, is passed into a class’s constructor, your SRP analysis might be misleading. But that’s why you always need to apply a good amount of your own common sense and knowledge of the system in addition to what you learn from the SRP analysis.

SRP Sightings

The SRP has already made a few appearances in our work so far; now that you’re getting familiar with the SRP, it’s time for you to figure out where and how it’s been used. Your task is to look at the page below and figure out how SRP was used, and why.

How do you think the Single Responsibility Principle was used in Todd and Gina’s dog door? Write your answer in the blanks below:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Now see if you can find two more instances in the book’s examples so far where we’ve used the SRP to make our design better and more flexible. You can find the SRP in the dog door, Rick’s instrument inventory searcher, or Gary’s game framework. Write down each instance you found, and how you think the SRP is being used.

SRP Sightings Revealed!

Let’s look back on the times that SRP has already shown up in our software. Here are the SRP sightings we came up with; see if your answers are similar.

How do you think the Single Responsibility Principle was used in Todd and Gina’s dog door? Write your answer in the blanks below:

Now see if you can find two more instances in the book’s examples so far where we’ve used the SRP to make our design better and more flexible. You can find the SRP in the dog door, Rick’s instrument inventory searcher, or Gary’s game framework. Write down each instance you found, and how you think the SRP is being used.

First Instance

Example application:

Rick’s Instruments

___ Doug’s Dog Doors

_____ Gary’s Games

How SRP is being used:

Second Instance

Example application:

___Rick’s Instruments

___Doug’s Dog Doors

Gary’s Games

How SRP is being used:

When we used a Map to store properties for all types of units in the Unit class, we were using the SRP. So instead of having game-specific Units have to deal with their properties, and still have the base Unit class dealing with a different set of properties, we moved all property-related functionality into the nit class. So handling the properties feature is taken care of in ONE single place—the Unit class.

Contestant #4: The Liskov Substitution Principle (LSP)

Next up in our design principle parade is the Liskov Substitution Principle, or the LSP. It’s definition is as simple as it gets:

The LSP is all about well-designed inheritance. When you inherit from a base class, you must be able to substitute your subclass for that base class without things going terribly wrong. Otherwise, you’ve used inheritance incorrectly!

Misusing subclassing: a case study in misusing inheritance

Suppose that Gary’s Games has a new client who wants to use their game system framework to create World War II air battles. They need to take the basic Board base type, and extend it to support a 3-dimensional board to represent the sky. Here’s what they’ve done:

Make it Stick

One of these things is just like another, Use the base or its subclass, it’s not a bother, Substitute, exchange, it doesn’t rattle me, They all work the same, they use the LSP!

LSP reveals hidden problems with your inheritance structure

At first glance, it may seem like subclassing Board and using inheritance is a great idea. But look closer, there are lots of problems that this approach creates:

The 3DBoard class is not substitutable for Board, because none of the methods on Board work correctly in a 3D environment. Calling a method like getUnits(2, 5) doesn’t make sense for 3DBoard. So this design violates the LSP.

Note

Even worse, we don’t know what passing a coordinate like (2,5) even means to 3DBoard. This is not a good use of inheritance.

“Subtypes must be substitutable for their base types”

We already said that LSP states that a subtype must be substitutable for its base type. But what does that really mean? Technically, it doesn’t seem to be a problem:

But when you start to actually use that instance of 3DBoard like a Board, things can get confusing very fast:

So even though 3DBoard is a subclass of Board, it’s not substitutable for Board... the methods that 3DBoard inherited don’t have the same meaning as they do on the superclass. Even worse, it’s not clear what meaning those methods do have!

Violating the LSP makes for confusing code

It might seem like this isn’t such a big deal, but code that violates LSP can be confusing, and a real nightmare to debug. Let’s think a bit about someone who comes to use the badly designed 3DBoard for the first time.

They probably start out by checking out the class’s methods:

It’s hard to understand code that misuses inheritance.

When you use inheritance, your subclass gets all the methods from its superclass, even if you don’t want those methods. And if you’ve used inheritance badly, then you’re going to end up with a lot of methods that you don’t want, because they probably don’t make sense on your subclass.

So what can you do to avoid this? First, be sure your subclasses can substitute for their base types, which is just following the LSP. Second, learn about some alternatives to using inheritance in your code...

Solving the 3DBoard problem without using inheritance

It’s not enough to just know that inheritance isn’t the answer... now we’ve got to figure out what we should have done. Let’s look at the Board and 3DBoard classes again, and see how we can create a 3-dimensional board without using inheritance.

So what options are there besides inheritance?

Delegate functionality to another class

You’ve already seen that delegation is when one class hands off the task of doing something to another class. It’s also just one of several alternatives to inheritance.

Note

Delegation is when you hand over the responsibility for a particular task to another class or method.

Delegation was what we used to solve the 3DBoard problem we’ve been looking at, without resorting to inheritance:

When to use delegation

Delegation is best used when you want to use another class’s functionality, as is, without changing that behavior at all. In the case of 3DBoard, we wanted to use the various methods in the Board class:

Since we don’t want to change the existing behavior, but we do want to use it, we can simply create a delegation relationship between 3DBoard and Board. 3DBoard stores multiple instances of Board objects, and delegates handling each individual board-related task.

If you need to use functionality in another class, but you don’t want to change that functionality, consider using delegation instead of inheritance.

Use composition to assemble behaviors from other classes

Sometimes delegation isn’t quite what you need; in delegation, the behavior of the object you’re delegating behavior to never changes. 3DBoard always uses instances of Board, and the behavior of the Board methods always stay the same.

But in some cases, you need to have more than one single behavior to choose from. For example, suppose we wanted to develop a Weapon interface, and then create several implementations of that interface that all behave differently:

Now we need to use the behavior from these classes in our Unit class. One of the properties in our properties Map will be “weapon”, and the value for that property needs to be an implementation of the Weapon class. But a Unit might change weapons, so we don’t want to tie the weapon property to a specific implementation of Weapon; instead, we just want each Unit to be able to reference a Weapon, regardless of which implementation of Weapon we want to use.

When to use composition

When we reference a whole family of behaviors like in the Unit class, we’re using composition. The Unit’s weapons property is composed of a particular Weapon implementation’s behavior. We can show this in UML like this:

Composition is most powerful when you want to use behavior defined in an interface, and then choose from a variety of implementations of that interface, at both compile time and run time.

Note

Composition allows you to use behavior from a family of other classes, and to change that behavior at runtime.

Pizza is actually a great example of composition: it’s composed of different ingredients, but you can swap out different ingredients without affecting the overall pizza slice.

[note from marketing: how will anyone take us seriously if we compare programming principles to pizza?]

When the pizza is gone, so are the ingredients...

There’s one important point we haven’t mentioned so far about composition. When an object is composed of other objects, and the owning object is destroyed, the objects that are part of the composition go away, too. That’s a little confusing, so let’s take a closer look at what that actually means.

Here’s our Unit class again, which has a composition relationship to the Weapon interface and its implementations:

Suppose we create a new Unit, and assign its weapon property to an instance of Sword:

What happens if this Unit is destroyed? Obviously, the pirate variable is trashed, but the instance of Sword referenced by pirate is also thrown away. It doesn’t exist outside of the pirate object.

In composition, the object composed of other behaviors owns those behaviors. When the object is destroyed, so are all of its behaviors.

The behaviors in a composition do not exist outside of the composition itself.

Brain Power

Can you think of an example where the ownership aspect of composition would be a negative in your application? When might you want the composed objects to exist outside of the composing class?

Aggregation: composition, without the abrupt ending

What happens when you want all the benefits of composition—flexibility in choosing a behavior, and adhering to the LSP—but your composed objects need to exist outside of your main object? That’s where aggregation comes in.

Note

Aggregation is when one class is used as part of another class, but still exists outside of that other class.

The ice cream, bananas, and cherries exist outside of a banana split. Take away that fancy container, and you’ve still got the individual components.

You’ve already used aggregation...

We’ve been using aggregation already, in Rick’s Stringed Instruments, from Chapter 5:

Aggregation versus composition

It’s easy to get confused about when you should use composition, and when you should use aggregation. The easiest way to figure this out is to ask yourself, Does the object whose behavior I want to use exist outside of the object that uses its behavior?

If the object does make sense existing on its own, then you should use aggregation; if not, then go with composition. But be careful! Sometimes the slightest change in the usage of your objects can make all the difference.

Five-Minute Mystery

Joel leaned back in his seat, arched his back, and thought again about buying that new Aeron chair once his stock options came in. Being a game programmer was hard work, and Joel was the last coder in the office yet again.

“People are gonna go nuts over Cows Gone Wild,” he thought. He pulled up the user guide for Gary’s Game System Framework, and started to think about how he was going to implement the cowboys, one of the last features he had to deal with. Suddenly, his eyes lit upon the Unit class, and he realized that he could use Units for cowboys, and the Weapon interface for lassos, revolvers, and even branding irons.

Joel created Lasso, Revolver, and BrandingIron classes, and made sure they all implemented the Weapon interface. He even added a Weapon property to his Building class, so the cowboys could hang their gear up at the end of long days chasing the cows.

“This is so money... a little bit of composition, and I’ll bet boss-man Brad will put me as the lead designer in the game credits.” He quickly drew up a class diagram of what he had done for the morning shift, colored in his composition diamond between the Unit and Weapon classes, and headed for Taco Bell on the way back to his apartment.

Little did Joel know that when he got back into work the next day, Brad would be yelling at him, instead of congratulating him...

What did Joel do wrong?

Answer in Exercise Solutions

Inheritance is just one option

We started out this section talking about the LSP, and the basic idea that subclasses must be substitutable for their base classes. More importantly, though, now you have several ways to reuse behavior from other classes, beyond inheritance.

Let’s take a quick look back at our options for reusing behavior from other classes, without resorting to subclassing.

Delegation

Delegate behavior to another class when you don’t want to change the behavior, but it’s not your object’s responsibility to implement that behavior on its own.

Composition

You can reuse behavior from one or more classes, and in particular from a family of classes, with composition. Your object completely owns the composed objects, and they do not exist outside of their usage in your object.

If you favor delegation, composition, and aggregation over inheritance, your software will usually be more flexible, and easier to maintain, extend, and reuse.

Aggregation

When you want the benefits of composition, but you’re using behavior from an object that does exist outside of your object, use aggregation.

All three of these OO techniques allow you to reuse behavior without violating the LSP.

There are no Dumb Questions

Q:

Q: I thought subclassing was a good thing. Now you’re saying it’s a bad thing?

A:

A: No, subclassing and inheritance are key to any good OO programming language. The LSP is not about subclassing, though; it’s about when to subclass. If your subclass really is substitutable for its base type, then you’ve probably done a good job using inheritance. If your subclass is not substitutable for its base type, then you might look at other OO solutions like aggregation or delegation.

Q:

Q: But it is OK to use delegation, composition, or aggregation in a class that really shouldn’t extend another class?

A:

A: Sure. In fact, the LSP doesn’t apply at all to aggregate or delegate classes, because those are two great ways to fix an inheritance tree that doesn’t conform to the LSP. You might even say that good use of the LSP goes hand-in-hand with more delegation, composition, and aggregation.

Q:

Q: Do we really need to apply the LSP all the time to figure this out? Isn’t this just writing good OO software?

A:

A: Lots of times, you don’t need to worry about the formal name of a design principle to write good code. For example, look back at the Board example in Misusing subclassing: a case study in misusing inheritance; to make 3DBoard extend Board, all of the methods had to be changed! That should be a real tip-off that you’re got some inheritance problems.

Q:

Q: There were a lot of weird UML symbols in there. How am I supposed to remember what they all mean?

A:

A: You really don’t need to memorize these symbols at all. While UML provides specific notation for aggregation and composition, they are all just different forms of association. So just like we did with delegation, you can use a normal line with an arrow, a normal association, for composition and aggregation.

Q:

Q: But won’t that be confusing to developers if they don’t know what type of association should be used?

A:

A: That’s possible, but it also allows for a lot more flexibility. Suppose that you decide later on that when an army is destroyed, you don’t want the individual units destroyed as well. So you might change the relationship between army and unit from composition to aggregation.

If you’re using a basic association arrow, you won’t need to change your class diagram at all. It also gives the developer freedom to come up with their own ideas about how to implement the association.

There’s nothing wrong with using the aggregation and composition symbols, but you shouldn’t get too hung up on it, especially if you’re early on in the development cycle. You never know what might change later, and flexibility is always better than rigidity in your design.

Who Am I?

A bunch of classes involved in OO principles, all in full costume, are playing a party game, Who Am I? They give a clue, and you try to guess who they are, based on what they say. Assume they always tell the truth about themselves. If they happen to say something that could be true for more than one of them, choose all for whom that sentence can apply. Fill in the blanks next to the sentence with the names of one or more attendees. The first one’s on us.

Tonight’s attendees:

I’m substitutable for my base type.

___________________________________

I let someone else do things for me.

___________________________________

My behavior is used as part of another class’s behavior.

___________________________________

I change the behavior of another class.

___________________________________

I don’t change the behavior of another class.

___________________________________

I can combine the behavior of other classes together.

___________________________________

I’m not gonna go away, even if other related classes do.

___________________________________

I get my behavior and functionality from my base type.

___________________________________

Unmask the principles in Who Am I? Solutions

Bullet Points

The Open-Closed Principle keeps your software reusable, but still flexible, by keeping classes open for extension, but closed for modification.

With classes doing one single thing through the Single Responsibility Principle, it’s even easier to apply the OCP to your code.

When you’re trying to determine if a method is the responsibility of a class, ask yourself, Is it this class’s job to do this particular thing? If not, move the method to another class.

Once you have your OO code nearly complete, be sure that you Don’t Repeat Yourself. You’ll avoid duplicate code, and ensure that each behavior in your code is in a single place.

DRY applies to requirements as well as your code: you should have each feature and requirement in your software implemented in a single place.

The Liskov Substitution Principle ensures that you use inheritance correctly, by requiring that subtypes be substitutable for their base types.

When you find code that violates the LSP, consider using delegation, composition, or aggregation to use behavior from other classes without resorting to inheritance.

If you need behavior from another class but don’t need to change or modify that behavior, you can simply delegate to that class to use the desired behavior.

Composition lets you choose a behavior from a family of behaviors, often via several implementations of an interface.

When you use composition, the composing object owns the behaviors it uses, and they stop existing as soon as the composing object does.

Aggregation allows you to use behaviors from another class without limiting the lifetime to those behaviors.

Aggregated behaviors continue to exist even after the aggregating object is destroyed.

Tools for your OOA&D Toolbox

We’ve got a lot more OO principles to add to the toolbox. Let’s add what we’ve learned to our notes—and remember: these principles are best used together, not separately!

OOA&D Cross

This one is a particularly tough puzzle: almost all the answers are more than one word. Good luck, and keep that left brain working.

Across

Down

1. A variation in composition.

3. This is when one object owns behaviors from other objects.

6. This is when you hand over responsibility for a particular behavior.

7. He was all about substitution.

8. The LSP reveals problems related to this.

11. You should keep a single piece of code in this many places.

13. You should have each piece of your information and this in a single, sensible place.

14. ________ Out things that are common in your code.

15. Each object in your system should have this many responsibilities.

16. This is overrated in good OO software design.

17. Another term for SRP is this.

2. Aggregated objects exist _______ of the classes that use them.

4. Subtypes must be substitutable for these.

5. Classes should be closed for this.

9. OO principles work best when used this way.

10. A well-designed class has only one reason to do this.

12. Classes should be open for this.

Who Am I? Solutions

A bunch of classes involved in OO principles, all in full costume, are playing a party game, Who Am I? Solutions They give a clue, and you try to guess who they are, based on what they say. Assume they always tell the truth about themselves. If they happen to say something that could be true for more than one of them, choose all for whom that sentence can apply. Fill in the blanks next to the sentence with the names of one or more attendees. The first one’s on us.

Tonight’s attendees:

Exercise Solutions

Five-Minute Mystery Solved

Joel’s big mistake was revealed in this line:

He even added a Weapon property to his Building class, so the cowboys could hang their gear up at the end of long days chasing the cows.

When Joel decided that cowboys could hang up their weapons, he committed to the Lasso, Revolver, and BrandingIron classes existing outside of any individual Unit instance. No cowboy owned the gear; they just used the behavior of the gear for a time.

Since the Weapon implementations exist outside of a specific cowboy, Joel should have used aggregation instead of composition. Different cowboys could use the same Weapon implementation at different times, and those weapons should stay in existence, even if the cowboy using them was trampled by a mad cow.

Chapter 9. Iterating and Testing: The Software is Still for the Customer

It’s time to show the customer how much you really care. Nagging bosses? Worried clients? Stakeholders that keep asking, “Will it be done on time?” No amount of well-designed code will please your customers; you’ve got to show them something working. And now that you’ve got a solid OO programming toolkit, it’s time to learn how you can prove to the customer that your software works. In this chapter, we learn about two ways to dive deeper into your software’s functionality, and give the customer that warm feeling in their chest that makes them say, Yes, you’re definitely the right developer for this job!

Your toolbox is filling up

We’ve learned quite a bit so far, and our toolbox of analysis and design tools is getting pretty full. We even added some OO programming techniques in the last chapter:

But you’re still writing your software for the CUSTOMER!

All the tools and techniques you’ve been learning are terrific... but none of them matter if you don’t use them to produce great software that makes your customer happy.

And most of the time, your customer won’t care about all the OO principles and diagrams you create. They just want the software to work the way that it’s supposed to.

Joe: Yeah, maybe we shouldn’t have spent all this time on so many diagrams, and all this architecture stuff. We’ve got nothing to show Gary except a bunch of ovals with things like “Play Game” written inside them.

Frank: Come on guys, we’ve got a lot more done than that. It’s going to be simple to finish up the Board class, because we’ve already got a start on writing a lot of that functionality.

Jill: Well, sure, but that’s the only class we’ve written any code for. How are we supposed to show that to Gary?

Joe: Well, I guess we could write the Unit class pretty easily, since we did that class diagram. So it wouldn’t take a lot more time to write the code for that class.

Frank: Exactly. And, really, we know how to write all of these classes. We can just take each class, or even an entire package, and apply all those OO principles and analysis and design techniques to each chunk of functionality.

Jill: But we’ve got to work on functionality now. We don’t have time for a bunch more big-picture analysis and design.

Frank: But that’s just the thing, Jill: we don’t need to change what we’re doing, we just need to iterate deeper.

Joe: Iterate deeper? What does that mean?

Frank: It just means we keep doing analysis and design, but now on each individual part of Gary’s game system framework.

Jill: And as we build up the application, we’ll have lots of pieces working that we can show to Gary, right?

Joe: And we get to use all these tools we’ve got to make sure the software is well-designed, too, right?

Frank: Exactly. But first, we’ve got a choice to make...

You write great software iteratively.

Work on the big picture, and then iterate over pieces of the app until it’s complete.

Iterating deeper: two basic choices

When it comes to developing software, there is more than one way to iterate into specific parts of your application. You’ve got to take on smaller pieces of functionality, but there are two basic approaches to figuring out which small pieces to work on—and even what a “small piece” means in terms of your application.

You can choose to focus on specific features of the application. This approach is all about taking one piece of functionality that the customer wants, and working on that functionality until it’s complete.

Both approaches to iterating are driven by good requirements.

Feature Ahead

Feature driven development

...is when you pick a specific feature in your app, and plan, analyze, and develop that feature to completion.

Because requirements come from the customer, both approaches focus on delivering what the customer wants.

You can also choose to focus on specific flows through the application. This approach takes a complete path through the application, with a clear start and end, and implements that path in your code.

Note

Use case driven development

...is when you pick a scenario through a use case, and write code to support that complete scenario through the use case.

You’ll often see the terms “flow” and “scenario” used interchangeably.

Feature driven development

When you’re using feature driven development, you work on a single feature at a time, and then iterate, knocking off features one at a time until you’ve finished up the functionality of an application.

Use case driven development

With use case driven development, you work on completing a single scenario through a use case. Then you take another scenario and work through it, until all of the use case’s scenarios are complete. Then you iterate to the next use case, until all your use cases are working.

Two approaches to development

There’s just one basic way to write code, isn’t there? Well, there are actually a ton of different ways to go about iterating deeper and finishing up parts of your application. Most of these different approaches fall into the two basic categories we’ve been looking at, though. So how do you decide which to use?

What’s the difference between feature driven and use case driven development?

Feature driven development is more granular

Use case driven development is more “big picture”

Works well when you have a lot of different features that don’t interconnect a whole lot.

Works well when your app has lots of processes and scenarios rather than individual pieces of functionality.

Allows you to show the customer working code faster.

Allows you to show the customer bigger pieces of functionality at each stage of development.

Is very functionality-driven. You’re not going to forget about any features using feature driven development.

Is very user-centric. You’ll code for all the different ways a user can use your system with use case driven development.

Works particularly well on transactional systems, where the system is largely defined by lengthy, complicated processes.

Works particularly well on systems with lots of disconnected pieces of functionality.

Name That Approach!

Welcome to Name That Approach! Below are several statements, and each one is about a particular approach to iterating over parts of your system. Your job is to figure out which approach each statement refers to. Note that sometimes, a statement might apply to both approaches.

Use Case Driven

Feature Driven

This approach deals with really small pieces of your application at a time.

This approach lets you focus on just a part of your application at a time.

This approach is all about a complete process in your application.

Using this approach, you can always test to see if you’ve completed the part of the application you’re working on.

When you use this approach, your focus is on a diagram, not a list.

Name That Approach!: Exercise Solutions

Welcome to Name That Approach! Below are several statements, and each one is about a particular approach to iterating over parts of your system. Your job is to figure out which approach each statement refers to. Note that sometimes, a statement might apply to both approaches.

Use Case Driven

Feature Driven

This approach deals with really small pieces of your application at a time.

This approach lets you focus on just a part of your application at a time.

This approach is all about a complete process in your application.

Using this approach, you can always test to see if you’ve completed the part of the application you’re working on.

When you use this approach, your focus is on a diagram, not a list.

Let’s use feature driven development

Since Gary’s losing patience, let’s go with feature driven development. We can take just a single feature and work it through to completion, and it shouldn’t take as much time as it would to write the code to support an entire use case.

Anytime you’ve got a customer impatient to see results, you should consider feature driven development, and starting with a feature you’ve already done some work on.

Brain Power

If you decided to go with use case driven development, what would you start working on first?

Analysis of a feature

Once you’ve decided on a feature to start with, you’ve got to do some more analysis. Let’s start with what we had written down on the feature list:

3. The framework supports multiple types of troops or units that are game-specific

Note

Here’s what we’ve got so far... but this is still a pretty generic description of what we need to code.

We also have the start of a class diagram, from Chapter 7:

It looks like we’ve got everything we need to start coding, right? To help us make sure we haven’t forgotten anything, let’s go back to using some textual analysis.

We don’t have a use case to analyze, but we can revisit the vision statement for Gary’s games, and see if we’re covering everything that Gary wanted his units to do.

Gary’s Games Vision Statement

Gary’s Games provides frameworks that game designers can use to create turn-based strategy games. Unlike arcade-style shoot-’em-up games and games that rely on audio and video features to engage the player, our games will focus on the technical details of strategy and tactics. Our framework provides the bookkeeping details to make building a particular game easy, while removing the burden of coding repetitive tasks from the game design.

Note

Here’s Gary’s vision statement, from way back in Chapter 6.

The game system framework (GSF) will provide the core of all of Gary’s Games. It will be delivered as a library of classes with a well-defined API that should be usable by all board game development project teams within the company. The framework will provide standard capabilities for:

Defining and representing a board configuration

Defining units and configuring armies or other fighting units

Moving units on the board

Determining legal moves

Conducting battles

Providing unit information

The GSF will simplify the task of developing a turn-based strategic board game so that the users of the GSF can devote their time to implementing the actual games.

Compare the class diagram for Unit with this vision statement. Are there things missing from our class diagram?

What else might Gary expect to see when you say, “I’m done with writing code for the units in your framework?”

Fleshing out the Unit class

In our class diagram, all we’ve really figured out is how to represent the properties of a unit. But in Gary’s vision statement, he’s expecting his game system framework to support a lot more than just those game-specific properties.

Note

This makes sense, because the key feature we were focusing on in Chapter 7 was not the entire Unit class, but just game-specific properties of a Unit.

Here are the things we came up with that Gary is expecting units in his framework to do:

Each unit should have properties, and game designers can add new properties to unit types in their own games.

Note

Our class diagram is focused on this particular aspect of the Unit class right now.

Units have to be able to move from one tile on a board to another.

Note

You should have some ideas about how to handle this from our work on a related key feature back in Chapter 7.

Units can be grouped together into armies.

Note

These new features are all pulled straight from Gary’s vision statement.

Showing off the Unit class

We worked on supporting game-specific units, and how to store the properties of a Unit, back in Chapter 7. But Gary wants more than a class diagram before he’s convinced you’re getting any work done.

Your customers want to see something that makes sense to them

Your customers are used to seeing computer programs run on a computer. All those diagrams and lists may help you get on the same page with them in terms of requirements and what you’re supposed to build, but you’re going to need more than that before they think you’ve built anything useful.

You need to come up with some test scenarios that you can show to your customer, which will prove that your code works, and that it behaves like your customer expects it to.

Writing test scenarios

Note

Be careful... this “scenario” isn’t the same as the “scenario” we’ve been talking about in a use case scenario.

Test cases don’t have to be very complex; they just provide a way to show your customer that the functionality in your classes is working correctly.

For the properties of a unit, we can start out with a simple test scenario that creates a new Unit, and adds a property to the unit. We could just show our customer a running program that displays output like this:

BE the Customer

We’ve already got one test scenario. It’s your job to play Gary, and think of two more test scenarios that we can use to prove that the Unit class is working like it should. Write the output of each scenario in the code windows on the right.

BE the Customer Solutions

Your job was to think of two more test scenarios that we can use to prove that the Unit class is working like it should. Here are the two scenarios we came up with:

Scenario #2: Changing property values

We decided to test setting, and then changing, the value of a property. If the hitPoints property is set, for example, and then set again, getting the value of hitPoints should return the most recent value for that property:

Scenario #3: Getting non-existent property values

For our third scenario, we decided to test what would happen when you tried to retrieve the value of a property that had never been set. Error conditions like this crop up all the time, and we don’t want our program crashing every time a game designer makes a small typo or mistake in their code. Here’s what we did to test this:

You should test your software for every possible usage you can think of. Be creative!

Don’t forget to test for incorrect usage of the software, too. You’ll catch errors early, and make your customers very happy.

There are no Dumb Questions

Q:

Q: We don’t have any code written yet. Aren’t we doing things a bit backwards by worrying about tests right now?

A:

A: Not at all. In fact, if you know what tests you’re going to use before you write your code, it’s easy to figure out what code you’re going to need to pass those tests. With the three test scenarios we just developed, it should be pretty simple to write the Unit class, and the tests tell us exactly how our code should behave.

Q:

Q: Isn’t this just test driven development?

A:

A: For the most part, yes. Formally, test driven development focuses on automated tests, and usually involves a testing framework like JUnit. But the idea of writing test cases, and then writing the code that will pass the test, is the core idea behind test driven development.

Q:

Q: So are we using test driven development or feature driven development? I’m confused...

A:

A: Both. In fact, most good software analysis and design mixes lots of different approaches. You might start with a use case (use case driven development), and then choose just a small feature in that use case to start working on (which is really a form of feature driven development). Finally, you might use tests to figure out how to implement that feature (feature driven development).

Q:

Q: Why are the tests so simple? I expected something a little fancier.

A:

A: You want to keep your tests simple, and have them test just a small piece of functionality at a time. If you start testing multiple things at once, it’s hard to tell what might have caused a particular test to fail. You may need a lot more tests, but keep each one focused on a very specific piece of functionality.

Q:

Q: And each test makes sure a single method in the class works correctly, right?

A:

A: No, each test really focuses on a single piece of functionality. That might involve one method, or several methods. For example, you can’t test setting a property’s value (which uses setProperty()) without getting that property’s value as well (using getProperty()). So it’s one piece of functionality—setting a property—but it takes two methods.

Q:

Q: Can you explain why you tested getting a property that you didn’t set? Isn’t that testing the wrong way to use the Unit class?

A:

A: Testing incorrect usage of your software is usually at least as important as testing it when it’s used properly. Game designers could easily mistype a property name, or write code that expects some other piece of a game to set a property and asks for a property that doesn’t exist. It’s your job to know what will happen in these situations.

Q:

Q: Now that we’ve got our tests planned out, we can finally start coding the Unit class, right?

A:

A: Well, there’s one more bit of design we need to think about first...

Test driven development focuses on getting the behavior of your classes right.

Joe: What do you mean? We figured out that all properties in a Unit have a name and a value. So we decided to use a Map to store them all.

Frank: And game designers can add any new properties they want by just creating new property names, and sticking name/value pairs in the Map with the setProperty() method.

Jill: Right. But then, we also added a type property, since all units will have a type. And that’s something common for all units...

Joe: Sure. See, we did do the commonality analysis right.

Jill: ...but we also now know that units can be assembled into groups, like armies or fleets or whatever. So what happens if we have two units of the same type in the same group... how can we tell the difference between them?

Frank: You think we need some sort of ID, don’t you?

Jill: Yeah, maybe. Or at least a name... but even then, you can’t really prevent duplication with a name property, can you?

Joe: OK, but that still doesn’t mean we need to change our design. We can just add the ID property into our property Map. So we’ve got a nice, uniform way to access all those properties, using the getProperty() method.

Frank: He’s right, Jill. And since we encapsulate away the details about property names into the properties Map, we could even change from using an ID to a name, or something totally different, and code using the Unit class wouldn’t have to change much... you’d just need to use the new property name in getProperty(). That’s a pretty slick design!

Jill: But what about commonality? If ID is really common to all types of Unit, shouldn’t it be moved out of the Map, sort of like we did with the type property?

Joe: Whoa... encapsulation or commonality. That’s tough... it seems like we can’t do one without screwing up the other.

Sharpen your pencil

Refine your commonality analysis.

Before we close the book on dealing with Unit properties, there are a few things you still need to think through. Below are several properties that different units might have, and two sheets of paper. Write down on the Commonality sheet the properties that you think all units, regardless of their type, would have; on the Variability sheet, write down properties you think only specific types of units might have.

Potential Unit Properties

name

weapon

allegiance

gear

type

hitPoints

wingspan

lastName

strength

weight

landSpeed

id

speed

intelligence

experience

groundSpeed

stamina

firstName

weapons

hunger

Now update the Unit class diagram.

With the details from your revised commonality analysis in Sharpen your pencil, you (might) need to update the Unit class diagram, shown below. Make any changes that might improve the design of the Unit class below, and add notes to remind yourself what the purpose of any additions you’ve made are going to be used for.

Sharpen your pencil answers

Refine your commonality analysis.

In Sharpen your pencil, we showed you several properties that different units might have. Your job was to write down on the Commonality sheet the properties that you think all units, regardless of their type, would have; on the Variability sheet, you should have written down properties you think only specific types of units might have.

Relax

You may have a different idea about what makes a good game.

You might have played different games than we have, and come up with different common properties. That’s OK—just focus on how and why you made your own decisions. We’re going to use our choices in the rest of the chapter, so you should be comfortable with how we made our choices, too.

There are no Dumb Questions

Q:

Q: I didn’t have anything on the Commonality list except for “type”. Where did I go wrong?

A:

A: You didn’t go wrong at all. Analysis and design are all about making choices, and sometimes you’re going to make a different choice than another programmer. There’s nothing wrong with that, as long as you have good, well thought out reasons for the decision you made.

Q:

Q: But won’t different choices at least result in different code and design implementations?

A:

A: Yes, they sure will. But OOA&D, and software development, aren’t about making a particular decision, since many times there isn’t an exactly “right” or exactly “wrong” choice. They’re about writing well-designed software, and that can happen in a lot of different ways.

In fact, even if two programmers made the same decision about commonality and variability in this exercise, it can lead to totally different design decisions when it comes to actually writing your classes. Let’s assume for a moment that two developers both came up with the answers for commonality and variability shown here, and then tried to revise the Unit class to reflect what they figured out...

Solution #1: Emphasizing Commonality

In this solution, all game designers can directly access the id, name, and weapons properties, instead of having to use getProperty() and work through the more generic properties Map.

The emphasis is on keeping the common properties of a Unit outside of the properties Map, and leaving properties that vary inside the properties Map.

Design decisions are always a tradeoff

Sam chose to emphasize the things that are common across all types of Units. But there are some negatives to Sam’s design, too:

Note

We’re repeating ourselves

Now there are two different ways to access properties: through the getId(), getName(), and property-specific methods, and the getProperty() method. Two ways to access properties is almost certainly going to mean duplicate code somewhere.

Maintenance is a problem

Note

When you see the potential for duplicate code, you’ll almost always find maintenance and flexibility issues, as well.

Now you’ve got property names, like id and name, hard-coded into the Unit class. If a game designer doesn’t want to use those, or wants to change them, it’s going to be a real hassle, and require changes to the Unit class. This is usually where encapsulation would help, and that leads us to Randy’s design choice...

Solution #2: Emphasizing Encapsulation

This solution focuses on encapsulating all the properties for a Unit into the properties Map, and providing a standard interface—the getProperty() method—for accessing all properties. Even properties that apply to all units, like type and id, are accessed through the properties Map in this solution.

The emphasis is on encapsulation, and a flexible design. Even if the names of common properties change, the Unit class can stay the same, since no property names are hardcoded into the class itself.

Tradeoffs with this decision, too...

Randy’s solution is more resistant to changes, and uses a lot more encapsulation, but there are tradeoffs with this design, as well. Here are a few of the downsides to Randy’s design:

We’re ignoring commonality Randy encapsulated all of the properties into the properties Map, but now there’s nothing to indicate that type, name, id, and weapons are intended to be properties common to all Unit types.

Lots of work at runtime getProperty() returns an Object, and you’re going to have to cast that into the right value type for each different property, all at runtime. That’s a lot of casting, and a lot of extra work that your code has to do at runtime, even for the properties that are common to all Unit types.

Brain Power

Which developer’s solution do you think is best? Are there times where you think one solution might be the best choice, and other times where the other might work better?

Let’s go with the commonality-focused solution

For Gary’s game system framework, let’s use Sam’s solution, which pulls the common properties of a Unit out into their own properties and methods, and leaves unit-specific properties in a separate Map.

There are no Dumb Questions

Q:

Q: I thought the other design, that focused on encapsulation, was better. Is that OK?

A:

A: Absolutely. Both design choices have positives, and either one might work well. The only thing you cannot do is be unwilling to change your design—whichever one you start with—if it turns out to not work well down the line. At each stage of iterating through your app, you need to reevaluate your design decisions, and make sure they’re still solid.

Q:

Q: So how do I know when I need to change my design? My code won’t just stop working, so what should I look out for?

A:

A: Iteration is really the key point here. Lots of design decisions look great at one stage of your development, but then turn out to be a problem as you get deeper into a particular part of your app. So once you make a decision, stick with it, and iterate deeper into your application. As long as your design is working, and you’re able to use good OO principles and apply design patterns, you’re in good shape. If you start running into trouble with a decision, though, don’t ever be afraid to change designs and rework things.

Q:

Q: What happens when I can’t decide between a couple of good design choices?

A:

A: You always have to make a choice, even if you’re not 100% sure if it’s the right one. It’s always better to take your best guess, and see how things work out, rather than spend endless hours debating one choice or another. That’s called analysis paralysis, and it’s a sure way to not get anything done. It’s much better to start down one path, even if you’re not totally sure it’s the right one, and get some work done, than to not make a choice at all.

Good software is built iteratively. Analyze, design, and then iterate again, working on smaller and smaller parts of your app.

Each time you iterate, reevaluate your design decisions, and don’t be afraid to CHANGE something if it makes sense for your design.

Match your tests to your design

We’ve got test scenarios we want to show Gary, and a design for the Unit class. The last thing we need to do before coding is to make sure our design for Unit will allow us to code a solution that passes all the tests.

Let’s write the Unit class

It’s been two chapters in coming, but we’re finally ready to write the code for the Unit class. Here’s how we did it:

Test cases dissected...

We’ve talked a lot about test cases, but so far, you haven’t seen how to actually write one. Let’s examine a test case up close, and see exactly what makes up a good test.

Each test case should have an ID and a name.

Note

Try not to refer to tests as test1, test2, etc. Use descriptive names whenever possible.

The names of your test cases should describe what is being tested. Test names with nothing but a number at the end aren’t nearly as helpful as names like testProperty() or testCreation(). You should also use a numeric ID, so you can easily list your tests cases out (something we’ll do on the next page).

Each test case should have one specific thing that it tests.

Note

One piece of functionality may involve one method, two methods, or even multiple classes... but to start with, focus on very simple pieces of functionality, one at a time.

Each of your test cases should be atomic: each should test only one piece of functionality at time. This allows you to isolate exactly what piece of functionality might not be working in your application.

Each test case should have an input you supply.

Note

If you’re setting hitPoints to 15, then “15” becomes the input you supply to your test case.

You’re going to give the test case a value, or a set of values, that it uses as the test data. This data is usually then used to execute some specific piece of functionality or behavior.

Each test case should have an output that you expect.

Note

This is what you want the program to output. So if you set type to “infantry”, and then call getType(), your expected output is “infantry”.

Given your input, what should the program, class, or method output? You’ll compare the actual output of the program with your expected output, and if they match, then you’ve got a successful test, and your software works.

Most test cases have a starting state.

Note

There’s not much starting state for the Unit class. We do need to create a new Unit, but that’s about it.

Do you need to open a database connection, or create a certain object, or set some values before running your test? If so, that’s all part of the starting state of the test case, and needs to be handled before you run the actual test.

Sharpen your pencil

Design your test cases.

Below is a table with 5 columns, one for each of the 5 important parts of a test case. Your job is to fill in the table with information for the test cases we’ve laid out in this chapter already. We’ve even done the first one to help get you started, and filled in a few empty spots on the rest of the tests.

Sharpen your pencil answers

Design your test cases.

Below is a table with 5 columns, one for each of the 5 important parts of a test case. Your job was to fill in the table with information for the test cases we’ve laid out in this chapter already.

There are no Dumb Questions

Q:

Q: How did our three test scenarios turn into four test cases?

A:

A: Because the first test case really tested two things: setting and retrieving a common property, which has its own variable and access method (like getType()), and setting a retrieving a unit- or game-specific property, which is accessed through getProperty() (like hitPoints). That’s two pieces of functionality, so two different test cases are required.

Q:

Q: And all these tests will let us know that our software works like it should, right?

A:

A: It’s a good start on that, yes, but remember, we started out writing the tests so that we could prove to the customer that the software we’ve been writing actually will work. Our test cases let the customer see some code actually running, as well as help us find bugs in our code before we get too far along in our development cycle.

Test Puzzle

Now that you know what test cases are, and have several written up in table form, you’re ready to code a test class to show your customer that your software works, and prove to yourself that there aren’t any bugs in the code that you’ve written.

The problem:

Gary wants to know that you’re making progress on supporting units in his game system framework, and you want to be sure that the code you’ve written for Unit.java works properly.

Your task:

Create a new class called UnitTester.java, and import the Unit class and any related classes into it.

Add a new method for each test case you figured out from the table in Sharpen your pencil answers. Be sure to use descriptive names for the test methods.

Each test method should take in an instance of Unit with any starting state already set, and any other parameters you think you’ll need to run the test and compare an input value with an expected output value.

The test method should set the supplied property name and property value on the provided Unit, and then retrieve the expected output property value using the expected output property name.

If the provided input value and expected output value match, the method should print out “Test passed”; if they don’t match, the method should print “Test failed”, along with the mismatched values.

Write a main() method that sets up the starting state for each test, and then runs each test.

Bonus Credit:

There are several things in Unit.java that are not being tested by the scenarios in Sharpen your pencil answers. Identify what each of these are, and create a test method for each.

Run these tests from your main() method as well.

Test Puzzle Solutions

And now for some bonus credit...

We added three new test cases to our table, to handle the three properties common to all units that aren’t tested in UnitTester. You should be able to write three additional test methods based on this table. Did you figure these out on your own?

Prove yourself to the customer

With a Unit class and a set of test cases, you’re ready to show Gary some working code, and prove that you’re on the right track to building his game system framework just the way he wants it. Let’s show him the test class running:

Let’s change the programming contract for the game system

When you’re writing software, you’re also creating a contract between that software and the people that use it. The contract details how the software will work when certain actions are taken—like requesting a non-existent property on a unit.

If the customer wants an action to result in different behavior, then you’re changing the contract. So if Gary’s framework should throw an exception when a non-existent property is queried, that’s fine; it just means that the contract between game designers and the framework has changed.

When you program by contract, you and your software’s users are agreeing that your software will behave in a certain way.

Note

Want to know more about what this means? Turn the page to find out more...

We’ve been programming by contract so far

You probably didn’t notice, but we’ve been doing something called programming by contract in the Unit class so far. In the Unit class, if someone asks for a property that doesn’t exist, we’ve just returned null. We’ve been doing the same thing in getWeapons(); if the weapons list isn’t initialized, we just return null there, too:

This is the contract for Unit

The Unit class assumes that people using it are competent programmers, and that they can handle null return values. So our contract states something like this:

Programming by contract is really all about trust

When you return null, you’re trusting programmers to be able to deal with null return values. Programmers are basically saying that they’ve coded things well enough that they won’t ask for non-existent properties or weapons, so their code just doesn’t worry about getting null values back from the Unit class:

And we can always change the contract if we need to...

Back in Note, we were asked to stop returning null, and throw an exception instead. This really isn’t a big change to the contract; it just means that now game designers are going to have big problems if they ask for non-existent properties or weapons.

But if you don’t trust your users...

But what happens if you don’t think your code will be used correctly? Or if you think that certain actions are such a bad idea that you don’t want to let users deal with them in their own way? In these cases, you may want to consider defensive programming.

Suppose you were really worried that game designers using the Unit class, and asking for non-existent properties, were getting null values and not handling them properly. You might rewrite the getProperty() method like this:

I’m sure you’re great code and all, but I just don’t trust you. I could send you null, and you could totally blow up. So let’s just be safe, and I’ll send you a checked exception that you’ll have to catch, to make sure you don’t get a null value back and do something stupid with it.

-or if they don’t trust you...

Of course, when programmers use your code, they might not trust you either... they can program defensively as well. What if they don’t believe that you’ll only return non-null values from getProperty()? Then they’re going to protect their code, and use defensive programming, as well:

There are no Dumb Questions

Q:

Q: You said in Programming by contract is really all about trust that we could change the contract to throw an exception, but then you said here that throwing an exception is defensive programming. I’m confused...

A:

A: It’s really not that important what kind of exception is thrown. What’s important is how your customers and clients are involved in that decision. In programming by contract, you work with the client to agree on how you’re going to handle problems; in defensive programming, you make that decision in a way that ensures your code doesn’t crash, regardless of what the client wants to have happen.

When we decided to switch from returning null to throwing an exception, we did that by listening to the client, and agreeing on that particular action as a response to a request for non-existent properties. And we made the exception a RuntimeException, again because the client didn’t want to add lots of try/catch blocks to their code. They could have just as easily asked for a checked exception, and we could have agreed—and still been programming by contract.

Compare that to defensive programming, where we’re not really that interested in what the client wants. In defensive programming, we’re making sure that we aren’t responsible for crashing a program, and we even go out of our way to try and prevent the client from crashing their program.

Fireside Chats

Tonight’s talk: Programming by Contract and Defensive Programming duke it out over trust issues with programmers.

Programming by Contract

Defensive Programming

It’s nice to sit down with you and meet face to face, we really don’t see each other like this very often.

Yeah, I really don’t like to get out much There’s just so much that can go wrong.

What do you mean?

Well, I could be crossing the street, and slip on some Banana.peel() that hadn’t been garbage collected, or some for loop without a good termination condition could come screaming through the intersection... there’s a lot of bad code out there, you know?

Well, sure, I guess... but you can’t live your whole life in fear of bad code. At some point, you have to just commit to how you’re going to behave, and trust other programmers to use you right.

Are you kidding me? Have you met most of the programmers writing the code you’re talking about trusting? They’re too busy watching Lost to worry about checking for bugs in their software. If they’d stop gawking at that Kate and her freckles, maybe I wouldn’t have to double-check their work so much.

Boy, it sounds like you have trust issues.

And you don’t?

No. I trust programmers understand the contract that I provide them.

Contract? Oh, you still think that if you explain what you’ll do in a certain situation, that a “good” programmer will use you correctly? Boy, what naivete!

Look, my contract explicitly states what I have to do, and what people that use me have to do.

Haven’t you heard? Over 50% of contracts today end in divorce... or maybe that was a different stat, I’m not sure... anyway, do you really think programmers are paying attention to your little contract?

Look, if programmers and users don’t keep their end of the bargain, I can’t be held responsible for that. If they violate the contract, they deserve what they get. I can’t be held liable.

Sounds pretty callous to me. I try and help my users, and even protect them from themselves.

With tons of extra code, little “if (value == null)” checks everywhere? What a beating. Sounds like you slow things down more than anything.

Sure, sometimes I’m not the best performer, but I sure keep everyone safe from disaster. I often like to think of myself... a bit like Superman.

Superman? You did not just say that...

It’s true! Besides, how many times has your code gone up in smoke because of a lazy programmer who ignored your contract?

But that’s the point! I may not be great for lazy programmers, but I’m terrific for programmers who do check their work. They get a performance bump, and their code is shorter when they use me.

Short code, humph. I’d much rather have good code. Code that keeps programmers and users safe.

And that’s what I provide, just without all the trust issues and baggage you bring along...

Hey, I’ve got a trust issue for you right here...

I’ll show you safe code, you little...

...transmission ended... Veuillez nous aider! ... 4 8 15 ...

Who Am I?

Feature Driven Development, Use Case Driven Development, Programming by Contract, and Defensive Programming have all showed up for a masquerade party, but none of them bothered to wear name tags. They’re all a chatty bunch, though, so it’s up to you to listen to what they’re saying, and try and figure out who’s behind the masks. Be careful.... sometimes more than one masked guest could be saying the same thing.

I’m very well-ordered. I prefer to take things one step at a time, until I’ve made it from start to finish.

_____________________________

Well, sure, she said she would call, but how can you really believe anyone anymore?

_____________________________

Oh, absolutely, requirements really get me motivated.

_____________________________

I’m very well-behaved. In fact, I’ve been focusing on all of my own behavior before moving on to anything else.

_____________________________

Really, it’s all about my customer. I just want to satisfy them, after all.

_____________________________

Hey, you’re a big boy. You can deal with that on your own... it’s really not my problem anymore, is it?

_____________________________

As long as you’re good with it, so am I. Who am I to tell you what to do, so long as you know what you can expect from me.

_____________________________

Figure out who is who in Who Am I? Solutions.

Sharpen your pencil

Change the programming contract for Unit.

Gary’s clients want Unit to assume they’re using it correctly. That means that if a non-existent property is being queried, then something has truly gone wrong in the game, and an exception needs to be thrown. Your job is to:

Update Unit.java so that requests for a non-existent property result in an exception being thrown. Figuring out the type of exception to use is up to you.

Update UnitTester and the test cases that this contract change affects to reflect this new contract.

Re-run UnitTester and make sure Unit.java still passes all of the tests.

Note

Our answers are on the next page.

Sharpen your pencil answers

Change the programming contract for Unit.

Gary’s clients want Unit to assume they’re using it correctly. That means that if a non-existent property is being queried, then something has truly gone wrong in the game, and an exception needs to be thrown.

There are no Dumb Questions

Q:

Q: Why are you throwing a RuntimeException, and not a checked exception, like IllegalAccessException?

A:

A: If you used a checked exception, code that calls getProperty() would have to check for that exception, in try/catch blocks. That’s not what the client wanted; we agreed to a contract that would let them code without having to catch for any exceptions. So by using a RuntimeException, no extra worked is required for their client code to use the Unit class.

Q:

Q: What about the get methods for other properties, like weapons, name, and id?

A:

A: id and name are an int and String, respectively, so those aren’t a problem (id is required to create a new Unit, and name will either be null or a String with a value). The weapons property is a List, so if you call getWeapons() when there aren’t any it’s going to result in a null list being returned. You could change that method to throw an exception if the weapons list was empty, although that wasn’t specifically asked for by the clients.

When you are programming by contract, you’re working with client code to agree on how you’ll handle problem situations.

When you’re programming defensively, you’re making sure the client gets a “safe” response, no matter what the client wants to have happen.

There are no Dumb Questions

Q:

Q: You said that programming by contract resulted in less code, but it seems like we just added a lot of code to Unit.java.

A:

A: That’s because instead of directly returning null, we throw a new RuntimeException. But that’s more of a special case here than the rule. Most of the time, you’ll not have much extra code on the service side, because you’re simply returning objects and values without checking to see if they’re non-null, or within a particular data range.

Q:

Q: I still don’t see why we’re switching to programming by contract here. Why is it so much better?

A:

A: It’s not a matter of being better or worse; it’s a matter of what your customer wants. In fact, you’ll rarely decide on your own if you want to do programming by contract or defensive programming. That’s something that’s usually determined by what your customer wants, and the types of users that will be using the software that you’re writing.

Moving units

We’ve finally finished up unit properties, and can move on to the next item on our list:

Each unit should have properties, and game designers can add new properties to unit types in their own games.

Units have to be able to move from one tile on a board to another.

Note

We’re on to dealing with movement, now.

Units can be grouped together into armies.

Haven’t we been here before?

This should sound pretty familiar... we already dealt with movement in Chapter 7:

Break your apps up into smaller chunks of functionality

We’ve been talking a lot about iterating deeper into your application, and at each stage, doing more analysis and design. So you’re taking each problem, and then breaking it up (either into use cases or features), and then solving a part of the problem, over and over. This is what we’ve been doing in this chapter: taking a single feature, and working on that feature until it’s complete.

But you can still break things up further...

But once you choose a single feature or use case, you can usually break that feature up into even smaller pieces of behavior. For example, a unit has properties and we have to deal with unit movement. And we also need to support groupings of units. So each of these individual pieces of behavior has to be dealt with.

Just like when you broke your app up and began to iterate, you’ll have to do more analysis and design at each step. Always make sure your earlier decisions make sense, and change or rework those decisions if they don’t.

Your decisions can iterate down, too

Lots of times you’ll find that decisions you made earlier save you work down the line. In Gary’s system, we decided that game designers would deal with movement on their own. So now that we’re talking about how to handle unit movement, we can take that decision we made earlier, and apply it here. Since it still seems sensible—there’s no reason to change that decision—we can have game designers worry about handling unit movement, and move on to the next piece of behavior.

Note

Just add a note to your docs for the game designers that movement is up to them.

Feature Puzzle

By now, you should have feature driven development, iteration, analysis, and design down pretty solid. We’re going to leave it up to you to handle the last bit of behavior and finish off the Unit feature of Gary’s game system framework.

The problem:

Gary’s framework needs to support groups of units.

Your task:

Create a new class that can group units together, and both add and remove units to the group.

Fill out the table below with test case scenarios that will test your software, and prove to Gary that the grouping of units works.

Add methods to UnitTester to implement the test scenarios in the table, and make sure all your tests pass.

See how we solved the puzzle in Feature Puzzle Solutions.

Bullet Points

The first step in writing good software is to make sure your application works like the customer expects and wants it to.

Customers don’t usually care about diagrams and lists; they want to see your software actually do something.

Use case driven development focuses on one scenario in a use case in your application at a time.

In use case driven development, you focus on a single scenario at a time, but you also usually code all the scenarios in a single use case before moving on to any other scenarios, in other use cases.

Feature driven development allows you to code a complete feature before moving on to anything else.

You can choose to work on either big or small features in feature-driven development, as long as you take each feature one at a time.

Software development is always iterative. You look at the big picture, and then iterate down to smaller pieces of functionality.

You have to do analysis and design at each step of your development cycle, including when you start working on a new feature or use case.

Tests allow you to make sure your software doesn’t have any bugs, and let you prove to your customer that your software works.

A good test case only tests one specific piece of functionality.

Test cases may involve only one, or several, methods in a single class, or may involve multiple classes.

Test driven development is based on the idea that you write your tests first, and then develop software that passes those tests. The result is fully functional, working software.

Programming by contract assumes both sides in a transaction understand what actions generate what behavior, and will abide by that contract.

Methods usually return null or unchecked exceptions when errors occur in programming by contract environments.

Defensive programming looks for things to go wrong, and tests extensively to avoid problem situations.

Methods usually return “empty” objects or throw checked exceptions in defensive programming environments.

Feature Puzzle Solutions

Gary’s framework needs to support groups of units, and should also allow groups of those groups (in as many nestings as the game designer wants to allow).

And now for the test cases:

Get online

You should be able to write the code for UnitTester using the test case table shown here. If you want to see how your code compares with ours, visit http://www.headfirstlabs.com, click on Head First OOA&D, and look for “UnitGroup Test Cases.”

Tools for your OOA&D Toolbox

We learned about several approaches to iterating through your project, and even a bit about two common programming practices in this chapter. Add all these to your toolbox:

OOA&D Cross

Lots of new terms in this chapter, so lots of little square boxes to fill in for this chapter’s crossword. Review the chapter and see if you can get them all!

Across

Down

3. Never be afraid to do this in design.

4. This type of programming protects you and focuses on preventing errors and invalid data.

6. You should test your software for this kind of usage.

11. Iterating your development based on specific pieces of functionality.

12. Feature driven development is very __________.

15. Good development is driven by these.

16. Customers just want their software to do this.

17. Developing your software based on scenarios through a system.

18. Getting stuck trying to decide on one design decision or another.

1. This is what you use to prove to the customer that your software works.

2. Program this way when you trust your users, and they trust you.

5. Testing weird and strange usages your code will help you catch errors __________.

7. Use case diagrams and feature lists don’t make sense to the ___________.

8. Design decisions are always a __________.

9. A single test case can focus on this many pieces of functionality

10. Great software is written like this.

13. You write software for the __________.

14. Once you choose a feature or use case, you need to do this again.

Exercise Solutions

Who Am I? Solutions

Feature Driven Development, Use Case Driven Development, Programming by Contract, and Defensive Programming have all showed up for a masquerade party, but none of them bothered to wear name tags. They’re all a chatty bunch, though, so it’s up to you to listen to what they’re saying, and try and figure out who’s behind the masks. Be careful.... sometimes more than one masked guest could be saying the same thing.

Chapter 10. The OOA&D Lifecycle: Putting It All Together

Are we there yet? We’ve been working on lots of individual ways to improve your software, but now it’s time to put it all together. This is it, what you’ve been waiting for: we’re going to take everything you’ve been learning, and show you how it’s all really part of a single process that you can use over and over again to write great software.

Developing software, OOA&D style

You’ve got a lot of new tools, techniques, and ideas about how to develop great software by now... but we still haven’t really put it all together.

That’s what this chapter is all about: taking all the individual things you know how to do—like figuring out requirements, writing up use cases, and applying design patterns—and turning it into a reusable process that you can use to tackle even your trickiest software problems, over and over again.

So what does that process look like?

Let’s build a software project, from start to finish, using this process.

We’ve used all of the different parts of this process to work on software projects throughout the book, but we haven’t yet really put it all together. But that’s all about to change... we’re going to let you build a pretty complex piece of software in this chapter, from feature list to implementation and delivery.

Along the way, you’ll see for yourself how all the things you’ve been learning really do help you build great software. Get ready, this will be your final test.

OOA&D GENERAL’S WARNING: Answers to this exercise do NOT appear on the next page. Go ahead and work through this chapter, and we’ll come back to these answers at the end of the chapter.

OOA&D Magnets

Before we dive into the problem we’re going to be solving in this chapter, you need to make sure you see where all the things you’ve been learning fit in the big OOA&D Project Lifecycle. At the bottom of this page are OOA&D magnets for lots of the things you’ve learned about already; your job is to try and put those magnets on the right phase of the OOA&D lifecycle, shown again below.

You can put more than one magnet on each phase, and there are some magnets you may want to use more than once, so take your time, and good luck.

The problem

Here’s the project we’re going to work through in this chapter, from beginning to end:

Statement of Work

Congratulations! Based on your amazing work for Rick’s Stringed Instruments and Doug’s Dog Doors, we’d like to commission you to program our brand new Objectville Travel RouteFinder.

With the recent increase in travel to Objectville, we want to provide tourists an easy way to see the wonderful sights that make Objectville so unique. The RouteFinder should be able to store Objectville’s complete network of subway lines, as well as all the stations along each line. Objectville’s subways are state-of-the-art, and can go backwards and forwards between stations, so you don’t need to worry about the direction of any of the lines.

The RouteFinder should also be able to take a starting station, and a destination station, and figure out a route to travel. Our travel agents should be able to print out the route, indicating which lines to take, which stations are passed on a line, and when travelers may need to get off one line and get on another at a connecting station.

We pride ourselves on flexibility and extensibility in Objectville, so we expect the RouteFinder to be easy to extend as we come up with new ways to provide our tourists the best experience around in object-based travel.

We look forward to seeing your design and a working RouteFinder soon. We’re all counting on you!

Sincerely,

Orbin Traveloctic, CEO

P.S. To help you get started, we’ve provided a map of Objectville’s subway lines, and a file with all of the stations and lines.

Objectville Diner

This page left intentionally blank, so you can cut out the cool Objectville Map on the next page and hang it up on your cubicle wall.

Sharpen your pencil

Write the feature list for the RouteFinder app.

We’re throwing you right into things. Your job is to take the Statement of Work in The problem, and use it to develop a feature list. You can refer back to Chapter 6 if you need help on what features are, and what a typical feature list looks like.

Objectville RouteFinder Feature List

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

________________________________________________________

You don’t have to use all of these blanks if you don’t think you need them all.

Sharpen your pencil answers

Write the feature list for the RouteFinder app.

Your job was to take the Statement of Work in The problem, and use it to develop a feature list for the RouteFinder we’re going to build.

There are no Dumb Questions

Q:

Q: Why aren’t we gathering requirements? I’m still not clear on how a feature is really that different from a requirement, anyway.

A:

A: Features and requirements are often used almost interchangeably. Most of the time, though, people say “feature” when they’re talking about BIG things that an application needs to do. So it might take several requirements to satisfy one feature. And since features are usually a little bigger-picture than requirements, it’s a good idea to start any new project by writing out a feature list, like we’ve done with the RouteFinder.

Q:

Q: Why did you list printing out the route as a separate feature? That’s pretty easy once you’ve got a valid route between two stations, isn’t it?

A:

A: It probably will be, yes. But the feature list isn’t just a list of hard problems you have to solve—it’s a list of all the things your application has to be able to do. So even if a feature seems easy or trivial, put it on your feature list anyway.

Now you should really know what you’re supposed to do

With a feature list in hand, you should have a good understanding of the things that your app needs to do. You probably even can begin to think about the structure of your application, although we’ll spend a lot more time on that in just a bit.

Once you’ve got your feature list down, you should move on to use case diagrams. Those will help you connect what your app does to how it will be used—and that’s what customers really are interested in.

Your feature lists are all about understanding what your software is supposed to do.

Your use case diagrams let you start thinking about how your software will be used, without getting into a bunch of unnecessary details.

Sharpen your pencil

Decide on the structure for the RouteFinder code.

With feature lists in hand, let’s look at how our app is going to be used. Below, we’ve started a use case diagram for the RouteFinder app. For this project, there are two actors, and just two use cases (sounds sort of simple, doesn’t it?).

It’s up to you to figure out who (or what) the two actors are, and to label the two use cases. If you need help, refer back to Chapter 6 for more on use case diagrams.

Answers in Exercise Solutions.

Feature Magnets

Once you’ve got your use case diagrams figured out, you need to make sure that your use cases match up with the features you have to deliver to the customer. Below is the feature list for RouteFinder, as well as magnets for each feature. Place each magnet below on one of the use cases you filled in in Sharpen your pencil. Make sure you have each feature covered before turning the page.

Exercise Solutions

Decide on the structure for the RouteFinder code, and map your use cases back to your feature list.

You had a Sharpen Your Pencil, and a Feature Magnets to solve. You were supposed to figure out the actors and use cases for your system, and then make sure those use cases covered all the features we decided RouteFinder had to support.

Use cases reflect usage, features reflect functionality

Let’s look more closely at one of the feature-use case matches we showed you on the last page:

The “Load network of subway lines” use case really does not directly use our feature that deals with representing the subway. Obviously, we have to be able to represent the subway for this use case to work, but it’s a stretch to tie the two together like this.

That’s not a mistake, though; when we’re writing use cases, we’re dealing with just the interactions between actors and a system. We’re just talking about the ways that your system is used (which is where the term “use case” came from).

The features in your system reflect your system’s functionality. Your system must do those things in order for the use cases to actually work, even though the functionality isn’t always an explicit part of any particular use case.

There are no Dumb Questions

Q:

Q: Didn’t you say that I should be able to match up every feature to a use case in my system?

A:

A: Yes, and that’s still true. Every feature in your system will be at least a part of addressing one or more uses cases in your use case diagram. But that doesn’t mean that the use case has to actually directly use that feature. Lots of times, a feature makes it possible for a use case to function without being directly used by the use case itself.

In our RouteFinder, there would be no way to load a network of subway lines into the system (one of our use cases) without having a representation of a subway in the first place (one of our features). But the “Load Network” use case doesn’t have any steps that match up directly with that feature... the steps in the use case just assume that a representation of the subway exists. So the use case indirectly uses the feature, without explicitly referring to it.

Q:

Q: So is a use case a requirement, or is a feature a requirement?

A:

A: Both! Use cases are requirements for how people and things (actors) interact with your system, and features are requirements about things that your system must do. They’re related, but they are not the same. Still, to implement a system’s use cases, you’re going to need the functionality in the system’s features. That’s why you should always be able to map your features to the use cases that they enable and are used by.

Q:

Q: What happens if I find a feature that I can’t match up to a use case, even indirectly?

A:

A: You should take a hard look at the feature, and make sure it really is a required part of your system. Your customer—and her customers—only interact with your system through the use cases. So if a feature doesn’t at least indirectly make a use case possible, you’re customer really isn’t going to see a benefit. If you think you’ve got a feature that doesn’t really affect how your system is used or performs, talk it over with the customer, but don’t be afraid to cut something if it’s not going to improve your system.

The features in your system are what the system does, and are not always reflected in your use cases, which show how the system is used.

Features and use cases work together, but they are not the same thing.

The Big Break-Up

We’re starting to pick up some steam. With use case diagrams in place, you’re ready to break this problem up into some smaller pieces of functionality. There are several ways to do this in any application, but our goal here is to keep the RouteFinder system very modular. That means keeping different pieces of functionality separate—each module should have a single responsibility.

Go ahead and break up the RouteFinder system into four different “modules”. Think carefully about the best way to break up your system... it isn’t necessarily going to line up with your four features (although it might!).

HINT: Remember, you need to handle the system’s functionality, but you also need to prove to the customer that your system works.

The Big Break-Up, Solved

We’re starting to pick up some steam. With use case diagrams in place, you’re ready to break this problem up into some smaller pieces of functionality.

Sharpen your pencil

Which OO principles are we using?

Check the box next to the OO principles you think we’re using to break up the RouteFinder functionality in this manner.

Single Responsibility Principle

Delegation

Don’t Repeat Yourself

Polymorphism

Encapsulation

Liskov Substitution Principle

Note

Answers in Sharpen your pencil answers.

Now start to iterate

Iteration 1

Once you’ve broken up your software into several individual pieces of functionality, you’re ready to start iterating over each piece of functionality, until the application is complete.

At this point, we need to take our big-picture view of the system, from our use case diagram, and refine that into requirements that we can begin to tackle, one by one. For this first iteration, let’s take the “Load network of subway lines” use case, and turn that into a set of requirements that isn’t so big-picture. Then we can take care of that use case, and iterate again, working on the next use case.

Note

We’re taking the first use case from our diagram, and starting with it.

Sharpen your pencil

What approach to development are we using?

_____________________________________________________________________

_____________________________________________________________________

Sharpen your pencil

Write the use case for loading subway lines.

Turn that little oval into a full-blown use case. Write the steps that RouteFinder needs to take to implement the “Load network of subway lines” use case.

Load network of subway lines Use Case

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

You can use more room, or more steps, if you need them.

_____________________________________________________________________

Not too sure about this use case? It’s OK... turn the page for some help...

You’ll often have to do some extra work between breaking up the problem and writing your use cases.

You’ve just uncovered a “secret step” in our process for writing software the OOA&D way:

If you get stuck writing a use case, there’s nothing wrong with taking a step back, and examining the problem you’re trying to solve a bit. Then, you can go back to your use case, and have a better chance of getting it written correctly.

Sharpen your pencil answers

Which OO principles are we using?

Check the box next to the OO principles you think we used to break up the RouteFinder functionality into separate modules.

A closer look at representing a subway

Iteration 1

Note

We’re on Iteration 1, trying to handle the first use case: loading a network of subway lines.

Before we can figure out how to load a subway line, there are two things we need to get a good grasp of:

Understanding the basics of what a subway system is.

Understanding the information an administrator would have when they’re loading a set of subway stations and lines.

What is a station?

A subway system has stations, and connections between those stations, and lines that are groups of connections. So let’s begin by figuring out exactly what a station is.

And a connection between two stations?

As soon as you start adding several stations, you’ve got to deal with the connections between those stations:

Sharpen your pencil answers

What approach to development are we using in this chapter?

____Use-case driven development_______

Then a line is just a series of connections...

If you put several connections together, then you’ve got a subway line.

Let’s take a look at that subway file

We’ve got a basic idea now of what a subway is, so let’s see what kind of data we’ve got to work with. Remember, Objectville Travel said they would send us a file with all the stations and lines, so this should give us an idea of what an administrator will use to load the lines into the subway system.

Iteration 1

Sharpen your pencil

Write the use case for loading subway lines.

You should have enough understanding of what a subway system is, and the format of the Objectville Subway input file, to write this use case now.

Sharpen your pencil answers

Write the use case for loading subway lines.

You should have enough understanding of what a subway system is, and the format of the Objectville Subway input file, to write this use case now.

There are no Dumb Questions

Q:

Q: My use case looks totally different. Is your use case the only solution to the puzzle?

A:

A: No, not at all. By now you realize that there are lots of decisions you have to make to solve any problem, and our use case simply reflects the decisions we made. We’re going to work with this particular use case throughout the rest of this chapter, so make sure you understand our reasoning behind it, but it’s perfectly OK if you came up with your own use case that solves the same problem of loading a network of subway stations and lines.

Q:

Q: I didn’t add any steps about validation to my use case. Is that OK?

A:

A: Validation is something that you should add to your use case if you left it out. Making sure the stations for a connection actually exist is a lot like not having a dog door automatically close. It seems innocent enough, until the real world creeps in, and someone misspells a station name. Suddenly, you have the equivalent of software rodents: a connection that goes to a non-existent station. So if you left out validation, be sure to add it in to your own use case.

Iteration 1

Let’s see if our use case works

The use case for loading a network is a little tricky, and has several groups of steps that repeat. Let’s check the flow of things against our text file before we go on to analyzing the use case, and starting to design the classes in our system.

Analysis and Design Puzzle

This time, it’s your job to take on two phases of the OOA&D process at once. First, you need to perform textual analysis on the use case below, and figure out the nouns that are candidate classes, and the verbs that are candidate operations. Write the nouns and verbs in the blanks provided below the use case.

Load network of subway lines Use Case

The administrator supplies a file of stations and lines.

The system reads in the name of a station.

The system validates that the station doesn’t already exist.

The system adds the new station to the subway.

The system repeats steps 2-4 until all stations are added.

The system reads in the name of a line to add.

The system reads in two stations that are connected.

The system validates that the stations exist.

The system creates a new connection between the two stations, going in both directions, on the current line.

The system repeats steps 7-9 until the line is complete.

The system repeats steps 6-10 until all lines are entered.

Nouns (candidate classes):

_________________

_________________

_________________

_________________

_________________

_________________

Verbs (candidate operations):

_________________

_________________

_________________

_________________

_________________

_________________

Iteration 1

It’s on to preliminary design. Using the candidate nouns and verbs you got from the use case, draw a class diagram below of what you think the subway system might look like modeled in code. Use associations and any other UML notation you think will help make your design clear and understandable.

Analysis and Design Puzzle Solutions

Load network of subway lines Use Case

The administrator supplies a file of stations and lines.

The system reads in the name of a station.

The system validates that the station doesn’t already exist.

The system adds the new station to the subway.

The system repeats steps 2-4 until all stations are added.

The system reads in the name of a line to add.

The system reads in two stations that are connected.

The system validates that the stations exist.

The system creates a new connection between the two stations, going in both directions, on the current line.

The system repeats steps 7-9 until the line is complete.

The system repeats steps 6-10 until all lines are entered.

Nouns (candidate classes):

Verbs (candidate operations):

Iteration 1

To use a Line class or not to use a Line class... that is the question

It was pretty easy to look at our use case and figure out that we need a Station, Connection, and Subway class—those are fundamental to our system. But then we decided to not create a Line class. Instead, we just assigned a line name to each connection:

We made this decision based on one thing: we know how the system is going to be used. In the original Statement of Work (back in The problem) from Objectville Travel, we were told we needed to represent a subway, and get directions between one station and another. Once we have those directions, we can simply ask each connection for its line; there doesn’t seem to be a need for an actual Line class.

Your design decisions should be based on how your system will be used, as well as good OO principles.

Iteration 1

There are no Dumb Questions

Q:

Q: I found the “validates that a station exists” verb, but where does that operation appear on any of the classes in your design?

A:

A: We modeled that operation as hasStation() on the Subway class. You could have called that operation validate() or validateStation(), but those aren’t as descriptive as hasStation(), and you should always try and make your code as readable as possible.

Q:

Q: Could you talk a little more about how you showed those repeated steps in the use case?

A:

A: Lots of times a use case has a set of steps that need to be repeated, but there’s not a standard way to show that in use cases. So we just made one up! The point of a use case is to provide you with a clear set of steps that detail what your system should do, and we thought the clearest way to show those repeated steps was to write down “Repeat Steps 7-9.”

Q:

Q: I’ve been thinking about that subway representation, and it looks a lot like a graph data structure to me. Why aren’t we using a graph?

A:

A: Wow, you must have taken a data structures or algorithms class recently! Yes, you can use a graph to represent the subway. In that case, each station would be a node, and each connection would be a labeled edge.

Q:

Q: So then why aren’t we using a graph structure in this example?

A:

A: We think it’s really overkill in this situation. If you already know about graphs and nodes and edges, and you happen to have code for that sort of data structure lying around, then go ahead and use them. But from our point of view, we’d do more work adapting a graph to our needs than just coming up with a few simple classes for Station and Connection. Like almost everything else in the design stage, there are several ways to solve a problem, and you need to choose a solution that works well for you.

Q:

Q: You lost me on the whole graph thing... what’s all this about edges and nodes?

A:

A: It’s OK; you don’t need to know about graphs in order to understand and solve this particular problem. It’s nothing to worry about, at least until we come up with a Head First Data Structures book (anyone? anyone?).

Code the Station class

We’ve got requirements in the form of a use case, a class diagram, and we know the Station class will fit into our Subway model. Now we’re ready to start writing code:

Watch it!

When you override equals() in Java, you should usually also override hashCode() to ensure correct comparisons.

The Java specification recommends that if two objects are equal, they should have the same hash code. So if you’re deciding on equality based on a property, it’s a good idea to also override hashCode() and return a hash code based on that same property. This is particularly important if you’re using your object in a Hashtable or HashMap, which both make heavy use of the hashCode() method.

Note

For a lot more on equals() and hashCode(), check out Chapter 16 of Head First Java.

Iteration 1

Sharpen your pencil

Write the Connection class.

Using the class diagram on the right, complete the Connection class by filling in the blanks with the correct lines of code. Be sure your class will compile before you turn the page and see our answers.

public class Connection {

  private _________ ___________, ____________;
  private _________ ___________;

  public Connection(__________ __________, _________ _________,
                    __________ __________) {
    this.__________ = station1;
    this.__________ = station2;
    this.__________ = lineName;
  }

  public _________ ___________() {
    ________ station1;
  }

  public _________ ___________() {
    ________ station2;
  }

  public _________ ___________() {
    ________ lineName;
  }
}

Sharpen your pencil answers

Write the Connection class.

Using the class diagram on the right, your job was to fill in the blanks and complete the Connection class.

Iteration 1

Code the Subway class

Next up is the Subway class itself. With Station and Connection done, and a good class diagram, nothing here should be a surprise:

Points of interest on the Objectville Subway (class)

We threw a couple of new things into the Subway class; first, you’ll see this line of code quite a bit:

Station station = new Station(stationName);

For example, when we create a new Connection, we have code like this:

Station station1 = new Station(station1Name);
Station station2 = new Station(station2Name);
Connection connection =
  new Connection(station1, station2, lineName);

Lots of programmers would take station1Name, and iterate through the list of stations in the Subway class to find the Station object that has a name of station1Name. But that takes a lot of time, and there’s a better way. Remember how we defined an equals() and hashCode() method on our Station class?

These methods allowed us to tell Java that when it compares two Station objects, just see if their name is the same. If the names are equal, even if the objects don’t refer to the same location in memory, they should be treated as the same. So instead of looking for a particular Station object in the Subway class’s list of station, it’s much easier to just create a new Station and use it.

Note

Normally, equals() in Java just checks to see if two objects actually are the SAME object... in other words, it looks to see if they are actually both references to the same place in memory. But that’s NOT what we want to use for comparison of two Station objects

Because we overrode equals() and hashCode(), we can save search time and complexity in our code. Your design decisions should always make your implementation better, not more complicated or harder to understand.

Iteration 1

What Java’s default equals() implementation does...

What our equals() implementation does...

There are no Dumb Questions

Q:

Q: What does any of this have to do with OOA&D?

A:

A: This is the very core of what makes OOA&D useful: because we understand our system, we realize that two stations should be considered identical if they have the same name. And, our design is improved by being able to compare stations based on their name, rather than their location in memory.

So the time we spent on requirements and getting a good grasp of our system made our design better, which in turn made implementing that design a lot simpler. That’s the power of OOA&D: you can turn knowledge of your system into a flexible design, and even end up with cleaner code—all because you spent time up front listening to the customer and gathering requirements, rather than diving right into an IDE and typing in source code.

Frank: That’s true. So we could change our Subway class to look more like this:

Jill: But then you’re exposing the internals of your application!

Joe: Whoa... not sure what that means, but it sure doesn’t sound like something I want to do. What are you talking about?

Jill: Well, look at our code right now. You don’t have to work with a Station or Connection at all to load up the subway. You can just call methods on our new Subway class.

Frank: How is that any different from what we’re suggesting?

Jill: If we went with your ideas, people that use the Subway class would have to also work with Station and Connection. In our version right now, they just work with Strings: the name of a station, and the name of a line.

Joe: And that’s bad because...

Frank: Wait, I think I get it. Their code is getting tied in to how we implement the Station and Connection classes, since they’re having to work with those classes directly.

Jill: Exactly! But with our version, we could change up Connection or Station, and we’d only have to change our Subway class. Their code would stay the same, since they’re abstracted away from our implementations of Connection and Station.

Iteration 1

Protecting your classes (and your client’s classes, too)

Frank, Joe, and Jill are really talking about just one more form of abstraction. Let’s take a closer look:

You should only expose clients of your code to the classes that they NEED to interact with.

Classes that the clients don’t interact with can be changed with minimal client code being affected.

Note

In this application, we could change how Station and Connection work, and it wouldn’t affect code that only uses our Subway object; they’re protected from changes to our implementation

The SubwayLoader class

We’re almost done with our first iteration, and our first use case. All that’s left is to code the class that loads a subway based on the test file we got from Objectville Travel, Inc.

Iteration 1

Method Magnets

Let’s see exactly what happens when you call loadFromFile() in SubwayLoader, and give it the text file we got from Objectville Travel. Your job is to place the magnets from the bottom of this page—which match up to methods on the SubwayLoader and Subway classes—next to the lines in the text file where they’ll be called.

Method Magnet Solutions

Let’s see exactly what happens when you call loadFromFile() in SubwayLoader, and give it the text file we got from Objectville Travel. Your job was to place the magnets from the bottom of this page next to the lines in the text file where they’ll be called.

Iteration 1

Test Puzzle

You’re almost done with the first use case, and our first iteration! All that’s left is to test out our solution, and make sure it actually works.

The problem:

You need to test loading the ObjectvilleSubway.txt file, and make sure that SubwayLoader correctly loads in all stations and connections in the file.

Your task:

Add a method to Subway to check if a particular connection exists, given the two station names and the line name for that connection.

Write a test class, called LoadTester, with a main() method that loads the Objectville Subway system from the text file we got from Objectville Travel, Inc.

Write code in LoadTester that checks a few of the stations and connections from the text file against the Subway object returned from SubwayLoader’s loadFromFile() method. You should check to make sure that at least three stations and three connections on three different lines were all entered correctly.

Run your test program, and verify that we’re really done with Iteration 1.

Test Puzzle Solution

Your job was to test the SubwayLoader and our subway representation to make sure you can load a subway system from a text file.

Add a method to Subway to check if a particular connection exists, given the two station names and the line name for that connection.

There are no Dumb Questions

Q:

Q: Wouldn’t it be easier to write the hasConnection() method if we used a Line object, like we talked about a few pages ago?

A:

A: It would. If we had a Line object, we could look up the line using the name passed into hasConnection(), and just iterate over the Connection objects for that line. So in most cases, hasConnection() would involve less iteration, and return a We still decided not to use a Line object, though, because we’ve only added hasConnection() to help us test our classes. So adding a Line object just to make a test method return faster doesn’t seem like a good idea. If we find that we need the hasConnection() method in other parts of our app, though, this result faster, if we had a Line object.

Iteration 1

Write a test class, called LoadTester, with a main() method that loads the Objectville Subway system from the text file we got from Objectville Travel, Inc.

Write code in LoadTester that checks a few of the stations and connections from the text file against the Subway object returned from SubwayLoader’s loadFromFile() method. You should check to make sure that at least three stations and three connections on three different lines were all entered correctly.

Test Puzzle Solution (cont.)

Your job was to test the SubwayLoader and our subway representation to make sure you can load a subway system from a text file.

Run your test program, and verify that we’re really done with Iteration 1.

Brain Power

Try and write a test case that gets all the stations and connections in the Subway and prints them out, to verify your subway is loading the network correctly.

It’s time to iterate again

Our test proves that we really have finished up our first iteration. The “Load network of subway lines” use case is complete, and that means it’s time to iterate again. Now, we can take on our next use case—“Get directions”—and return to the Requirements phase and work through this use case.

But before we start Iteration 2...

It’s been a LONG iteration, and you’ve done some great work. STOP, take a BREAK, and eat a bite or drink some water. Give your brain a chance to REST.

Then, once you’ve caught your breath, turn the page, and let’s knock out that last use case. Are you ready? Then let’s iterate again.

What’s left to do?

We’ve made a lot of progress, on both our use cases, and our feature list. Below is the feature list and use case diagram we developed earlier in the chapter:

Back to the requirements phase...

Now that we’re ready to take on the next use case, we have to go back to the requirements phase, and work through this use case the same way we did the first one. So we’ll start by taking our use case title from our use case diagram, “Get directions,” and developing that into a full-blown use case.

Sharpen your pencil

Write the complete use case for “Get directions.”

We’re back to writing use cases again. This time, your job is to write a use case that allows a travel agent to get directions from one station to another on the Objectville Subway.

Sharpen your pencil answers

Write the complete use case for “Get directions.”

Focus on code, then focus on customers. Then focus on code, then focus on customers...

When we started breaking our application up into different modules way back in The Big Break-Up, Solved, we were really talking about the structure of our application, and how we are going to break up our application. We have a Subway and Station class in the Subway module, and a SubwayLoader class in the Loader module, and so on. In other words, we’re focusing on our code.

But when we’re working on use cases, we’re focusing on how the customer uses the system—we looked at the format of an input file to load lines, and began to focus on the customer’s interaction with your system. So we’ve really been going back and forth between our code (in the Break Up the Problem step) and our customer (in the Requirements step):

When you’re developing software, there’s going to be a lot of this back-and-forth. You have to make sure your software does what it’s supposed to, but it’s your code that makes the software actually do something.

It’s your job to balance making sure the customer gets the functionality they want with making sure your code stays flexible and well-designed.

Analysis and Design Puzzle

Note

Do some of these exercises look familiar? You use the same techniques in each iteration of your development cycle.

It’s time to take on more domain analysis and design for your system. Take the use case below, figure out the candidate classes and candidate operations, and then update the class diagram on the right with any changes you think you need to make.

Get directions Use Case

The travel agent gives the system a starting station and a station to travel to.

The system validates that the starting and ending stations both exist on the subway.

The system calculates a route from the starting station to the ending station.

The system prints out the route it calculated.

Nouns (candidate classes):

_________________

_________________

_________________

_________________

_________________

_________________

Verbs (candidate operations):

_________________

_________________

_________________

_________________

_________________

_________________

Analysis and Design Puzzle Solutions

Note

*We didn’t show the nouns and verbs... by now, you should be comfortable with that step, and be able to translate them into the class diagram shown here.

Iteration makes problems easier

The class diagram on the last page really isn’t that much different from our class diagram from the first iteration (flip back to Let’s see if our use case works to take a look at that earlier version). That’s because we did a lot of work that applies to all our iterations during our first iteration.

Once you’ve completed your first iteration, your successive iterations are often a lot easier, because so much of what you’ve already done makes those later iterations easier.

Implementation: Subway.java

Figuring out a route between two stations turns out to be a particularly tricky problem, and gets into some of that graph stuff we talked about briefly back in There are no Dumb Questions. To help you out, we’ve included some Ready-bake Code that you can use to get a route between two stations.

Ready-bake Code

Ready-bake Code

Sometimes the best way to get the job done is find someone else who has already done the job for you.

It might seem weird that at this stage, we’re giving you the code for getting a route between two stations. But that’s part of what makes a good developer: a willingness to look around for existing solutions to hard problems.

In fact, we had some help from a college student on implementing a version of Dijkstra’s algorithm that would work with the subway (seriously!). Sure, you probably can come up with your own totally original solution to every problem, but why would you want to if someone has already done the work for you?

Note

Thanks, Felix Geller, your code really saved the day.

Sometimes the best code for a particular problem has already been written. Don’t get hung up on writing code yourself if someone already has a working solution.

What does a route look like?

The getDirections() method we just added to Subway takes in two Strings: the name of the starting station, and the name of the station that a tourist is trying to get to:

getDirections() then returns a List, which is filled with Connection objects. Each Connection is one part of the path between the two stations:

So the entire route returned from getDirections() looks like a series of Connection objects:

Printing Puzzle

You’re almost done! With a working getDirections() method in Subway, the last feature to implement is printing those directions out. Your job is to write a class called SubwayPrinter that takes the data structure returned from getDirections(), which is a list of Connection objects, and prints out the directions. The directions should be printed to an OutputStream, supplied to the constructor of the SubwayPrinter class when an instance of the printer class is created.

Here’s the class diagram for SubwayPrinter that you should follow:

SubwayPrinter

out:PrintStream

printDirections(Connection [*])

Your output should look similar to this:

Printing Puzzle Solution

Here’s how we wrote the SubwayPrinter class. You might have come up with a slightly different approach to looping through the route List, but your output should match ours exactly for full credit.

One last test class...

All that we need to do now is put everything together. Below is the SubwayTester class we wrote to load the Objectville Subway system, take in two stations from the command line, and print out directions between those two stations using our new getDirections() method and printer class.

Check out Objectville for yourself!

It’s time to sit back and enjoy the fruits of your labor. Compile all your classes for the Objectville Subway application, and try out SubwayTester with a few different starting and stopping stations. Here’s one of our favorites:

OOA&D Magnets

Way back in OOA&D Magnets, we asked you to think about where lots of different things you’ve been learning about fit on the OOA&D lifecycle below. Now that you’ve written another piece of great software, you’re ready to take this exercise on, and see how we answered it, too. Go ahead and work this exercise again; did you change where you put any of the magnets after working through this chapter?

Oh, and don’t forget, you can put more than one magnet on each phase, and there are some magnets you may want to use more than once.

This time, answers are on the next page!

OOA&D Magnet Solutions

Your job was to try and put the different magnets on the right phase of the OOA&D lifecycle, shown below. You could put more than one magnet on each phase; how do your answers compare with ours?

There are no Dumb Questions

Q:

Q: It seems like I could put almost every magnet on each phase... but that can’t be right, can it?

A:

A: That’s exactly right. Although there are definitely some basic phases in a good development cycle, you can use most of the things you’ve learned about OOA&D, OO principles, design, analysis, requirements, and everything else at almost every stage of development.

The most effective and successful way to write great software is to have as many tools as you can, and to be able to choose any one (or more) to use at each stage of your development cycle. The more tools you have, the more ways you’ll have to look at and work on a problem... and that means less time being stuck or not knowing what to do next.

OOA&D is about having lots of options. There is never one right way to solve a problem, so the more options you have, the better chance you’ll find a good solution to every problem.

Iteration #3, anyone?

No, we’re not going to launch into any more design problems. But, you should realize that there is plenty more that you could do to improve the design of our RouteFinder application. We thought we’d give you just a few suggestions, in case you’re dying to take another pass through the OOA&D lifecycle.

Make loading more extensible

Right now, we’ve just got a single class that handles loading, and it only accepts a Java File as input. See if you can come up with a solution that allows you to load a subway from several types of input sources (try starting with a File and InputStream). Also make it easy to add new input sources, like a database. Remember, you want to minimize changes to existing code when you’re adding new functionality, so you may end up with an interface or abstract base class before you’re through.

Allow different output sources (and formats!)

We can only print subway directions to a file, and the directions are formatted in a particular way. See if you can design a flexible Printing module that allows you to print a route to different output sources (like a File, OutputStream, and Writer), in different formats (perhaps a verbose form that matches what we’ve done already, a compact form that only indicates where to changes lines, and an XML form for other programs to use in web services).

Note

Here’s a hint: check out the Strategy pattern in Head First Design Patterns for ideas on how you might make this work.

(the last) OOA&D Cross

Yes, it’s a sad day: you’re looking at the last crossword in the book. Take a deep breath, we’ve crammed this one full of terms to make it last a little longer. Enjoy!

Across

Down

2. All of your features should map to these, at least indirectly.

3. When you override equals() in Java, you should create a related implementation of this method.

5. Your features reflect this in your application.

6. You do this once you complete one feature or use case.

10. A feature list focuses on what your software __________.

12. When you complete this phase, you’re either done or need to iterate again.

15. Break your application up into these, based on your app’s functionality.

17. Understanding how a system is used should help you make better __________ decisions.

18. The approach to development we used in this chapter (3 words).

19. Never be afraid to use a __________ to a problem that someone else came up with.

21. Your design decisions are based on how this is used as well as good OO principles.

22. Iteration makes problems _______.

23. Each module in your applications should have a single ____________________.

1. Make a list of these to get your development started.

4. You usually create this type of diagram based on your domain analysis.

7. This iteration is usually the toughest.

8. OOA&D is about giving you lots of these.

9. You sometimes have to add a step to do this with your problem before writing use cases.

10. The kind of analysis that involves speaking to the customer in language that they understand.

11.This proves that your implementation is working.

13. The nouns in your use case are these types of classes.

14. You have to balance what the customer wants with your software’s _____________.

16. This is the stage where you apply good OO principles.

20. Use case diagrams focus on how your software will be ____________.

Exercise Solutions

The journey’s not over...

Now take OOA&D for a spin on your own projects!

We’ve loved having you here in Objectville, and we’re sad to see you go. But there’s nothing like taking what you’ve learned and putting it to use on your own development projects. So don’t stop enjoying OOA&D just yet... you’ve still got a few more gems in the back of the book, an index to read through, and then it’s time to take all these new ideas and put them into practice. We’re dying to hear how things go, so drop us a line at the Head First Labs web site, http://www.headfirstlabs.com, and let us know how OOA&D is paying off for YOU.

Appendix A. Leftovers: The Top Ten Topics (we didn’t cover)

Believe it or not, there’s still more. Yes, with over 550 pages under your belt, there are still things we couldn’t cram in. Even though these last ten topics don’t deserve more than a mention, we didn’t want to let you out of Objectville without a little more information on each one of them. But hey, now you’ve got just a little bit more to talk about during commercials of CATASTROPHE... and who doesn’t love some stimulating OOA&D talk every now and then?

Besides, once you’re done here, all that’s left is another appendix... and the index... and maybe some ads... and then you’re really done. We promise!

#1. IS-A and HAS-A

Lots of times in OO programming circles, you’ll hear someone talk about the IS-A and HAS-A relationships.

IS-A refers to inheritance

Usually, IS-A relates to inheritance, for example: “A Sword IS-A Weapon, so Sword should extend Weapon.”

HAS-A refers to composition or aggregation

HAS-A refers to composition and aggregation, so you might hear, “A Unit HAS-A Weapon, so a Unit can be composed with a Weapon object.”

The problem with IS-A and HAS-A

The reason we haven’t covered IS-A and HAS-A much is that they tend to break down in certain situations. For example, consider the situation where you’re modeling shapes, like Circle, Rectangle, and Diamond.

If you think about a Square object, you can apply the IS-A relationship: Square IS-A Rectangle. So you should make Square extend Rectangle, right?

But remember LSP, and that subtypes should be substitutable for their base types. So Square should be a direct substitute for Rectangle. But what happens with code like this:

The problem here is that when you set the width in setWidth() on Square, the square is going to have to set its height, too, since squares have equal width and height. So even though Square IS-A Rectangle, it doesn’t behave like a rectangle. Calling getHeight() above will return 5, not 10, which means that squares behave differently than rectangles, and aren’t substitutable for them—that’s a violation of the LSP.

Use inheritance when one object behaves like another, rather than just when the IS-A relationship applies.

#2. Use case formats

Even though there’s a pretty standard definition for what a use case is, there’s not a standard way for writing use cases. Here are just a few of the different ways you can write up your use cases:

Focusing on interaction

This format is a little more focused on separating out what is in a system, and how the actors outside of the system interact with your software.

A more formal use case

All of these use cases say the same thing... it’s up to you (and probably your boss) to decide which format works best for you.

#3. Anti patterns

We’ve talked a lot in this book about design patterns, and described them this way:

Note

Design Patterns

Design patterns are proven solutions to particular types of problems, and help us structure our own applications in ways that are easier to understand, more maintainable, and more flexible.

Design patterns help you recognize and implement GOOD solutions to common problems.

But there’s another type of pattern you should know about, called an anti-pattern:

Anti patterns are about recognizing and avoiding BAD solutions to common problems.

Note

Anti Patterns

Anti-patterns are the reverse of design patterns: they are common BAD solutions to problems. These dangerous pitfalls should be recognized and avoided.

Anti patterns turn up when you see the same problem get solved the same way, but the solution turns out to be a BAD one. For example, one common anti pattern is called “Gas Factory”, and refers to designs that are overly complex, and therefore not very maintainable. So you want to work to avoid the Gas Factory in your own code.

Note

We’re actually not making this up! At your next serious development meeting, be sure to mention trying to avoid the Gas Factory.

#4. CRC cards

CRC stands for Class, Responsibility, Collaborator. These cards are used to take a class and figure out what its responsibility should be, and what other classes it collaborates with.

CRC cards are typically just 3x5 index cards, with each individual card representing a class. The card has two columns: one for the responsibilities of the class, and another for other classes that are collaborators, and used to fulfill those responsibilities.

CRC cards help implement the SRP

You can use CRC cards to make sure your classes follow the Single Responsibility Principle. These go hand in hand with your SRP Analysis, as well:

#5. Metrics

Sometimes it’s hard to tell how solid your design really is, because design is such a subjective thing. That’s where metrics can help out: while they don’t provide a complete picture of your system, they can be helpful in pointing out strengths, weaknesses, and potential problems. You usually use software tools to take as input your class’s source code, and those tools then generate metrics based on your code and its design.

These metrics are more than just numbers, though. For example, just counting the number of lines of code in your application is almost a total waste of time. It’s nothing but a number, and has no context (and also depends a lot on how you’re writing your code, something else we’ll talk about in this appendix). But if you count the number of defects per 1000 lines of code, then that becomes a useful metric.

You can also use metric to measure things like how well you’re using abstraction in your code. Good design will use abstract classes and interfaces, so that other classes can program to those interfaces rather than specific implementation classes. So abstraction keeps one part of your code independent from changes to other parts of your code, at least to the degree that it’s possible in your system. You can use something called the abstractness metric to measure this:

Packages that have lots of abstractions will have a higher value for A, and packages with less abstractions have a lower value for A. In general, you want to have each package in your software only depend on packages with a higher value for A. That means that your packages are always depending on packages that are more abstract; the result should be software that can easily respond to change.

#6. Sequence diagrams

When we were working on the dog door for Todd and Gina, we developed several alternate paths (and one alternate path actually had an alternate path itself). To really get a feel for how your system handles these different paths, it’s helpful to use a UML sequence diagram. A sequence diagram is just what it sounds like: a visual way to show the things that happen in a particular interaction between an actor and your system.

#7. State diagrams

You’ve already seen class diagrams and sequence diagrams. UML also contains a diagram called a state machine diagram or statechart diagram, which is usually just referred to as a state diagram. This diagram describes a part of your system by showing its various states, and the actions that cause that state to change. These diagrams are great for describing complex behaviors visually.

State diagrams really come into play when you have multiple actions and events that are all going on at the same time. On the right page, we’ve taken just such a situation, and drawn a state diagram for how a game designer might use Gary’s Game System Framework. If game designers were going to use the framework, they might write a game that behaves a lot like this state diagram demonstrates.

#8. Unit testing

In each chapter that we’re worked on an application, we’ve built “driver” programs to test the code, like SubwayTester and DogDoorSimulator. These are all a form of unit testing. We test each class with a certain set of input data, or with a particular sequence of method calls.

While this is a great way to get a sense of how your application works when used by the customer, it does have some drawbacks:

You have to write a complete program for each usage of the software.

You need to produce some kind of output, either to the console or a file, to verify the software is working correctly.

You have to manually look over the output of the test, each time its run, to make sure things are working correctly.

Your tests will eventually test such large pieces of functionality that you’re no longer testing all the smaller features of your app.

Fortunately, there are testing frameworks that will not only allow you to test very small pieces of functionality, but will also automate much of that testing for you. In Java, the most popular framework is called JUnit (http://www.junit.org), and integrates with lots of the popular Java development environments, like Eclipse.

There are no Dumb Questions

Q:

Q: If the tests we wrote in the main part of the book made sure our software worked at a high level, why do we need more tests? Aren’t those enough to be sure our software works?

A:

A: Most of the tests we wrote really tested a particular scenario, such as opening the door, letting a dog out, having another dog bark, and then letting the owner’s dog back in. Unit tests, and particular the tests we’re talking about here, are far more granular. They test each class’s functionality, one piece at a time.

The reason that you need both types of tests is because you’ll never be able to come up with scenarios that test every possible combination of features and functionality in your software. We’re all human, and we all tend to forget just one or two strange situations now and then.

With tests that exercise each individual piece of functionality in your classes, you can be sure that things will work in any scenario, even if you don’t specifically test that scenario. It’s a way to make sure each small piece works, and one that lets you assume pretty safely that combining those small pieces will then work, as well.

What a test case looks like

A test case has a test method for each and every piece of functionality in the class that it’s testing. So for a class like DogDoor, we’d test opening the door, and closing the door. JUnit would generate a test class that looked something like this:

Test your code in context

Notice that instead of directly testing the DogDoor’s open() and close() methods, this test uses the Remote class, which is how the door would work in the real world. That ensures that the tests are simulating real usage, even though they are testing just a single piece of functionality at a time.

The same thing is done in testCloseDoor(). Instead of calling the close() method, the test opens the door with the remote, waits beyond the time it should take for the door to close automatically, and then tests to see if the door is closed. That’s how the door will be used, so that’s what should be tested.

#9. Coding standards and readable code

Reading source code should be a lot like reading a book. You should be able to tell what’s going on, and even if you have a few questions, it shouldn’t be too hard to figure out the answers to those questions if you just keep reading. Good developers and designers should be willing to spend a little extra time writing readable code, because it improves the ability to maintain and reuse that code.

Here’s an example of a commented and readable version of the DogDoor class we wrote back in Chapter 2 and Chapter 3.

Great software is more than just working code

Many developers will tell you that code standards and formatting are a big pain, but take a look at what happens when you don’t spend any time making your code readable:

From a purely functional point of view, this version of DogDoor works just as well as the one on the last page. But by now you should know that great software is more than just working code—it’s code that is maintainable, and can be reused. And most developers will not want to maintain or reuse this second version of DogDoor; it’s a pain to figure out what it does, or where things might go wrong—now imagine if there were 10,000 lines of code like this, and not just 25 or so.

Writing readable code makes that code easier to maintain and reuse, for you and other developers.

#10. Refactoring

Refactoring is the process of modifying the structure of your code without modifying its behavior. Refactoring is done to increase the cleanness, flexibility, and extensibility of your code, and usually is related to a specific improvement in your design.

Most refactorings are fairly simple, and focus on one specific design aspect of your code. For example:

public double getDisabilityAmount() {
  // Check for eligibility
  if (seniority < 2)
    return 0;
  if (monthsDisabled > 12)
    return 0;
  if (isPartTime)
    return 0;
  // Calculate disability amount and return it
}

While there’s nothing particularly wrong with this code, it’s not as maintainable as it could be. The getDisabilityAmount() method is really doing two things: checking the eligibility for disability, and then calculating the amount.

By now, you should know that violates the Single Responsibility Principle. We really should separate the code that handles eligibility requirements from the code that does disability calculations. So we can refactor this code to look more like this:

Now, if the eligibility requirements for disability change, only the isEligibleForDisability() methods needs to change—and the method responsible for calculating the disability amount doesn’t.

Think of refactoring as a checkup for your code. It should be an ongoing process, as code that is left alone tends to become harder and harder to reuse. Go back to old code, and refactor it to take advantage of new design techniques you’ve learned. The programmers who have to maintain and reuse your code will thank you for it.

Refactoring changes the internal structure of your code WITHOUT affecting your code’s behavior.

Appendix B. Welcome to Objectville: Speaking the Language of OO

Get ready to take a trip to a foreign country. It’s time to visit Objectville, a land where objects do just what they’re supposed to, applications are all well-encapsulated (you’ll find out exactly what that means shortly), and designs are easy to reuse and extend. But before we can get going, there are a couple of things you need to know first, and a few language skills you’re going to have to learn. Don’t worry, though, it won’t take long, and before you know it, you’ll be speaking the language of OO like you’ve been living in the well-designed areas of Objectville for years.

Welcome to Objectville

Whether this is your first trip to Objectville, or you’ve visited before, there’s no place quite like it. But things are a little different here, so we’re here to help you get your bearings before you dive into the main part of the book.

UML and class diagrams

We’re going to talk about classes and objects a lot in this book, but it’s pretty hard to look at 200 lines of code and focus on the big picture. So we’ll be using UML, the Unified Modeling Language, which is a language used to communicate just the details about your code and application’s structure that other developers and customers need, without getting details that aren’t necessary.

Sharpen your pencil

Write the skeleton for the Airplane class.

Using the class diagram above, see if you can write the basic skeleton for the Airplane class. Did you find anything that the class diagram leaves out? Write those things in the blanks below:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Sharpen your pencil answers

Write the skeleton for the Airplane class.

Using the class diagram in UML and class diagrams, you were supposed to write the basic skeleton for the Airplane class. Here’s what we did:

There are no Dumb Questions

Q:

Q: So the class diagram isn’t a very complete representation of a class, is it?

A:

A: No, but it’s not meant to be. Class diagrams are just a way to communicate the basic details of a class’s variables and methods. It also makes it easy to talk about code without forcing you to wade through hundreds of lines of Java, or C, or Perl.

Q:

Q: I’ve got my own way of drawing classes; what’s wrong with that?

A:

A: There’s nothing wrong with your own notation, but it can make things harder for other people to understand. By using a standard like UML, we can all speak the same language and be sure we’re talking about the same thing in our diagrams.

Q:

Q: So who came up with this UML deal, anyway?

A:

A: The UML specification was developed by Rational Software, under the leadership of Grady Booch, Ivar Jacobson, and Jim Rumbaugh (three really smart guys). These days it’s managed by the OMG, the Object Management Group.

Q:

Q: Sounds like a lot of fuss over that simple little class diagram thing.

A:

A: UML is actually a lot more than that class diagram. UML has diagrams for the state of your objects, the sequence of events in your application, and it even has a way to represent customer requirements and interactions with your system. And there’s a lot more to learn about class diagrams, too.

At this point, though, you just need the basics in UML and class diagrams. We’ll talk about other things you can show in a class diagram, and other types of diagrams, when we need them later in the book.

Next up: inheritance

One of the fundamental programming topics in Objectville is inheritance. That’s when one class inherits behavior from another class, and can then change that behavior if needed. Let’s look at how inheritance works in Java; it’s similar in other languages, too:

Note

Inheritance lets you build classes based on other classes, and avoid duplicating and repeating code.

Pool Puzzle

Your job is to take code snippets from the pool below and place them into the blank lines in the code you see on the right. You may use the same snippet more than once, and you won’t need to use all the snippets. Your goal is to create a class that will compile, run, and produce the output listed.

Output:

public class FlyTest {
  public static void main(String[] args) {
    Airplane biplane = new Airplane();
    biplane.setSpeed(_____);
    System.out.println(_________________);
    Jet boeing = new Jet();
    boeing.setSpeed(_____);
    System.out.println(________________);
    __________;
    while (______) {
      __________________;
      System.out.println(__________________);
      if (___________________ > 5000) {
        ________________(__________________ * 2);
      } else {
        ___________________;
      }
      _______;
    }
    System.out.println(__________________);
  }
}

Solution in Pool Puzzle Solution

And polymorphism, too...

Polymorphism is closely related to inheritance. When one class inherits from another, then polymorphism allows a subclass to stand in for the superclass.

There are no Dumb Questions

Q:

Q: What’s so useful about polymorphism?

A:

A: You can write code that works on the superclass, like Airplane, but will work with any subclass type, like Jet or Rocket. So your code is more flexible.

Q:

Q: I still don’t get how polymorphism makes my code flexible.

A:

A: Well, if you need new functionality, you could write a new subclass of Airplane. But since your code uses the superclass, your new subclass will work without any changes to the rest of our code! That means your code is flexible and can change easily.

Last but not least: encapsulation

Encapsulation is when you hide the implementation of a class in such a way that it is easy to use and easy to change. It makes the class act as a black box that provides a service to its users, but does not open up the code so someone can change it or use it the wrong way. Encapsulation is a key technique in being able to follow the Open-Closed principle. Suppose we rewrote our Airplane class like this:

Encapsulation is when you protect information in your code from being used incorrectly.

Now anyone can set the speed directly

This change means that the rest of your app no longer has to call setSpeed() to set the speed of a plane; the speed variable can be set directly. So this code would compile just fine:

So what’s the big deal?

Doesn’t seem like much of a problem, does it? But what happens if you create a Jet and set its speed like this:

Sharpen your pencil

What’s the value of encapsulating your data?

Type in, compile, and run the code for FlyTest3.java, shown above. What did your output look like? Write the two lines of output in the blanks below:

Speed of jet1: ________________

Speed of jet2: ________________

What do you think happened here? Write down why you think you got the speeds that you did for each instance of Jet:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Finally, summarize what you think the value of encapsulation is:

_____________________________________________________________________

_____________________________________________________________________

_____________________________________________________________________

Sharpen your pencil answers

What’s the value of encapsulating your data?

Type in, compile, and run the code for FlyTest3.java shown above. What did your output look like? Write the two lines of output in the blanks below:

Speed of jet1: _______212________

Speed of jet2: _______424________

What do you think happened here? Write down why you think you got the speeds that you did for each instance of Jet:

The Scholar’s Corner

Note

Taking a college class in programming? Here’s the official definition of encapsulation... if you’re taking an exam, this is the definition to use.

encapsulation. The process of enclosing programming elements inside larger, more abstract entities. Also known as information hiding, or separation of concerns.

There are no Dumb Questions

Q:

Q: So encapsulation is all about making all your variables private?

A:

A: No, encapsulation is about separating information from other parts of your application that shouldn’t mess with that information. With member variables, you don’t want the rest of your app directly messing with your data, so you separate that data by making it private. If the data needs to be updated, you can provide methods that work with the data responsibly, like we did with the Airplane class, using getSpeed() and setSpeed().

Q:

Q: So are there other ways to use encapsulation besides with variables?

A:

A: Absolutely. In fact, in Chapter 1, we’ll be looking at how you can encapsulate a group of properties away from an object, and make sure that the object doesn’t use those properties incorrectly. Even though we’ll deal with an entire set of properties, it’s still just separating a set of information away from the rest of your application.

Q:

Q: So encapsulation is really about protecting your data, right?

A:

A: Actually, it’s even more than that! Encapsulation can also help you separate behavior from other parts of your application. So you might put lots of code in a method, and put that method in a class; you’ve separated that behavior from the rest of your application, and the app has to use your new class and method to access that behavior. It’s the same principles as with data, though: you’re separating out parts of your application to protect them from being used improperly.

Q:

Q: Wow, I’m not sure I’m following all of this. What do I need to do?

A:

A: Just keep reading. Make sure you understand the exercise solutions in Sharpen your pencil answers, and you’re ready for Chapter 1. We’ll spend a lot more time on all of these OO principles and concepts, so don’t feel like you need to get everything down perfectly at this point.

Encapsulation separates your data from your app’s behavior.

Then you can control how each part is used by the rest of your application.

Bullet Points

UML stands for the Unified Modeling Language.

UML helps you communicate the structure of your application to other developers, customers, and managers.

A class diagram gives you an overview of your class, including its methods and variables.

Inheritance is when one class extends another class to reuse or build upon the inherited class’s behavior.

In inheritance, the class being inherited from is called the superclass; the class that is doing the inheritance is called the subclass.

A subclass gets all the behavior of its superclass automatically.

A subclass can override its superclass’s behavior to change how a method works.

Polymorphism is when a subclass “stands in” for its superclass.

Polymorphism allows your applications to be more flexible, and less resistant to change.

Encapsulation is when you separate or hide one part of your code from the rest of your code.

The simplest form of encapsulation is when you make the variables of your classes private, and only expose that data through methods on the class.

You can also encapsulate groups of data, or even behavior, to control how they are accessed.

OOA&D Cross

Take a moment to review the concepts in this appendix, and then you’re ready to step firmly into the world of analysis, design, OO programming, and great software.

Across

Down

3. This is when a subclass can substitute for its superclass.

4. Class diagrams don’t show details about this part of our class.

5. A class that inherits from another class is this.

6. Encapsulation lets you do this to information.

7. A class that is inherited from is called this.

1. Another term for encapsulation id separation of this.

2. Polymorphism helps make your code ____________.

4. Use this kind of diagram to avoid wading through lots of code.

Pool Puzzle Solution

Your job was to take code snippets from the pool below, and place them into the blank lines in the code you see on the right. You may use the same snippet more than once, and you won’t need to use all the snippets. Your goal was to create a class that will compile, run, and produce the output listed.

Output:

Exercise Solution

Index

A note on the digital index

A link in an index entry is displayed as the section title in which that entry appears. Because some sections have multiple index markers, it is not unusual for an entry to have several links to the same section. Clicking on any link will take you directly to the place in the text in which the marker appears.

Symbols

3DBoard, solving without inheritance , Solving the 3DBoard problem without using inheritance

A

abstract base class , Let’s put our design to the test, Finishing up Rick’s search tool

abstracting behavior , Behold: Rick’s new application

abstraction , But classes are really about behavior!

actors , But what is a feature, anyway?, Use case diagrams, Use case diagrams, Actors are people, too (well, not always)

aggregation , Let’s code Rick’s new search tool, Aggregation: composition, without the abrupt ending, Inheritance is just one option, #1. IS-A and HAS-A

versus composition , Aggregation versus composition

Airplane class , UML and class diagrams

alternate paths , Alternate paths handle system problems, It works! Let’s go show Todd and Gina...

dog door , Use cases have to make sense to you

dog door requirement changes , Use cases have to make sense to you

questions and answers , Start to finish: a single scenario

analysis , How to use this Book: Intro, Analysis: Taking Your Software into the Real World, The things you already know...

identifying problems , Identify the problem

planning solutions , Plan a solution

textual , Pay attention to the nouns in your use case

use cases and , Plan a solution

Analysis and Design Puzzle , Let’s see if our use case works, Focus on code, then focus on customers. Then focus on code, then focus on customers...

anonymous class , Automatically closing the door

anti patterns , #3. Anti patterns

architecturally significant features , But which of these are the most important?

architecture

defined , We need an architecture

purpose of , Which feature should we work on next?

three questions , The three Qs of architecture

Architecture Puzzle , Cubicle Argument Conversation

revisited , Cubicle Argument Conversation

solution , Cubicle Argument Conversation

array of arrays , Cubicle Argument Conversation

association , So how does recognize() work now?

attributes , So how does recognize() work now?

B

Bark object , Sam: object lover extraordinaire, Comparing barks

multiple , So what did Maria do differently?

BarkRecognizer class , Was that a “woof” I heard?, Power up the new dog door, Comparing barks

delegation , Delegation in Sam’s dog door: an in-depth look

questions and answers , Was that a “woof” I heard?

recognize() method , Delegation in Sam’s dog door: an in-depth look, So how does recognize() work now?

BarkRecognizer.java , Now we can start coding the dog door again, Was that a “woof” I heard?, Power up the new dog door

Don’t Repeat Yourself Principle , Principle #2: The Don’t Repeat Yourself Principle (DRY)

base classes, modifying , The OCP, step-by-step

Be the Browser , 3. How the “heck” do I do it?, 3. How the “heck” do I do it?, And still more order..., Writing test scenarios, Writing test scenarios

behavior

of subclasses , A closer look at the instrument classes

reusing from other classes , Inheritance is just one option

big problems

breaking into smaller pieces , It’s all in how you look at the big problem, Now divide and conquer, Now divide and conquer

looking at , It’s all in how you look at the big problem

versus little problems , Solving Really Big Problems: “My Name is Art Vandelay... I am an Architect”

Board class , Cubicle Argument Conversation, The Tile and Unit classes, Keep the right focus, And still more order...

boolean property versus numStrings property , Let’s make sure Inventory.java is (really) well-designed

Bullet Points , Working app, happy customers, More Tools for your OOA&D Toolbox, So how does recognize() work now?, The power of OOA&D (and a little common sense), Reducing risk helps you write great software, Inheritance is just one option, Your decisions can iterate down, too, So what’s the big deal?

C

cancel() method (TimerTask anonymous class) , Automatically closing the door

case diagrams, versus use cases , One use case, three parts

change , “What is CHANGE?”

constant in software development , The one constant in software analysis and design

changing requirements , The one constant in software analysis and design

checked exception , -or if they don’t trust you...

class diagrams , Ditching String comparisons, So how does recognize() work now?

abstract classes , Class diagrams dissected (again)

annotating guitar application , Let’s make sure Inventory.java is (really) well-designed

dissected , Class diagrams dissected

Guitar , Analyze the search() method

limitations , Class diagrams aren’t everything

subclasses , Class diagrams dissected (again)

UML and , UML and class diagrams

what’s missing , Class diagrams aren’t everything, So how does recognize() work now?

classes, protecting , What our equals() implementation does...

clear value , One use case, three parts, One use case, three parts, Working app, happy customers, Working app, happy customers

closed for modification , Principle #1: The Open-Closed Principle (OCP), Inheritance is just one option, Inheritance is just one option

code, robust , Ditching String comparisons

coding standards , #9. Coding standards and readable code

cohesion , Sweet! Our software is easy to change... but what about that “cohesive” thing?

collections , What we did: a closer look

common behavior , Behold: Rick’s new application

commonality , Commonality revisited, Do you know what “coordinating movement” means?, Scenario #3: Getting non-existent property values

commonality-focused solution , Let’s go with the commonality-focused solution

emphasizing , Solution #1: Emphasizing Commonality

commonality analysis , Commonality analysis: the path to flexible software, Do you know what “coordinating movement” means?

composition , Use composition to assemble behaviors from other classes, Inheritance is just one option, #1. IS-A and HAS-A

assembling behaviors from other classes , Use composition to assemble behaviors from other classes

ownership and , When the pizza is gone, so are the ingredients...

versus aggregation , Aggregation versus composition

when to use , When to use composition

Connection class , To use a Line class or not to use a Line class... that is the question, Code the Station class

constant in software analysis & design , The one constant in software analysis and design

context , Your software has a context

contract, programming by , Prove yourself to the customer

coordinating movement , Cubicle Argument Conversation, What does it mean? Ask the customer, Do you know what “coordinating movement” means?

CRC cards , #4. CRC cards

customer goal , (Re) introducing use cases

customers

listening to , Listen to the customer

satisfying , Great software is... more than just one thing

understanding customer’s requirements , Creating a requirements list

customer’s language , Cubicle Conversation

D

death of a design , Death of a design (decision)

Decorator Pattern

disadvantages , Working app, happy customers, Start to finish: a single scenario, Cubicle Argument Conversation, Cubicle Argument Conversation

interview , Working app, happy customers, Start to finish: a single scenario, Cubicle Argument Conversation, Cubicle Argument Conversation

defensive programming , But if you don’t trust your users...

delegation , Let’s make sure Inventory.java is (really) well-designed, Let’s make sure Inventory.java is (really) well-designed, The power of loosely coupled applications, Inheritance is just one option, Now start to iterate

3DBoard , Delegate functionality to another class

BarkRecognizer class , Delegation in Sam’s dog door: an in-depth look

DogDoor class (Sam’s) , Delegation in Sam’s dog door: an in-depth look

versus inheritance , When to use delegation

when to use , When to use delegation

design

death of a , Death of a design (decision)

preliminary , Developing software, OOA&D style

design lifecycle , Rick’s software, in review

design patterns , What’s the FIRST thing you’d change?, What’s the FIRST thing you’d change?, Rick’s customers want choices!, Getting ready for another test drive, OOA&D is about writing great software, not doing a bunch of paperwork!, OOA&D is about writing great software, not doing a bunch of paperwork!, Don’t forget who your customer really is, What’s a design pattern? And how do I use one?, What’s a design pattern? And how do I use one?, The power of OOA&D (and a little common sense), #3. Anti patterns

design principles , Design principle roundup, Principle #1: The Open-Closed Principle (OCP), The OCP, step-by-step, Contestant #4: The Liskov Substitution Principle (LSP), Inheritance is just one option

writing your own , A final test drive

Dessert interface , “What is CHANGE?”

DessertService class , “What is CHANGE?”

dog door

alternate paths , Use cases have to make sense to you

automatically closing , Automatically closing the door

barking focus , One of these things is not like the other...

coding changes in , Now we can start coding the dog door again

final test drive , A final test drive

main path , Use cases have to make sense to you

planning for things going wrong , Plan for things going wrong

single scenario , Start to finish: a single scenario

Todd and Gina’s Dog Door , DRY is really about ONE requirement in ONE place, Principle #3: The Single Responsibility Principle (SRP)

updating after analysis , Update your use case

where code should go for closing door , Power up the new dog door

Dog Door Class Diagram (Maria’s) , From good analysis to good classes...

DogDoor class , Test drive, Power up the new dog door

allowedBarks attribute , Class diagrams dissected

updating , Updating the dog door

DogDoor class (Sam’s) , Sam: object lover extraordinaire

delegation , Delegation in Sam’s dog door: an in-depth look

DogDoor.java , Let’s start with the dog door, Test drive, Now we can start coding the dog door again, Power up the new dog door, Updating the dog door, A final test drive

Don’t Repeat Yourself Principle , 1. Let’s abstract out the common code

gathering requirements , But when Gina tried it...

test drive , Test drive

second , We need a new simulator!

DogDoorSimulator class , Test drive, Power up the new dog door

updating , Power up the new dog door

DogDoorSimulator.java , Test drive, We need a new simulator!, Reviewing the alternate path, Now we can start coding the dog door again, Power up the new dog door, Power up the new dog door, So how does recognize() work now?

code magnets , Reviewing the alternate path, Test drive, version 2.1

test drive , Test drive, version 2.1

domain analysis , Cubicle Conversation, Don’t forget who your customer really is, Feeling a little bit lost?, The power of OOA&D (and a little common sense), Developing software, OOA&D style

Don’t Repeat Yourself Principle (see DRY)

double encapsulation , “Double encapsulation” in Rick’s software

DRY (Don’t Repeat Yourself Principle) , Principle #2: The Don’t Repeat Yourself Principle (DRY)

main idea , DRY is really about ONE requirement in ONE place

E

encapsulate what varies , The one constant in software analysis and design

encapsulation , Analyze the search() method, Getting ready for another test drive, OOA&D is about writing great software, not doing a bunch of paperwork!, “What is ENCAPSULATION?”, “What is CHANGE?”, But classes are really about behavior!, But classes are really about behavior!, The things you already know..., Now start to iterate, Last but not least: encapsulation, So what’s the big deal?

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

double , “Double encapsulation” in Rick’s software

emphasizing , Solution #2: Emphasizing Encapsulation

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

OCP and , The OCP, step-by-step

questions and answers , Now update your own code

enumerated types , Ditching String comparisons

enums , Ditching String comparisons

equals()

Java’s default , Points of interest on the Objectville Subway (class)

overriding , Code the Station class

RouteFinder , Points of interest on the Objectville Subway (class)

essence of a system , The three Qs of architecture, 3. How the “heck” do I do it?

external initiator , One use case, three parts, One use case, three parts, Working app, happy customers, Working app, happy customers, Working app, happy customers, Working app, happy customers

F

feature analysis , Analysis of a feature

feature driven development , Iterating deeper: two basic choices, Feature driven development, Let’s use feature driven development, Your decisions can iterate down, too, Your decisions can iterate down, too

versus use case driven development , Two approaches to development

feature lists , Developing software, OOA&D style, Now you should really know what you’re supposed to do

Feature Magnets

RouteFinder feature list , Now you should really know what you’re supposed to do

Feature Puzzle , Your decisions can iterate down, too

solutions , Your decisions can iterate down, too

features , Figure out the features

architecturally significant , But which of these are the most important?

interpreting , What does it mean? Ask the customer

mapping to use case diagrams , Use case diagrams, Use case diagrams

versus requirements , But what is a feature, anyway?

versus use cases , Use cases reflect usage, features reflect functionality, Use cases reflect usage, features reflect functionality

Final CATASTROPHE! , “What is CHANGE?”

FindGuitar class , Getting ready for another test drive

FindGuitar.java

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

FindInstrument.java , But does the application actually work?, But does the application actually work?

initializeInventory() method , Test driving Rick’s well-designed software

test driving , Test driving Rick’s well-designed software, Rick’s got working software, his client has three choices

flexibility , Getting ready for another test drive, OOA&D is about writing great software, not doing a bunch of paperwork!, OOA&D is about writing great software, not doing a bunch of paperwork!, The OCP, step-by-step

interfaces and , “What is an INTERFACE?”

versus functionality , Focus on code, then focus on customers. Then focus on code, then focus on customers...

fragile , Ditching String comparisons

Friedman, Dan , A small Socratic exercise in the style of The Little Lisper

functionality , Getting ready for another test drive, OOA&D is about writing great software, not doing a bunch of paperwork!, Feeling a little overwhelmed?, Let’s start with functionality, But which of these are the most important?, Cubicle Argument Conversation, Cubicle Argument Conversation, And still more order..., Reducing risk helps you write great software, Reducing risk helps you write great software, Use cases reflect usage, features reflect functionality

breaking applications into smaller chunks of , Break your apps up into smaller chunks of functionality

versus flexibility , Focus on code, then focus on customers. Then focus on code, then focus on customers...

G

game system framework (GSF) , So let’s solve a BIG problem!

game-specific units , Game-specific units... what does that mean?

Gary’s Game System Framework

coordinating game movement , And still more order...

feature list , So what exactly have we done?, Feeling a little overwhelmed?, Let’s start with functionality

determining significance , 3. How the “heck” do I do it?, 3. How the “heck” do I do it?

key features , We’ve got a lot less chaos now..., More order, less chaos, And still more order..., Reducing risk helps you write great software

risk , Cubicle Argument Conversation

Gary’s Games

customer conversations , Customer Conversation

features , Figure out the features

vision statement , So let’s solve a BIG problem!

getNumStrings() method (GuitarSpec.java) , Let’s make sure Inventory.java is (really) well-designed, Let’s make sure Inventory.java is (really) well-designed

good enough software , Rick’s software, in review

graph structure , To use a Line class or not to use a Line class... that is the question

great software

3 steps to , Finishing up Rick’s search tool, Finishing up Rick’s search tool

consistently writing , Remember this poor guy?

satisfying customers , Great software is... more than just one thing

three easy steps , Great software in 3 easy steps

what does this mean? , What’s the FIRST thing you’d change?

Guitar class diagram , Analyze the search() method

Guitar.java

adding class for mandolins , Let’s code Rick’s new search tool

encapsulating properties of GuitarSpec , Let’s make sure Inventory.java is (really) well-designed

GuitarSpec class , Analyze the search() method, Let’s code GuitarSpec...

adding property to , Let’s make sure Inventory.java is (really) well-designed

encapsulating properties of , Let’s make sure Inventory.java is (really) well-designed

questions and answers , Now update your own code

GuitarSpec.java

adding new property , Let’s make sure Inventory.java is (really) well-designed

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

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

H

HAS-A , #1. IS-A and HAS-A

hashCode( ), overriding , Code the Station class

Head First Labs website , Ditching String comparisons

Head First learning principles , And we know what your brain is thinking

I

implementation , Developing software, OOA&D style

inheritance , But classes are really about behavior!, The OCP, step-by-step, #1. IS-A and HAS-A, Next up: inheritance

alternatives , Solving the 3DBoard problem without using inheritance, Inheritance is just one option

hidden structure problems , LSP reveals hidden problems with your inheritance structure

misusing , Misusing subclassing: a case study in misusing inheritance

versus delegation , When to use delegation

(see also LSP)

Instrument abstract base class , Did you notice that abstract base class?

instrument application

ease-of-change challenge , Rick’s got working software, his client has three choices

Instrument class

adding new subclasses , Uh oh... adding new instruments is not easy!

completed class diagram , Did you notice that abstract base class?

extending , Let’s code Rick’s new search tool

updated , Using the new Instrument and InstrumentSpec classes

instrument-specific subclasses

killing , Let’s turn some bad design decisions into good ones

Instrument.java , Let’s code Rick’s new search tool

InstrumentSpec , We’ll need a MandolinSpec class, too

creating abstract class for , Create an abstract class for instrument specifications

making concrete class , A closer look at the search() method

matches( ) method , Remember working on Rick’s Stringed Instruments?

InstrumentSpec class

updated , Using the new Instrument and InstrumentSpec classes

InstrumentSpec.java , Create an abstract class for instrument specifications

InstrumentType enum , Finishing up Rick’s app: the InstrumentType enum

InstrumentType.java , Finishing up Rick’s app: the InstrumentType enum

interface , “What is an INTERFACE?”, “What is ENCAPSULATION?”, “What is CHANGE?”, “What is CHANGE?”

coding to an , The things you already know...

Inventory class , Update the Inventory class

addInstrument() method , A closer look at the instrument classes

updating , Finishing up Rick’s app: the InstrumentType enum

updating to work with multiple instrument types , Finishing up Rick’s search tool

Inventory Roundup , But does the application actually work?

solutions , Test driving Rick’s well-designed software

Inventory.java , Finishing up Rick’s search tool, Finishing up Rick’s app: the InstrumentType enum

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

search( ) method , Let’s make sure Inventory.java is (really) well-designed, Let’s make sure Inventory.java is (really) well-designed, Let’s make sure Inventory.java is (really) well-designed, A closer look at the search() method

IS-A , #1. IS-A and HAS-A

iterating over all choices (guitar application) , Test drive

iterative design , Now start to iterate, The SubwayLoader class, Iteration makes problems easier

iterative development , Your decisions can iterate down, too, Developing software, OOA&D style

J

Java’s default equals() , Points of interest on the Objectville Subway (class)

L

Line class , To use a Line class or not to use a Line class... that is the question

Liskov Substitution Principle (see LSP)

LoadTester class , The SubwayLoader class

loosely coupled , The power of loosely coupled applications

LSP (Liskov Substitution Principle) , Contestant #4: The Liskov Substitution Principle (LSP), Aggregation: composition, without the abrupt ending

hidden structure problems , LSP reveals hidden problems with your inheritance structure

violating , Violating the LSP makes for confusing code

M

main path , Working app, happy customers, Working app, happy customers, Working app, happy customers

dog door , Use cases have to make sense to you

Mandolin.java , Let’s code Rick’s new search tool

MandolinSpec class , Let’s put our design to the test, We’ll need a MandolinSpec class, too, Behold: Rick’s new application, ... and MandolinSpec, too

MandolinSpec.java , ... and MandolinSpec, too

Map for storing properties , Using the new Instrument and InstrumentSpec classes, Using the new Instrument and InstrumentSpec classes

Method Magnets , The SubwayLoader class

solutions , The SubwayLoader class

metrics , #5. Metrics

mismatched object type , Analyze the search() method

Model-View-Controller pattern (see MVC pattern)

multiplicity , So what did Maria do differently?, Class diagrams dissected, So how does recognize() work now?

MVC pattern , What’s a design pattern? And how do I use one?

N

noun analysis , So how does recognize() work now?

nouns in use cases , Pay attention to the nouns in your use case, Remember: pay attention to those nouns!

numStrings property (GuitarSpec.java) , Let’s make sure Inventory.java is (really) well-designed, Let’s make sure Inventory.java is (really) well-designed

numStrings property versus boolean property , Let’s make sure Inventory.java is (really) well-designed

O

Object Oriented Design Principles , A final test drive

Object-Oriented Analysis & Design (see OOA&D)

objects

concepts , Analyze the search() method

forwarding operation to another object , Let’s make sure Inventory.java is (really) well-designed

naming , Analyze the search() method

Objectville Subway Map , The problem

ObjectvilleSubway.txt file , The SubwayLoader class

OCP (Open-Closed Principle) , OOA&D is about writing great software, not doing a bunch of paperwork!, Principle #1: The Open-Closed Principle (OCP), Contestant #4: The Liskov Substitution Principle (LSP), Inheritance is just one option, Inheritance is just one option

step-by-step , The OCP, step-by-step

OO CATASTROPHE! , “What is an INTERFACE?”

OO Cross , So what’s the big deal?

OO Principles , “What is CHANGE?”

OOA&D (Object-Oriented Analysis & Design) , Remember this poor guy?, OOA&D is about writing great software, not doing a bunch of paperwork!, OOA&D is about writing great software, not doing a bunch of paperwork!

power of , The power of OOA&D (and a little common sense)

process overview , Developing software, OOA&D style

OOA&D Cross , OOA&D is about writing great software, not doing a bunch of paperwork!, Working app, happy customers, More Tools for your OOA&D Toolbox, So how does recognize() work now?, Knowing when to say “It’s good enough!”, The power of OOA&D (and a little common sense), Reducing risk helps you write great software, Inheritance is just one option, Your decisions can iterate down, too, Allow different output sources (and formats!)

OOA&D Magnets , Developing software, OOA&D style, Check out Objectville for yourself!

solutions , Check out Objectville for yourself!

OOA&D Toolbox , Knowing when to say “It’s good enough!”, The power of OOA&D (and a little common sense), Inheritance is just one option, Your decisions can iterate down, too

more tools for , More Tools for your OOA&D Toolbox

tools , Working app, happy customers

open for extension , Principle #1: The Open-Closed Principle (OCP), Remember working on Rick’s Stringed Instruments?, The OCP, step-by-step, Inheritance is just one option, Inheritance is just one option

Open-Closed Principle (see OCP)

operation , So how does recognize() work now?

optional paths , Use cases have to make sense to you

P

Painter class , “What is ENCAPSULATION?”

Patterns Exposed , Working app, happy customers, Start to finish: a single scenario, Cubicle Argument Conversation, Cubicle Argument Conversation

placeholders , Did you notice that abstract base class?

planning for things going wrong , Plan for things going wrong

polymorphism , But classes are really about behavior!, And polymorphism, too...

pressButton() , How to use this Book: Intro, Power up the new dog door, Updating the dog door

programming

by contract , Prove yourself to the customer, -or if they don’t trust you...

versus defensive programming , -or if they don’t trust you...

defensively , But if you don’t trust your users..., -or if they don’t trust you...

properties

storing , Getting dynamic with instrument properties, What we did: a closer look, Using the new Instrument and InstrumentSpec classes

that vary across objects , What we did: a closer look

unused , Analyze the search() method

protecting classes , What our equals() implementation does...

R

readable code , #9. Coding standards and readable code

refactoring , #10. Refactoring

relationships , We need an architecture, But which of these are the most important?, Cubicle Argument Conversation, Which feature should we work on next?, Game-specific units... what does that mean?

Remote class , Let’s start with the dog door, Test drive, Power up the new dog door

automatically closing door , Automatically closing the door

code magnet solutions , Working app, happy customers

remote control

simplifying , Updating the dog door

Remote.java , Test drive, Power up the new dog door, A final test drive

Don’t Repeat Yourself Principle , Principle #2: The Don’t Repeat Yourself Principle (DRY)

requirements , Working app, happy customers, Working app, happy customers, Developing software, OOA&D style

changes , How to use this Book: Intro, Requirements Change: I Love You, You’re Perfect... Now Change

changes in use cases , Let’s get ready to code...

checking against use cases , Checking your requirements against your use cases

creating list of , Creating a requirements list, What does the dog door really need to do?

defined , But when Gina tried it...

gathering , How to use this Book: Intro, Gathering Requirements: Give Them What They Want

good , What does the dog door really need to do?, More Tools for your OOA&D Toolbox, The things you already know...

list , So now can we write some code?

list for changes to dog door , Finishing up the requirements list

list, checking , Was that a “woof” I heard?

questions and answers , What does the dog door really need to do?

versus features , But what is a feature, anyway?

requirements list , So let’s solve a BIG problem!

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

reusable design , Design once, design twice

Rick’s Search Tool , Rick’s shiny new application...

download , Getting ready for another test drive

encapsulation , Analyze the search() method

iterating over all choices , Test drive

looking deeper for problems , Looking for problems

making well-designed and flexible , Back to Rick’s search tool

mismatched object type , Analyze the search() method

problems with , But then Rick started losing customers...

revisiting problems , Remember Rick? Remember his lost customers?

String comparisons , Ditching String comparisons

search( ) method , Rick’s customers want choices!, Rick’s customers want choices!

analyzing , Analyze the search() method

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

risk , Cubicle Argument Conversation, Cubicle Argument Conversation

reducing , Keep the right focus, Commonality analysis: the path to flexible software, Reducing risk helps you write great software

use cases and , Cubicle Argument Conversation

robust code , Ditching String comparisons

RouteFinder , The problem

back to requirements phase , Back to the requirements phase...

breaking into modules , Use cases reflect usage, features reflect functionality, Use cases reflect usage, features reflect functionality

closer look at representing a subway , A closer look at representing a subway

coding

Station class , Code the Station class

Connection class , To use a Line class or not to use a Line class... that is the question, Code the Station class

different output sources , Iteration #3, anyone?

feature list , What’s left to do?

getDirections() method , What does a route look like?

iterative design , Now start to iterate, The SubwayLoader class, Iteration makes problems easier

Line class , To use a Line class or not to use a Line class... that is the question

LoadTester class , The SubwayLoader class

more extensible loading , Iteration #3, anyone?

statement of work , The problem

Station class , To use a Line class or not to use a Line class... that is the question

Subway class , To use a Line class or not to use a Line class... that is the question

coding , Code the Station class

equals( ) , Points of interest on the Objectville Subway (class)

hashCode( ) , Points of interest on the Objectville Subway (class)

subway file , Let’s take a look at that subway file

SubwayLoader class , The SubwayLoader class

SubwayPrinter class , What does a route look like?

SubwayTester class , One last test class...

textual analysis , Let’s see if our use case works

RuntimeException , -or if they don’t trust you...

S

satisfying customers , Great software is... more than just one thing

scenarios , (Re) introducing use cases

Board interface , Cubicle Argument Conversation, Cubicle Argument Conversation

questions and answers , Start to finish: a single scenario

risk and , Cubicle Argument Conversation

single, for dog door , Start to finish: a single scenario

search( ) method (guitar application) , Rick’s customers want choices!, Rick’s customers want choices!

analyzing , Analyze the search() method

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

seeing the big picture , But what is a feature, anyway?

sequence diagrams , #6. Sequence diagrams

Sharpen your pencil

adding support for mandolins to search tool , Let’s put our design to the test

answers , Let’s put our design to the test

analysis , Plan a solution

answers , Plan a solution

annotating guitar application class diagram , Let’s make sure Inventory.java is (really) well-designed, Let’s make sure Inventory.java is (really) well-designed

breaking RouteFinder into modules , Use cases reflect usage, features reflect functionality

Connection class , Code the Station class

answers , Code the Station class

design principle , A final test drive

designing test cases , Test cases dissected...

answers , Test cases dissected...

Dog class, not including , Focus: owner’s dog’s bark

answers , Remember: pay attention to those nouns!

dog door requirements , Creating a requirements list

DogDoor class

allowedBarks attribute , Class diagrams dissected, Class diagrams dissected

drawing class diagram for updated instrument application , Let’s update Inventory, too

game-specific units , Game-specific units... what does that mean?

answers , Game-specific units... what does that mean?

Gary’s Game System Framework

most important features , But which of these are the most important?

Gary’s Games features , But what is a feature, anyway?, Use case diagram... check! Features covered... check!

answers , Figure out the features, Use case diagram... check! Features covered... check!

Gary’s Games, things to do first , So let’s solve a BIG problem!

great software , What’s the FIRST thing you’d change?

guitar application , But then Rick started losing customers..., Ditching String comparisons

GuitarSpec object , Analyze the search() method, Analyze the search() method

instrument-specific subclasses , The benefits of our analysis, The benefits of our analysis

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

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

OCP, finding in your project , The OCP, step-by-step

OO principles , But classes are really about behavior!

answers , But classes are really about behavior!

potential Unit properties , Scenario #3: Getting non-existent property values

answers , Scenario #3: Getting non-existent property values

power of use cases , Working app, happy customers

reasons requirements might change , The one constant in software analysis and design

requirements for dog door , Is anything missing?

answers , Is anything missing?

risk , Cubicle Argument Conversation

rodents getting into kitchen , But when Gina tried it...

RouteFinder feature list , The problem

answers , The problem

scenario testing , Power up the new dog door

answers , Power up the new dog door

scenarios in use cases , Start to finish: a single scenario

answers , Start to finish: a single scenario

skeleton for Airplane class , UML and class diagrams

answers , UML and class diagrams

SRP, applying to automobile class , Spotting multiple responsibilities

answers , Spotting multiple responsibilities

structure for RouteFinder code , Now you should really know what you’re supposed to do

answers , Now you should really know what you’re supposed to do

Unit class programming contract , -or if they don’t trust you...

answers , -or if they don’t trust you...

use case for Get directions , Back to the requirements phase...

use case for loading subway lines , Now start to iterate, Let’s take a look at that subway file

answers , Now start to iterate, Let’s take a look at that subway file

use case nouns , Pay attention to the nouns in your use case

answers , Pay attention to the nouns in your use case

use case to store a bark , Update your use case

answers , Update your use case

use cases , Working app, happy customers

real power of , Working app, happy customers

real power of, solution , Working app, happy customers

writing more , Working app, happy customers

value of encapsulating your data , So what’s the big deal?

answers , So what’s the big deal?

writing code based on class diagram , Sam: object lover extraordinaire

answers , Sam: object lover extraordinaire

software

good enough , Rick’s software, in review

great (see great software)

well-designed , Finishing up Rick’s search tool

software release , Developing software, OOA&D style

software, great , The things you already know...

solutions, questions and answers , Plan a solution

SRP (Single Responsibility Principle) , OOA&D is about writing great software, not doing a bunch of paperwork!, Principle #3: The Single Responsibility Principle (SRP), Now start to iterate

analysis , Spotting multiple responsibilities

going from multiple to single , Going from multiple responsibilities to a single responsibility

SRP Analysis

CRC cards and , CRC cards help implement the SRP

SRP Sightings , Going from multiple responsibilities to a single responsibility

answers , Going from multiple responsibilities to a single responsibility

start condition , Working app, happy customers, Working app, happy customers

state machine diagrams , #7. State diagrams

statechart diagram , #7. State diagrams

Station class , To use a Line class or not to use a Line class... that is the question

coding , Code the Station class

String comparisons , Ditching String comparisons

Style.java , ... and MandolinSpec, too

subclasses

adding new instruments , Uh oh... adding new instruments is not easy!

behavior of , A closer look at the instrument classes

behavior versus properties , But classes are really about behavior!

instrument-specific

killing , Let’s turn some bad design decisions into good ones

misusing , Misusing subclassing: a case study in misusing inheritance

standing in for superclass , And polymorphism, too...

versus abstract base classes , Did you notice that abstract base class?

subtype must be substitutable for its base type , “Subtypes must be substitutable for their base types”

Subway class , To use a Line class or not to use a Line class... that is the question

coding , Code the Station class

equals( ) , Points of interest on the Objectville Subway (class)

hashCode( ) , Points of interest on the Objectville Subway (class)

Subway.java

implementation , Implementation: Subway.java

SubwayLoader class , The SubwayLoader class

making sure correctly loads in all stations and connections , The SubwayLoader class

SubwayPrinter class , What does a route look like?

SubwayTester class , One last test class...

system boundary , Use case diagrams

T

terrain types , Now divide and conquer

test cases , Test cases dissected..., Your decisions can iterate down, too, What a test case looks like

test driven development , Scenario #3: Getting non-existent property values

Test Puzzle , Test cases dissected..., The SubwayLoader class

solution , The SubwayLoader class

solutions , Test cases dissected...

test scenarios

Unit class , Writing test scenarios

textual analysis , Pay attention to the nouns in your use case, Focus: owner’s dog’s bark, Focus: owner’s dog’s bark, So how does recognize() work now?, Let’s see if our use case works

code magnets , Remember: pay attention to those nouns!

solution , Remember: pay attention to those nouns!

The Little Lisper , A small Socratic exercise in the style of The Little Lisper

There are no Dumb Questions

advanced OO techniques , OO CATASTROPHE: Objectville’s Favorite Quiz Show

aggregation , Inheritance is just one option

alternate paths , Start to finish: a single scenario

array of arrays , Cubicle Argument Conversation

BarkRecognizer class , Was that a “woof” I heard?

class diagrams , Ditching String comparisons, UML and class diagrams

cohesion , Cohesion, and one reason for a class to change

commonality , Scenario #3: Getting non-existent property values

commonality versus variability , It’s “different for every game”

composition , Inheritance is just one option

deciding between design choices , Let’s go with the commonality-focused solution

defensive programming , -or if they don’t trust you...

delegation , Let’s make sure Inventory.java is (really) well-designed, Inheritance is just one option

DessertService class , “What is CHANGE?”

Don’t Repeat Yourself Principle , DRY is really about ONE requirement in ONE place

encapsulation , Now update your own code, Getting ready for another test drive, So what’s the big deal?

enumerated types , Ditching String comparisons

equals( ) , Points of interest on the Objectville Subway (class)

essence of a system , 3. How the “heck” do I do it?

features versus requirements , But what is a feature, anyway?, The problem

fewer classes and flexibility , Using the new Instrument and InstrumentSpec classes

FindInstrument.java, getting different results , Rick’s got working software, his client has three choices

hasConnection() method , The SubwayLoader class

holding off writing code , And still more order...

inheritance , Inheritance is just one option

Instrument class , Finishing up Rick’s search tool

making Instrument abstract , We’ll need a MandolinSpec class, too

matching up every feature to a use case , Use cases reflect usage, features reflect functionality

multiple solutions , Plan a solution

nouns and verbs in use cases , Remember: pay attention to those nouns!

OCP , The OCP, step-by-step

options , Check out Objectville for yourself!

polymorphism , And polymorphism, too...

programming by contract , -or if they don’t trust you...

reducing risk , Commonality analysis: the path to flexible software

repeated steps in use case , To use a Line class or not to use a Line class... that is the question

requirements , What does the dog door really need to do?

RuntimeException , -or if they don’t trust you...

scenarios , Start to finish: a single scenario

Single Responsibility Principle , Principle #3: The Single Responsibility Principle (SRP)

SRP analysis , Going from multiple responsibilities to a single responsibility

steps in coding , Rick’s customers want choices!

subclassing , Inheritance is just one option

test cases , Test cases dissected...

test driven development , Scenario #3: Getting non-existent property values

textual context , Focus: owner’s dog’s bark

Tile and Unit classes , Keep the right focus

Timer class , Automatically closing the door

UML , Class diagrams dissected (again)

unit testing , #8. Unit testing

use case diagrams , Use case diagrams

use cases , One use case, three parts

use cases for storing a bark , Update your use case

uses cases and risk , Cubicle Argument Conversation

validation , Let’s take a look at that subway file

Thread class, using to close door , Automatically closing the door

Tile class , The Tile and Unit classes, Keep the right focus

Tile.java , The Tile and Unit classes

tiles , Now divide and conquer

time periods , Now divide and conquer

Timer class

using to close door , Automatically closing the door

TimerTask anonymous class

cancel() method , Automatically closing the door

U

UML and class diagrams , UML and class diagrams

UML Cheat Sheet , Class diagrams dissected (again)

UML diagrams , From good analysis to good classes..., Class diagrams dissected

Unit class , The Tile and Unit classes, Keep the right focus, Fleshing out the Unit class

class diagram , Scenario #3: Getting non-existent property values

matching tests to design , Match your tests to your design

programming by contract , We’ve been programming by contract so far

test scenarios , Writing test scenarios

writing , Let’s write the Unit class

unit testing , #8. Unit testing

Unit.java , The Tile and Unit classes

UnitGroup class , Your decisions can iterate down, too

units , Now divide and conquer

finding what is common between , Commonality revisited

game-specific (see game-specific units)

moving , Moving units

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

use case diagrams , Use case diagrams, So what exactly have we done?, Developing software, OOA&D style, Now you should really know what you’re supposed to do

mapping features to , Use case diagrams

use case driven development , Iterating deeper: two basic choices, Use case driven development, Your decisions can iterate down, too, Your decisions can iterate down, too

versus driven development , Two approaches to development

use cases , Alternate paths handle system problems, So let’s solve a BIG problem!

analysis and , Plan a solution

changes and requirements , Let’s get ready to code...

checking against requirements , Checking your requirements against your use cases

clear value , One use case, three parts

definite starting and stopping point , One use case, three parts

exposed , Working app, happy customers, Start to finish: a single scenario

external initiator , One use case, three parts

formats , #2. Use case formats

Get directions , Back to the requirements phase...

answers , Back to the requirements phase...

identifying classes to use , It’s all about the use case

Load network of subway lines , The SubwayLoader class

loading subway lines , Let’s take a look at that subway file

checking flow , Let’s take a look at that subway file

magnets , One use case, three parts, Working app, happy customers

solution , One use case, three parts, Working app, happy customers

nouns , Pay attention to the nouns in your use case, Remember: pay attention to those nouns!

questions and answers , One use case, three parts

real power of , Working app, happy customers

risk and , Cubicle Argument Conversation

seeing the big picture , But what is a feature, anyway?

storing a bark , Update your use case

three parts , One use case, three parts

updating after analysis , Update your use case

verbs , Remember: pay attention to those nouns!

versus case diagrams , One use case, three parts

versus features , Use cases reflect usage, features reflect functionality

writing so not confusing , Use cases have to make sense to you

V

validation , Let’s take a look at that subway file

variability , Commonality revisited, Solution #1: It’s all different!, Solution #2: It’s all the same!, Scenario #3: Getting non-existent property values, Scenario #3: Getting non-existent property values, Scenario #3: Getting non-existent property values

verb analysis , So how does recognize() work now?

verbs in use cases , Remember: pay attention to those nouns!

vision statement , So let’s solve a BIG problem!, So let’s solve a BIG problem!

W

Weapon interface , Use composition to assemble behaviors from other classes

well-designed software , Finishing up Rick’s search tool

Who Am I? , Inheritance is just one option, -or if they don’t trust you...

solutions , Inheritance is just one option, Your decisions can iterate down, too

About the Authors

Brett McLaughlin is a bestselling and award-winning non-fiction author. His books on computer programming, home theater, and analysis and design have sold in excess of 100,000 copies. He has been writing, editing, and producing technical books for nearly a decade, and is as comfortable in front of a word processor as he is behind a guitar, chasing his two sons and his daughter around the house, or laughing at reruns of Arrested Development with his wife.

Brett spends most of his time these days on cognitive theory, codifying and expanding on the learning principles that shaped the Head First series into a bestselling phenomenon. He's curious about how humans best learn, why Star Wars was so formulaic and still so successful, and is adamant that a good video game is the most effective learning paradigm we have.

Gary Pollice is a self-labeled curmudgeon (that's a crusty, ill- tempered, usually old man) who spent over 35 years in industry trying to figure out what he wanted to be when he grew up. Even though he hasn't grown up yet, he did make the move in 2003 to the hallowed halls of academia where he has been corrupting the minds of the next generation of software developers with radical ideas like, "develop software for your customer, learn how to work as part of a team, design and code quality and elegance and correctness counts, and it's okay to be a nerd as long as you are a great one." Gary is also a co-author of Head First Object-Oriented Analysis and Design.Gary is a Professor of Practice (meaning he had a real job before becoming a professor) at Worcester Polytechnic Institute. He went to WPI because he was so impressed with the WPI graduates that he's worked with over the years. He lives in central Massachusetts with his wife, Vikki, and their two dogs, Aloysius and Ignatius. When not working on geeky things he ... well he's always working on geeky things. You can see what he's up to by visiting his WPI home page at http://web.cs.wpi.edu/~gpollice/. Feel free to drop him a note and complain or cheer about the book.

Dave West would like to describe himself as sheik geek. Unfortunately no one else would describe him in that way. They would say he is a professional Englishman who likes to talk about software development best practices with the passion and energy of an evangelical preacher. Recently Dave has moved to Ivar Jacobson Consulting, where he runs the Americas and can combine his desire to talk about software development and spread the word on rugby and football, and argue that cricket is more exciting that baseball.Before running the Americas for Ivar Jacobson Consulting, Dave worked for a number of years at Rational Software (now a part of IBM). Dave held many positions at Rational and then IBM, including Product Manager for RUP where he introduced the idea of process plug-ins and agility to RUP. Dave still laments the days when he use to sit in a cube and write software in the city of London. This is where he believes he cut his teeth writing big insurance systems with nothing but a green screen and a process flow chart.

Dave can be contacted at dwest@ivarjacobson.com, and if he is not with customers or drinking warm beer with his friends in Boston, he will email you back.

Head First Object-Oriented Analysis and Design

Brett McLaughlin

Gary Pollice

David West

Editor

Mary Treseler

Copyright © 2009 Bert Bates and Kathy Sierra

Head First Object-Oriented Analysis and Design

by Brett D. McLaughlin, Gary Pollice, and David West

All rights reserved.

O’Reilly Media books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (safari.oreilly.com). For more information, contact our corporate/institutional sales department: (800) 998-9938 or corporate@oreilly.com.

Series Creators:

Kathy Sierra, Bert Bates

Series Editor:

Brett D. McLaughlin

Editor:

Mary O’Brien

Cover Designer:

Mike Kohnke, Edie Freedman

OO:

Brett D. McLaughlin

A:

David West

D:

Gary Pollice

Page Viewer:

Dean and Robbie McLaughlin

Printing History:

November 2006: First Edition.

The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. The Head First series designations, Head First OOA&D, and related trade dress are trademarks of O’Reilly Media, Inc.

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trademark claim, the designations have been printed in caps or initial caps.

While every precaution has been taken in the preparation of this book, the publisher and the authors assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.

In other words, if you use anything in Head First OOA&D to, say, write code that controls an American space shuttle, you’re on your own.

No dogs, rabbits, or woodchucks were harmed in the making of this book, or Todd and Gina’s dog door.

This book uses RepKover™, a durable and flexible lay-flat binding.

[M]

O’Reilly Media

1005 Gravenstein Highway North

Sebastopol, CA 95472

2014-07-08T09:51:30-07:00