An Indepth Look into Analysis and Design
- When to Spend Time on Design
- Design Methodologies
- User Interface Design
- What's Next?
Chapter 2 Design Fundamentals
Now that some of the fundamentals are out of the way, it is time to start on the main focus of this book: the Stock Tracker Application. By building a relatively large project throughout the book, you will learn not only the syntax and semantics of the Java programming language, but the entire project lifecycle from requirements to design to implementation and testing.
Syntax--The proper use of terms and punctuation
Semantics--The meaning and purpose of the code
In this chapter, I hope to show you the benefits of requirements gathering, as well as the importance of a good up-front design. Then, I will show you some of the tools that are used for design and give you some examples that you will begin to apply to this project in the next chapter and that you will be able to apply to your own projects in the future.
When to Spend Time on Design
Some programmers spend an incredible amount of time designing their applications, but others spend no time at all. Which is right?
The answer is: it depends on the project. From my perspective and experience, design should always be performed. The only limiting factor is the amount of time spent on the design; the amount of time is directly related to the size of the project. Now, before you start shouting at me for the "Hello, world" program in the last chapter, I will concede that some programs are too simple to spend time designing. However, it is a good idea to sit down and at least figure out how you are going to write your program before you start writing it.
You may be unclear as to what designing an application includes, but to make things simple, design includes figuring out how you are going to solve a problem before solving it. By designing a project, you will learn much more about it than if you were to sit down with an empty text editor and start coding.
Design has three important effects on your project:
First, before you start writing your program, you must be sure that you have made provisions for all the program's requirements. Too often, when writing a program, you forget a feature or two and then when you finally realize it, your program has to be completely rewritten to support them. Take the case of writing a system to handle all the shipping needs for a small company. You sit down and write a program that can handle single items coming in one at a time along a conveyor belt, and you properly update the database to reflect the new quantities. You test this and everything works great. Later you find out that sometimes multiple items come along the conveyor belt together, side by side. Now, all the code you have written handles only single ordered items, not multiple items. You have a choice: you can order all the items (which may not be possible because a man puts all the items on the conveyor belt), or you can rewrite your program to synchronize multiple elements. If you had realized this in the beginning, the change could have been implemented without much difficulty or time, but now that you have everything written, you are either going to have to scrap everything and start over or rewrite all your functions that handle incoming items. So what would you gain by writing a complete design and thinking everything through in this case? Time!
NOTE: Software engineering includes the concept that the later you catch a bug in the development lifecycle, the more time, and hence money, it takes to fix it. This makes a lot of sense. If you catch a problem when you are designing your project, you can simply change your design and continue--depending on the nature of the change, maybe several days to a week worth of work. Now, if you catch it after you have finished implementing the project, you not only have to modify the design, but potentially rewrite a large amount of your project. This could cause your schedule to slip and could cost a company a great amount of money. Furthermore, if you find a problem after your project has been deployed and is being used by thousands of people who paid a great deal of money for the software, the repair work could destroy your company! Good designs and thinking through your project thoroughly will help eliminate many potential problems.
Next, let's talk about expandability. I mentioned expandability a little in the last chapter, but expandability refers to the growth of an application beyond its original functionality after it has been implemented. This is important when you write very large-scale products that are going to be used in creative ways. Getting back to the shipping example, think about what would happen if a slightly larger company was going to use your application with multiple conveyor belts. Say, for example, they had two receiving docks that two trucks could pull up to and deliver merchandise. Now, you did not need to necessarily design in support for multiple conveyor belts, but if you designed the architecture of your shipping project such that it was componentized, you could simply create a new component that could plug right in to your existing architecture and handle the additional workload.
The current trend in the market today is to develop products using some form of component technology. Component technology, such as the Component Object Model (COM) or Common Object Request Broker Architecture (CORBA), is a specification for creating the equivalent to binary classes. Binary means that the classes are already compiled (not source-code-like classes). The class-like binary files have interfaces that define methods, properties, and events. Methods are like functions, properties are like variables, and events are notifications that the components fire to their containing applications. Conceptually, the benefit to this type of architecture is that individual components can be upgraded and redeployed at runtime. This way, an end user of your product can get a simple one-file binary update that he can update on the fly and get new functionality.
Aside from the obvious benefit of only having to update individual components, a side benefit is that if you design your applications in components, the exercise of componentizing all your application's functionality gives you a greater understanding of your project and the problem you are trying to solve.
The bottom line is that designing for future expandability is definitely a huge plus and something that all companies must incorporate if they want their current product to have any kind of shelf life.
Finally, let's talk about maintainability. A good design lends itself well to maintenance. Say, for example, you are having a problem in your shipping program where it is entering data for the wrong product codes. Now if you just wrote your program from start to finish without the forethought of design, you are in for a few weeks of sleepless nights. On the other hand, if you carefully designed your applications such that you had all the product code scanning handled by one component and all the data updating handled by another component, you know exactly where to look. Turn on some debugging in both of the components, and the problem should present itself quickly.
Also, some problems only seem to happen in the field (the end user's site), and trying to get the end user to set up an entire debugging environment is sometimes unreasonable. This is another instance where componentization can help greatly. You can send off both of the questionable components in a debug mode and have the user test those for you.
I hope that you now see the benefits of a good design and are ready to get started, but before you can design your project, you must define its requirements.
A requirement, simply put, is something that your program must do. Requirements are compiled into a document or documents that define all the functionality of the program (or system). A requirement defines WHAT your program will do, but not HOW it will do it; design addresses HOW your program will implement the requirement. I will talk more about the requirements later in the iterative analysis section.
In the past, software engineers used a design methodology called the waterfall method. In this method, the software engineering lifecycle had very clear and distinct boundaries. Figure 2.1 shows a graphical representation of the waterfall method.
Figure 2.1 The classic waterfall method.
In the waterfall method, you can see distinct boundaries between systems engineering, analysis, design, code, testing, and maintenance. In this methodology, the output of one stage becomes the input for the next stage; for example, the output of analysis becomes the input for design. In this classic approach, the requirements are ALL defined in detail and cast in stone. The customer signs off on the requirements and agrees that the functionality in the requirements document is exactly everything he wants in the final product. The requirements document is then passed on to the designer, who designs the entire system and passes his design document to the implementer. The implementer simply implements the design as specified by the designer. When he is done with the program, he hands it off to the Quality Assurance (QA) person, who tests the code and then releases it to the customer. This is theoretically a very good model. You and your customer completely agree on exactly what the program will include. The designer designs it, the implementer implements it, and the QA person tests it and ships it off to the customer. Nice, right?
The iterative process, as its name implies, is iterative, meaning that as you develop software, you go through the entire process repeatedly and try to enhance your understanding of the requirements. The basic concept is that when requirements are defined, a design is started. During the design phase, issues arise that require a modification and enhancement of the requirements. When you have a start on the design, you prototype parts of your project. During this prototyping phase, issues arise that affect the design and possibly even the requirements. This way, the development of a project occurs as it naturally would in practice. To describe the iterative process, here is a sequence of events that occurs throughout the process. Remember that these steps are repeated many times during the course of the development of a project.
At the beginning of the project, there is a visionary who is responsible for the project; he or she is the one with the main idea or, if the idea is built by a group of people, this is the one person given the responsibility of ensuring that the project adheres to the vision. This step always occurs in the development of any software project. In this chapter's example, I am the visionary who came up with the idea of a Stock Tracker application to track my stock purchases. Usually the conceptualization is presented in a single sentence or a short paragraph. An example of the vision for this project could be as simple as: "A Java application that can track my family's stock portfolios, get up-to-date information live from the Internet, and allow me to see a graphical representation of my stock's performance." It doesn't have to be difficult; you just need to understand, from a very high level, what it is that you want to accomplish.
The analysis phase is the development of the vision into specific requirements. It is the understanding of the problem domain (all facets of the problem including hardware, software, existing networks, and any other factors that relate to the problem). It involves writing down how the product will be used and how it must perform. There is a set of tools used to help you with these tasks, such as use case analysis and interaction diagrams (sequence diagrams and collaboration diagrams). The final result of the analysis phase includes the following:
- Use cases--Steps showing how the system will be used
- Domain analysis--The definition of the problem domain and the relationships between different domain objects
- Interaction diagrams--The interaction between different objects in the system
- Systems analysis--Hardware analysis documents
- Application analysis document--The customer's requirements specific to this project
- Operational constraint report--Defines performance constraints
- Cost and planning document--Scheduling, milestones, and costs
You might have noticed that I referred to the project as a problem; this wasn't a mistake, just some terminology. We refer to our project as a problem that we are trying to solve, which makes sense in many circumstances (implementing a new system to replace one that is already in place, but has limited functionality), and lends itself well even to a new project that has something it is trying to accomplish. Furthermore, you might have noticed the term problem domain ; this refers to all aspects of the problem that you need to consider when deriving a solution. So from now on, if I talk about solving a problem or understanding the problem domain, just realize that I am referring to the vision or project that you are trying to implement.
As you can see, a lot of items are produced in a full-scale large project analysis; my goal here was not to confuse you, but to give you an idea about how much work can be done in the analysis phase. In this example, we are going to look at some of the more common analysis techniques: use cases and sequence diagrams. Even for a relatively small application, you want to understand how the application will be used and how different objects will interact with each another.
Analysis focuses on understanding the problem, whereas design focuses on how to solve the problem. Design is the process of taking the requirements and generating a solution that can be developed in software.
The result of the design process is a design document. A design document defines three key points for your solution: the static class design, the dynamic class design, and the architectural mechanism design. The static class design defines the classes, their methods, and properties. The dynamic class design defines the interactivity between classes. The architectural mechanism design defines such properties of your system as object persistence and how the system will be distributed.
There are several different techniques you can use when performing the design phase of a project, but for this chapter's needs, it will be fairly simple. We will take the use cases and sequence diagrams and determine how to implement them in Java.
When you have a design in place and understand how you are going to solve the problem, it's time to actually do the work; that is where the implementation stage comes in. This is the phase in which you will start writing Java code to prototype your designs and actually implement your solution.
Notice that I mentioned prototypes in the implementation phase; this is one of the areas that is different between the waterfall model and the iterative model. In the waterfall model, prototypes are created in the analysis and design phases, and the implementation phase is not started until the design is finalized. In the iterative model, the implementation phase can include prototyping, as when you start creating your prototypes, it will feed right back into the design and analysis.
After you have implemented something, you need to spend time testing and debugging it. The testing phase is very important to any software project because the integrity of the software must be maintained. In the waterfall model, testing is put off to the end such that the quality assurance department is forced to test the entire project in its complete state. Now the iterative approach allows for formal testing at every stage of the development process.
When you have a releasable product, you can deploy it. Note that this may not be the final version of the software! You heard me right; you are releasing software that is not finished! Who would ever do that?
Okay, depending on the product, some may require that all the functionality exists in the product released to the end user, but usually this is considered the minimum set of functionality that will satisfy the user's needs. In some circumstances, companies will release products that establish a baseline of functionality that the user can work with to make it to the market in a timely manner, but they know perfectly well that they are going to enhance the product. Furthermore, most companies will tentatively plan the functionality of different versions of their software out over several years. I say tentatively because this is iterative; the feedback you receive from your customers will help you develop the functionality for the next version of your software!
So what have you learned about the iterative model of development?
You learned that you define your problem and problem domain. You analyze your problem, trying to determine what exactly you are going to try to solve, which may affect your understanding of the problem and cause you to redefine the problem. Next, you create a design for how you are going to solve the problem. During the design phase, you may uncover things that you didn't account for in your analysis or things that will enhance your analysis and potentially your understanding of the problem. When you have a good start on a design, you start prototyping your design (note, these prototypes may or may not be thrown out--some may make it to the final product). During this implementation phase, you may uncover facets of the design that have to change (and possibly analysis and problem understanding). When you have a set of code written, it is time to test it. The testing phase may cause alterations to the implementation, design, analysis, and problem understanding. Finally you deploy the product. When customers have your product in their hands, their feedback will help you define the functionality they like and dislike and what functionality you should add to future releases. Not only is this applicable to new release features, but may cause you to retest, reimplement, redesign, reanalyze, and (hopefully not) potentially change your understanding of the problem.
If I put this summary at the beginning of the chapter, I would have probably gotten some blank stares at the page, but I hope that after reading through the last few pages this is starting to make sense. There are many references on object-oriented design and the iterative model of software development. Take a look at your bookstore for books written by Grady Booch, Ivar Jacobson, and Jim Rumbaugh; they are among the pioneers of the iterative model and the modeling language that lends itself well to this type of development: the Unified Modeling Language, or UML.
Earlier, in the analysis and design discussions, I talked briefly about use cases, but now I want to spend some time showing you more specifically what use cases are, what they accomplish, what they look like, and how to use them in your own designs. To emphasize the importance of use cases, consider the fact that use cases drive the analysis, the design, the implementation, and the testing phase, and they aid in helping you identify your classes.
What Is a Use Case?
A use case, put simply, is a high-level definition of how a software product is going to be used. Usually you will sit down with a domain expert (a person who is an expert in the area you are developing software for) and discuss the potential ways that the software can be used. He will help you identify the actors, or people, that interact with your software (or entire system if you are responsible for more).
I used a few new terms in the preceding description. here are some formal definitions for you to refer to:
Use case--A description of how the system will be used
- Domain expert--A person who has experience in the area you are creating the project for
- Actor--Any person or system that interacts with the system you are developing
What Do Use Cases Accomplish?
Why should you use use cases? What is their benefit?
Not only are use cases a great place to start your analysis, they also provide you with a better understanding of your product. Think about designing an application without knowing how users are going to use it. This used to happen a lot in software development. People developed software without thinking about how it was going to be used, and they occasionally overlooked something and had to redesign after the product was implemented.
Use cases help you with your analysis and design. What about the other phases of the iterative model?
The testing phase is greatly aided by use cases. They give the quality assurance department concrete test cases that must work (because the software was written specifically to implement the use cases). It is a great starting point for testers!
How Do I Use Use Cases?
The first step to using use cases is to identify the actors; note that actors can be people or can be other systems that interact with your system.
Let's consider the Stock Tracker as an example. In this project there will be users who tell the application what stock symbols to retrieve information about, what time intervals to check for stock quotes, and even request an instant stock quote lookup. The user is definitely an actor. Are there any other actors? Actually, yes there are. Consider the Internet site that the application is getting its stock information from. It will request a page from a Web server, which will either give you the page, give you an error, or time out. The server, therefore, becomes an actor in your system.
That is enough for now. You could continue searching for more actors and you might find some, but for the initial analysis, just consider the obvious ones.
The next step is to determine the first use cases. In this step you start to think about how the actors are going to interact with the system. In a large system, this can become very complex and cumbersome, but it is essential to the project.
Let's get back to the example. What kinds of things can the user do to the system?
- The user adds a new stock symbol.
- The user adds a new profile.
- The user requests a stock quote check.
- The user deletes a stock symbol.
- The user requests a three-month graph of a stock's performance.
These are but a few of the use cases to consider in the analysis of the system. As you can see, the use cases can get detailed, but they spell out pretty clearly what the system must do when it is complete.
How to Derive Use Cases
Some use cases will be obvious; in our example, determining that a user must be able to add a new stock symbol to a stock tracking application is pretty brain-dead, but others may be more difficult to derive. To help you with this, ask yourself the following questions, which can give you more insight into use cases:
Why is the actor using the system?
- What type of response does the actor expect from each action?
- What must the actor do to use the system?
- What happened to cause the actor to use the system?
- What information must the actor give the system?
- What information does the user want from the system?
What Do Use Cases Look Like?
Before I close out this discussion on use cases, I want to show you what a typical use case will look like (yes, there is a standard form). A use case is composed of the following information:
Use case--Sentence or two describing the use case itself.
- Scenario--Specific set of circumstances that define the different actions that can occur during this use case; this may include several different scenarios for one use case.
Preconditions--What must be true for the scenario to begin.
- Triggers--What causes the scenario to begin.
Description--A detailed description of each scenario, describing what actions the actors take, what results or changes are caused by the system, what information is provided to the actors, how scenarios end, a logical layout of the flow of the scenario, and what causes the scenario to end.
- Post Conditions--What must be true when the scenario is complete.
So for our example of a user adding a new stock symbol, the use case may look like this:
User adds a new stock symbol.
The user successfully adds a new stock symbol to track in his portfolio.
1. The user has launched the Stock Tracker application.
2. The user has selected his portfolio.
The user clicks in an empty row in the table.
The user clicks on the symbol column of an empty row in the stock table and enters a symbol. The program instantly fetches the pricing information from the Internet and updates the display.
The stock table displays the new stock symbol and it is added to the user's portfolio.
Now you can see that for this use case, we are assuming that the Stock Tracker application is running and that the user has selected his portfolio. The use case begins when the user clicks in the symbol column of an empty row and types in a ticker symbol. The use case includes retrieving data from the Internet and updating the display (creating a new row). One more thing to note is that when the use case is complete, the user's portfolio has been updated, so that must also be included! There, I told you this stuff wasn't that hard. It is just a formal way of doing something that is natural.
A use case can also be displayed in a graphical form, referred to as a use case diagram. Figure 2.2 shows a simple use case diagram for our use case of a user adding a new stock symbol.
Figure 2.2 A very simplistic use case diagram.
As you can see, there is not much to learn from this type of use case diagram. The only time use case diagrams get a little more interesting is when one use case has some kind of relationship with another use case. For example, say there is a use case that checks the current portfolio for the symbol you are trying to add before adding it. This relationship between the two use cases can be represented graphically. There are two types of relationships that can exist between use cases: <<uses>> and <<extends>>. <<uses>> proclaims that one use case is a superset of another. In other words, it is impossible to add a new stock symbol until you have checked to see if it is already there. <<extends>> is a bit unclear and not really used much in practice--it refers to an inheritance type relationship (I'll talk more about inheritance later), but because of the confusion in the industry about the distinction between <<uses>> and <<extends>>, it is rarely used. See Figure 2.3 for an example of the <<uses>> relationship.
After you have gone through your preliminary use cases, it is a good time to start identifying classes and objects. Now the distinction between classes and objects is an important one during design. An object has three characteristics: state, behavior, and identity. An object's state represents one of the possible conditions that it can exist in; states are represented by a set of properties, for example, a car can be running or stopped. It also describes what types of relationships the object can have with other objects. The behavior represents how the object will respond to requests from other objects; behaviors are represented by a set of operations (methods). Finally, an object's identity simply provides a unique way of identifying this object: for example, a name.
An object is made up of three characteristics:
A class, on the other hand, is an abstraction of an object. Classes are a description of a group of objects with common attributes (attributes), common operations (behaviors), common relationships with other objects, and common semantics. In other words, a class is a template for building objects. An object is an item, or instance, of the class.
The goal in deriving class diagrams is to identify the classes in your system (or project). Use cases are a great place to start identifying classes. There is no fixed method to identifying classes. As a matter of fact, Grady Booch, one of the originators of this methodology, once said, "This is hard!" Another thing to remember is that when you are finding classes, you are still working under the iterative design, so these classes will be refined as the project matures.
Okay, now that you have a little bit of an idea about what classes are, let's forego any more theory about classes and look at our use case and see if we can identify some!
First, take the user: is he a class? He interacts with the system, but he is not a piece of software that we can control, so he must not be a class. Next, let's look at how the user interacts with the system: he clicks in an empty cell in the table. Can the table be a class? This question is subjective; it may or may not be depending on your interpretation of the system. I am going to call it a class.
Let's describe the table. Its properties include all the current stock symbols and user settings it received from the portfolio and all the stock pricing information it received from the Internet.
What kind of relationships does it have? Well, it has to interact with the user to get input, it has to interact with the profiles to get stock symbols, and it has to interact with the Internet to get stock quotes.
How does it respond to other objects' requests? What kind of actions could other objects ask the table to do? When the application is closing, the portfolio could ask the table for the current stock symbols, and the stock history object (that will feed data to the graph later) could ask it for the current prices. The main user interface could ask it to update its stock prices.
Finally, what about its identity? Should we name it Bob? Okay, let's call it StockTable (I know, not too original, but a little more descriptive than Bob!).
Now let's make a class diagram from this class. Class diagrams are pretty easy; you just draw a vertical rectangle divided into three sections. The top section is the name of the class, the middle section is a collection of the class's properties, and the bottom section is a collection of the class's methods. See Figure 2.4 for a sample class diagram for the StockTable class.
Figure 2.4 A sample class diagram.
NOTE: You might notice that next to each property of the class and next to half of the methods there is a little lock. This is the notation that Rational Rose uses to denote that a property or method is private (or not accessible to objects or classes outside of the class). In all cases, properties should be private. (You don't want anyone changing the values of your properties without you knowing and verifying that the values are valid--this is known as encapsulation or data hiding. We'll talk more about that later.) In this case, three methods are private: GetStockQuoteFromInternet(), GetNewStockSymbol(), and LoadStockSymbolFromProfile(). These methods represent methods that the class will call internally to get information for the table--they are not accessible to external classes.
UpdatePrices(), GetStockSymbols(), and GetPrices() however, are public and accessible from external classes. The user interface may call UpdatePrices() to tell the table to get information from the Internet, the profile manager may call GetStockSymbols () to get all the updated stock symbols, and the historian may call GetPrices() to get the price to record for later use.
The methods that are public in a class are sometimes referred to as the class's public interface . A public interface represents all functions that anyone can call in your class (this is how other classes control or use your class).
So you have your use case written and you have your class diagrams built; now what do you do with them? You should do at least one more thing before writing code. Figure out who needs to be involved and who has what responsibilities. One method of describing the interaction of classes is to use interaction diagrams. Interaction diagrams show a graphical representation of a scenario. There are two types of interaction diagrams: sequence diagrams and collaboration diagrams.
Sequence diagrams show object interactions organized by time, and collaboration diagrams show object interactions organized by an object's connections and links to other objects. Typically, collaboration diagrams are used when a visual representation of the relative locations of objects is important, for example when laying out a plant design. Sequence diagrams are used pretty much everywhere else. Sequence diagrams and collaboration diagrams are almost completely interchangeable, so when you know one, you don't really need to learn the other. I decided to show you sequence diagrams simply because throughout my years of experience, sequence diagrams are the most common.
As I said earlier, sequence diagrams represent object interaction based on time. Therefore, you need to figure out what happens in what order. Sequence diagrams are fairly self-explanatory, so take a look at Figure 2.5 (don't worry, there will be an explanation at the end).
Figure 2.5 Sample sequence diagram.
There are column headers that represent the actor (User) and all the classes that the actor is going to interact with ( StockTable, InternetManager, and ProfileManager). Each action is ordered and numbered such that the order can be easily extracted. Time increases as you read down the diagram, so you may not always see numbered sequence diagrams. The order is implied simply by the order actions are listed in. As you can see, arrows can point both ways, showing that interaction can occur in both directions.
Let me walk you through this sequence diagram:
1. The user clicks on an empty row in the table.
2. The Stock Table makes the cell editable.
3. The user types in a stock symbol.
4. The Stock Table asks the Internet Manager to look up the stock price on the Internet.
5. The Internet Manager returns the stock price to the Stock Table .
6. The Stock Table updates its display. Note that this could either be an arrow back to the user (as it is), or it could be an arrow back to itself, showing that it is affecting itself--either would be fine.
7. The Stock Table tells the Profile Manager to update the user profile to reflect the new stock symbol.
Now you might be asking yourself some questions about some of the details. For example, how does the Internet Manager get the latest stock price and how does the Profile Manager update the user profile? These questions would be answered in the use cases and the sequence diagrams for those specific questions. In the Internet Manager question, the sequence diagram probably would not even include the request from the Stock Table ; it would simply show how it gets its information from the Internet. After all, it doesn't care who calls its GetStockPrice() function!
User Interface Design
Understanding the system design is important, but there is another aspect: designing the user interface. Chapter 4, "User Interface Design," delves into the design of a user interface in Java, but there are several things to think about in general user interface design. These key components are usability (screen layout, intuitiveness, and so on) and understanding your user.
The usability of your application has been very involved in the past, but the good news is that it is getting easier now! I don't know how long you have been using computers, but you may recall that back in the 1980s we had a plethora of complicated word processors. One of the major players back then was WordPerfect. People who knew how to use WordPerfect well could do almost anything with it and do it quickly, but the average person could not figure out how to type his own name! Now this type of user interface could be considered good or bad depending on who you talked to. The question of intuitiveness was very difficult to determine.
What is intuitive to someone who has very limited exposure to computers? That, my friend, is a very difficult question. Something is only intuitive to someone when they have some point of reference to compare it to something they understand. This is the reason we kept seeing computer speakerphones that looked like regular speakerphones and an audio rack that looks like a stereo system. That can definitely be considered intuitive, but is it usable? To the novice user, yes, but to the expert user, probably not. What to do?
Well, now that more and more users are becoming familiar with computers and using them more commonly in their everyday lives, you can start to assume some user interface guidelines. This is one area that Microsoft has excelled in. All the interfaces for all their applications have a similar look and feel. You may argue whether or not the Find command should be in an Edit menu, but you know that it is there--and it will be there in all their applications and all applications that have a Windows 9x logo! Microsoft has even released a book of software design guidelines that explains their standards in detail. So the bottom line is that if your users are not familiar with your user interface and have to learn it, they can take what they learn and apply it to a horde of other software. Standards, standards, standards: that is the name of the game!
Finally, you must understand your user when designing your user interface. Think about who you are marketing your software to. Who will be using it? What role will they take using your software? Is your software going to play a key role in their profession, or is it going to be something that they occasionally use simply to accomplish a set task?
If a user is using your software as a key part of their job; for example, consider an accountant using an accounting software package. He will want a user interface laced with a lot of features and shortcuts to accomplish his tasks faster. He will spend the time to learn your software and learn it well! Your job is to create the user interface in such a way that he can accomplish his job quickly and accurately--he won't want to be slowed down by involved wizards and features accessible only from menus.
Now consider the other side of the equation. Consider the same accountant using say, a stock tracking application. He has an interest in the stock market, but it is not his livelihood. He may check his stocks in the morning when he gets in and in the afternoon when the market closes. Is he going to spend the time to learn a cryptic user interface? Does he want any advanced "power user" features? I would say no! He wants a simple user interface that he can easily navigate to accomplish his task. He does not want to spend time learning your user interface, so it should be intuitive; I would venture to say that if your interface is too difficult, he would probably choose a different package--there go the royalties! This is the type of user who would appreciate a big button that launches a wizard that guides him through adding a new stock symbol.
The bottom line here is: Know your user! When you are writing software, you don't always know who is going to use your software, but you should have a very good idea! Think about the stock tracker software. Is the previous user I described typical of who will use the software? Do you think that a stockbroker would use it? I think our user interface is going to have to be simple and easy to use, without a lot of "power user" features.
The term power user refers to an expert user who has a great amount of knowledge in either the domain of your software or in software in general. This type of person is going to understand almost everything and want additional cryptic features.
You can pat yourself on the back; you have learned a lot in this chapter! You learned a lot about analysis and design. You learned why they are important in a software project: to enhance completeness, expandability, and maintainability as well as to help you meet your deadlines. You learned the steps you have to perform in each. Furthermore, you have learned how to organize your thoughts into use cases, how to develop classes from them, and finally how to display them in sequence diagrams. You have now been exposed to all the popular professional analysis and design methods and should have a good theoretical understanding of them.
This is a good place to point out that all the diagrams I have shown in the chapter have been made using Rational Rose, a software package written by Rational Software that is used specifically to develop models of the Unified Modeling Language components. Furthermore, Rational Rose allows you to do far more than simply draw diagrams, it allows you to organize your classes, your relationships, and your entire project. It is a great tool, but a little complicated to learn. If you are interested in learning more about UML and Rational Rose, you can get more information and download a trial version from Rational Software's Web site: http://www.rational.com.
Now that you have these tools under your belt, the next step is to do something meaningful with them. In the next chapter, you are going to take what you have learned here and apply it to the design of the stock tracker application. Don't worry, we will cover a great amount of design work, but I will try not to overwhelm you with too many details.