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.
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.
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.
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.
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.
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?
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?
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...
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).
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.
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.
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...
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?
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.
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.
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.
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.
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.
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.
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.
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.
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?
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! |
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?
With a new actor in place, we can finally take our use case diagrams and our features, and match them all up.
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.
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 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.
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.
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.
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.
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.
We’ve done a lot of things in this chapter, and some of them don’t even seem to be related...
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.