Professional Documents
Culture Documents
Page 1 of 1
http://www-106.ibm.com/developerworks/rational/rationaledge/
Search for:
within
All of dW
Search help
IBM home
developerWorks
About IBM
>
Rational
>
7/15/2004
Page 1 of 2
Search for:
within
All of dW
Search help
IBM home
developerWorks
>
Rational
>
Issue contents
issue contents
archives
Have you ever wondered about the relationship between the creation of use cases and the
creation of code? In good development practice (not just in theory), use cases guide
development teams directly into the coding process. Although there are many steps to this
transformation, Gary K. Evans's puts us on a clear path that begins with writing solid use
cases, which leads to better analysis, then design, and finally coding. Part 1 concludes with
the analysis portion. Next month, we will complete the journey.
And you'll find much more this month in the list of contents below.
Happy iterations,
Mike Perrow
Editor-in-Chief
Features
z Getting from use cases to code
Part 1: Use case analysis
by Gary Evans
The first in a two-part series, this article
presents a case study that analyzes the
requirements captured in use cases and
transforms them into implementable
representations that can be directly coded.
z
subscribe
submit an article
contact us
Download the
entire issue in .pdf
(1.0 MB)
7/15/2004
Page 2 of 2
Rational reader
z Book review: Eric Meyer on CSS:
Mastering the Language of Web Design
by Eric A. Meyer
Reviewed by Kerry McKay
McKay reviews a book designed for
experienced HTML users who want to
improve their Web design capabilities.
Using a project-oriented approach, the book
takes readers step by step through ways of
applying cascading style sheet (CSS)
techniques for purposes ranging from online
greeting cards to input forms.
z
About IBM
7/15/2004
http://www-106.ibm.com/developerworks/rational/library/5383.html
Search for:
within
Search help
IBM home
developerWorks
My account
> Rational
Gary Evans
Independent Object Technology Evangelist, Evanetics
13 Jul 2004
from The Rational Edge: The first in a two-part series, this article presents a case study that analyzes the
requirements captured in use cases and transforms them into implementable representations that can be directly
coded.
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
The IBM Rational Unified Process (RUP) advocates writing use cases to capture the operational requirements of a software system. Use cases are actually
a constituent of a larger requirements package of documents collectively known as the Software Requirements Specification (SRS), which contains all the
requirements for a software project. The SRS includes the following requirements artifacts:
Supplementary Specification: A document that captures the system-wide requirements, and those functional aspects of the system which are neither
visible to the systems actors, nor local to a specific use case.
These requirements artifacts become inputs to the subsequent analysis and design activities of the Analysis and Design discipline in RUP. Exactly which
requirements artifacts are produced, of course, depends on the forces driving your development effort. If you are doing hot fixes (i.e., critical bug fixes on a
product already in production) you might not have any requirements documents, only bug reports that indicate the released software does not meet its originally
stated requirements. If you are doing a maintenance or enhancement release of software (i.e., adding new functionality to an existing product) you might have
one or two use cases describing how these new functions interact with a user, but you would not have a Supplementary Specification because no changes to
the non-functional properties of the software have occurred.
In this discussion I am assuming a brand-new, green-field development project for software that does not yet exist. This will be an object-oriented project
using the Unified Modeling Language (UML) to represent concepts and relationships. I am also assuming that the reader is comfortable with the concepts of
class and object, and is at least comfortable with reading UML version 1.x or 2.0 class diagrams, sequence diagrams, and collaboration diagrams.
To identify the classes that perform the various flows of events in a use case.
To note the usage of architectural mechanisms to provide the functionality needed by the use case, and the software system in general.
We can alternately say that the goal of Use-Case Analysis is to take our understanding of the requirements in the systems use cases and iteratively transform
those requirements into representations that support the business concepts, and meet the business goals of those requirements. In Use Case Design we will
transform these business concepts into classes, objects and relationships, components, interfaces, etc., which can be implemented in an executable
environment.
The diagram in Figure 2 is taken from the RUP Analysis and Design Activity Overview, which illustrates where the Use Case Analysis activity occurs within the
context of the other Analysis and Design activities.
Establish Traceability
Please note that the order of these steps is not cast in stone. The actual sequence you follow may differ according to your understanding of the domain you are
analyzing, your experience with RUP or UML, your personal preferences for the models you use, or the metaphor you follow for characterizing the properties of
your analysis classes (e.g., responsibility-centric, behavior-centric, or data-centric approaches). What is important is that you achieve a comprehensive
expression of the problem you are to solve (note that we achieve a comprehensive definition of the solution we have chosen in Use-Case Design, which is the
subject of Part 2 in this series). I will follow most, but not all, of these steps in this article, and I will change the sequence somewhat. As I discuss each step, I
will explain why I have found a slightly different sequence to be beneficial when teaching object-oriented analysis and design (OOAD) to people who are new to
RUP and OOAD.
As Figure 3 illustrates, there are some specific activities that separate the writing of a use case from its implementation in code. This illustration also shows the
steps recommended by RUP within the context of Use Case Analysis. This diagram will become our visual roadmap as the remainder of this paper addresses
the specific tasks within these activities.
http://www-106.ibm.com/developerworks/rational/library/5383.html (3 of 20)7/17/2004 5:41:24 AM
Reserve a Vehicle
Cancel a Reservation
To simplify our modeling, I will assume that our rental agency does not support corporate accounts, only individual accounts.
To keep our example simple and understandable, we will focus on just one of these use cases. Here is a use case description for the use case: Reserve a
Vehicle.
1. This use case begins when a customer indicates he wishes to make a reservation for a rental car.
2. The system prompts the customer for the pickup and return locations of the reservation, as well as the pickup and return dates and times. The customer indicates the desired locations and dates.
3. The system prompts for the type of vehicle the customer desires. The customer indicates the vehicle type.
4. The system presents all matching vehicles available at the pickup location for the selected date and time. If the customer requests detail information on a particular vehicle, the system presents this information to the
customer.
5. If the customer selects a vehicle for rental, the system prompts for information identifying the customer (full name, telephone number, email address for confirmation, etc.). The customer provides the required
information.
6. The system presents information on protection products (such as damage waiver, personal accident insurance) and asks the customer to accept or decline each product. The customer indicates his choices.
7. If the customer indicates accept reservation, the system informs the customer that the reservation has been completed, and presents the customer a reservation confirmation.
8. This use case ends when the reservation confirmation has been presented to the customer.
This use-case description is necessarily generic: it is not specific to a Web-based application, nor is it specific to the situation where a human being walks up to
a rental counter and requests a vehicle to rent. This description addresses only the what, not the how, of the system what is the behavior of the system and
the corresponding behavior of the use-case actor (i.e., the customer). If you substitute customer service representative for the system above, you will have a
http://www-106.ibm.com/developerworks/rational/library/5383.html (4 of 20)7/17/2004 5:41:24 AM
reasonably accurate description of what happens when a human walks into the rental office to get a vehicle. In this case, the reservation confirmation presented
to the customer in Step 7 is the printed rental agreement.
Alternately, if you are planning on implementing a Web-based interface, this use case describes that approach also, if you recognize that multiple steps in a use
case can be combined into a single browser page (e.g., steps 2 & 3 would most certainly be on the same page). In the Web environment, the reservation
confirmation presented to the customer in step 7 is the confirmation number associated with the rental transaction, presented to the actor on the transaction
summary Web page.
Also note the style of the use case. It is written in active voice and present tense. Active voice is clear and emphatic, while passive voice is a weaker
presentation. E.g., John throws the ball is active voice. The doer of the action, John, precedes the verb. The passive voice equivalent of this sentence is: The
ball is thrown by John, or just The ball is thrown, leaving the thrower unspecified. Here the doer of the action, John, follows the verb. Invariably, in passive
voice, the doer is contained within a prepositional phrase initiated with the word by. Keep your use case descriptions clear and consistent. Use active voice,
present tense. Use a limited and clear vocabulary. Do not introduce unnecessary words, and be consistent. For example, dont use the word customer, then
client, then business patron just to be creative. Your reader will conclude that you might be discussing three separate actors, with different security profiles
and authorizations!
Now that we have this use case as a starting point, lets follow the RUP steps of Use Case Analysis.
A UML class diagram for those classes participating in the use case on which we are focusing (sometimes called a View of Participating Classes class
diagram.), and
One or more UML interaction diagrams to describe which objects interact, and the interfaces which these objects will invoke to carry out the work of the
use-case process. UML defines two types of interaction diagrams: a sequence diagram (shown in Figure 4), and a collaboration diagram. Either
diagram can be effective.
This sounds like a lot to do in this first step, doesnt it? Yes, and actually this first step is a housekeeping task when you are using a CASE tool such as Rational
Rose or Rational XDE, and really means create a place to hold your use-case realization. We will develop the actual class and interaction diagrams later in
this process. But now we know the content we will be developing to populate our use-case realization: a class diagram and one or more interaction diagrams.
1. This use case begins when a customer enters our rental Website page.
2. The system presents fields to prompt the customer for the pickup and return locations of the reservation, and the pickup and return dates and times. The customer indicates his desired locations and dates. The system
also presents an option for the customer to limit the vehicle search to specific categories of vehicles e.g., compact, SUV, full-size, etc. The customer may specify a search category, or categories, if desired. The
default is to search for all categories of vehicles. If the customer is participating in our rental awards program, he may enter his awards identification number in a separate field on the page. If this field is filled in, the
system will access the customers rental profile, which the system will retain to pre-populate any required information.
3. If the customer indicates he wishes to continue the reservation session, the system accesses the vehicle inventory for the pickup location, and presents a new page with all vehicles of the specified categories available
at the pickup location for the selected date and time. With each vehicle the system presents a base rate, which may be discounted based on the customers rental profile. If the customer requests detail information on
a particular vehicle, the system obtains this information from the vehicle inventory and presents it to the customer.
4. If the customer selects a vehicle for rental, the system presents a new page which prompts for information identifying the customer (full name, telephone number, email address for confirmation, credit card issuer,
etc.). If a customer profile exists, the system pre-populates all known values. Some fields are mandatory; others (such as email address) are optional. The customer provides any remaining required information. The
system also presents information on protection products (damage waiver, personal accident insurance, etc.) and their daily costs, and asks the customer to accept or decline each product. The customer indicates his
choices.
5. If the customer indicates accept reservation, the system presents a page summarizing the reservation (type of vehicle, dates and times, any elected protection products and their charges, total rental cost), and
presents the customer a reservation confirmation. If the system has an email address for the customer, the system sends a reservation confirmation to that address.
6. This use case ends when the reservation confirmation has been presented to the customer.
In this supplemented version we are clearly describing the behavior of a browser-based application, specifying a fair amount of behavior that is not visible to the
customer actor. But there is no design-level information in the use case yet.
Why should I do the high-level use case at all? Why not just do a supplemented use case?
The answer is, the abstract use case (light on internal behavior) is the most generic description of behavior. What if you wanted to do a client/server version of
the Reserve a Vehicle use case? If you started with a browser-specific version, you would have to re-write the whole thing from scratch when you changed your
target platform. The generic version is technology-agnostic, and that is a great value when you are not ready, or able, to specify the production environment.
Additionally, the abstract version lets your Business Analysts or Subject Matter Experts focus on what the systems business behavior will be, rather than the
implementation which they may not understand at all.
According to RUP, the purpose of this step is to identify a candidate set of analysis classes which will be capable of performing the behavior described in our
use cases. So far we dont have any classes, so our main goal will be to identify the analysis classes we need in our Auto Rental system.
But this raises a very interesting and important question: Just what is an analysis class? There are two answers, really. First, a business-level analysis class is
one that is essential to the business domain, without reference to implementation or technology constraints. For example, a banking system has Bank
Customer, Account, Account Transaction, etc., and it does not matter if this is a new e-commerce system or a savings and loan system from the 1890s.
Second, RUP extends this definition by defining analysis classes in three disjoint categories: as entity, controller, and boundary classes. RUPs entity classes
are roughly equivalent to the business-level analysis classes above. Controller classes are process-aware, and sequence-aware: they control and direct the
flow of control of an execution sequence. It is common to find a controller class enforcing the process behavior of a use case. Boundary classes mediate the
transfer of information and events between the software being executed and the outside world. Boundary classes handle the input and output functions required
by a software system.
In my experience teaching object technology and modeling, I have found that teams employing RUPs entity, controller, and boundary categories jump too
quickly into a design mindset, without performing adequate analysis of the problem they are trying to solve. In fact, it is quite clear that controllers and boundary
classes are actually technology classes, not business classes. They are part of the solution domain defined in design, not part of the problem domain described
in analysis. So, in this article I am going to concentrate on the business-level, technology-agnostic analysis classes, and leave alone almost all technology
issues until we discuss design. Be aware that the activity of finding these business-level classes is normally performed in RUPs Architectural Analysis activity
if your project is pursuing that degree of RUP conformance.
With that said, lets recall that the focus of a use case description is behavior what services the system will provide to the actors who are requestors of those
services. There is nothing object-oriented about use-case descriptions, but these descriptions can be used to discover the classes or objects in our system.
Classes can be discovered in many different ways, from different sources:
Glossary of terms
Data mining
One simple technique for discovering classes is known as grammatical dissection, and I will illustrate that. In grammatical dissection we identify the nouns in our
requirements. Of these nouns (and adjective-noun pairs):
Lets identify and underline the nouns (skipping pronouns such as he) in our supplemented use case for Reserve a Vehicle, as follows:
Use Case: Reserve a Vehicle to a customer (Supplemented).
1. This use case begins when a customer enters our rental Website page.
2. The system presents fields to prompt the customer for the pickup and return locations of the reservation, and the pickup and return dates and times.
The customer indicates his desired locations and dates. The system also presents an option for the customer to limit the vehicle search to specific
categories of vehicles e.g., compact, SUV, full-size, . The customer may specify a search category, or categories, if desired. The default is to
search for all categories of vehicles. If the customer is participating in our rental awards program, he may enter his awards identification number in a
separate field on the page. If this field is filled in, the system will access the customers rental profile, which the system will retain to pre-populate any
required information.
3. If the customer indicates he wishes to continue the reservation session, the system accesses the vehicle inventory for the pickup location, and presents
a new page with all vehicles of the specified categories available at the pickup location for the selected date and time. With each vehicle the system
presents a base rate, which may be discounted based on the customers rental profile. If the customer requests detail information on a particular
vehicle, the system obtains this information from the vehicle inventory and presents it to the customer.
4. If the customer selects a vehicle for rental, the system presents a new page which prompts for information identifying the customer (full name,
telephone number, email address for confirmation, credit card issuer,.). If a customer profile exists, the system pre-populates all known values. Some
fields are mandatory; others (such as email address) are optional. The customer provides any remaining required information. The system also
presents information on protection products (damage waiver, personal accident insurance, etc.) and their daily costs, and asks the customer to accept
or decline each product. The customer indicates his choices.
5. If the customer indicates accept reservation, the system presents a page summarizing the reservation (type of vehicle, dates and times, any elected
protection products and their charges, total rental cost), and presents the customer a reservation confirmation. If the system has an email address for
the customer, the system sends a reservation confirmation to that address.
6. This use case ends when the reservation confirmation has been presented to the customer.
Note that every occurrence of any noun, or adjective-noun pair, has been underlined. We have lots of duplicates, so gather the distinct nouns/pairs into a single
list in Table 1, sorted alphabetically:
How do we identify which of these candidate nouns really describe classes in our problem domain? A very usable approach is to challenge each candidate
noun with a few simple questions shown in Figure 5:
Note that rental location has been added although it was not part of the use case. In talking with our Subject Matter Experts (SMEs), we learned that the normal
business vocabulary uses location to refer to both an address, and to a rental branch. To resolve the ambiguity, we agreed to use the term rental location for
the business location where rentals and returns are conducted.
From this list we extract those candidates that we have designated yes. This yields the following list of analysis classes:
Wow! Thats only eight analysis classes versus the thirty nine candidates we started with. The four questions have helped us rapidly narrow our focus and
thats a good thing.
But what if we made a mistake? What if we missed a real class, or we included a class that we should not have? It doesnt matter, really. The iterative nature
of RUP will reveal our errors, and allow us to correct them with minimum damage to work we have already done. The goal of analysis and design is not to get it
all right up front. The goal is to get it right when you need to have it right. Getting started is often the hardest part of any task, and we have now made the leap
from having no objects to having objects (or from having no classes to having classes). What is important is that we have started, and we can begin to move
forward in an object-oriented perspective.
We now have completed the first three steps in RUPs Use Case Analysis activity:
A data-driven approach
A behavior-driven approach, or
A responsibility-driven approach.
The data-driven approach is very popular with people coming from a database, or procedural, background. They see the world in terms of data, and data
relationships, and tend to populate their classes first with data usually with no strategy on how to assign operations (i.e., functions) to the class. This is fine,
but data is only half of the total picture. Indeed, the very concept of a class involves the intimate association of data with the operations that manipulate that
data.
The behavior-driven approach takes this dual nature into account. It populates a class first with the operations that the class will perform, and determines from
those operations the data that should be owned by the class. Very good, but how do I make sure that the operations I assign to a class are coherent? And how
do I distinguish between operations and classes, so that I know this operation belongs in this class, but that other operation should be in a different class? We
need a filter, some kind of discriminator that will help us make good decisions about our operations. This filter is what the responsibility-driven approach gives
us.
A responsibility-driven approach starts with a large-grained view of the class and first assigns responsibilities to that class. This approach describes first the
mission statement of a class in the context of the problem domain in which we are working. This mission statement is a declaration of the services the class
will provide to requestors of those services. In military terms, the responsibilities are strategic; the operations and data are tactical (subservient to, and a means
2
And once we identify our class responsibilities, we should construct an analysis class diagram to capture the structure of the relationships among our classes.
This structure is usually inherent in the business domain we are modeling, and a UML analysis class diagram gives us a visual representation of this
relationship structure.
So, the deviation I am recommending produces the following change to the standard RUP flow (sequence changes are in bold):
James Rumbaugh et al. defines an object, or class, as a concept, abstraction, or thing with crisp boundaries and meaning for the problem at hand [my
emphasis]. It is primarily through the definition of responsibilities that you can give a class crisp boundaries, a clear definition of what it does, and does not,
do.
What if we made a mistake in our responsibilities? Again, it doesnt matter. We have a starting point and we will move forward. It is common to adjust the
responsibilities of classes as we learn more about our system. This is just another example of where we use refactoring to help us build better models and
better software.
for Business Analysts and Subject Matter Experts to review with the technical people, and migrate the model toward a proper description of the problem being
solved.
Now we have classes, responsibilities, and a class diagram to show the structure of relationships among the classes. But so far we have no internals of the
classes no operations and no attributes. And the class diagram is a static picture. How can we be sure that these classes really can carry out the process
described in our use cases? Ah, that is what the next step is for, and it is an all-important step because it maps our use-case descriptions into potential
operations on our analysis classes.
The sequence diagram offers a significant advantage over the collaboration diagram, which is the script on the left-hand side of the diagram. This text is taken
from the use case, or scenario, that the sequence diagram depicts. The script on this diagram is just a terse rendering of the text in the Reserve a Vehicle use
case. Placing the script into the diagram makes the context of the messages very clear, and links the messages and objects back to the original use case. It is
always the case that a given statement in the use case will map to one or more messages sent between the objects in your system. The Sequence diagram
makes this explicit.
I want to emphasize a very important characteristic of analysis-level interaction diagrams: the messages show intent, not implementation, not even interface. In
the Reserve a Vehicle Sequence diagram the messages simply indicate what I want done by the receiving object, not the signature of a function call. This
deeper interface detail is addressed in design, but now we only want to be sure our classes have the responsibilities to do the work of the use case.
How did we know to send these particular messages to these classes? By following our responsibility definitions. For example, in Step 8, the RentalLocation is
asked to meet its responsibility of determining what vehicles are available. In Step 9, the VehicleInventory is asked to retrieve all vehicles for this location that
can match the requested rental dates and times. In Step 10, each Vehicle in inventory is asked if it is available to meet these rental criteria. Notice that all of this
knowledge is not in the RentalLocation object. We have distributed the intelligence in our system across all of our analysis classes, so that each class can act
on a small set of requests that are within its defined responsibilities.
If we create two objects from this Account class definition, FredsStash, and EthelsMadMoney, they would be shown as:
FredsStash : Account
EthelsMadMoney : Account
The one on the left, for example, indicates that FredsStash is an object of type Account. How do you know if you should name an object or leave it
anonymous? If you have a special entity in your system that has a well-known name, you might want to use a named object to represent it. Or, if you want to
build a diagram with sample objects (similar to sample tables in a logical data model) you could use named objects. But for most modeling purposes,
anonymous objects are sufficient. We are most interested in the services (functions) a class and object provide, and the name of the object does not affect what
the class or object can do.
The class diagram shown in Figure 8 shows our vehicle rental analysis classes, the relationships between them, and an initial start on the attributes appropriate
to be owned in each class. These are simply the attributes most evident from the class responsibilities. Note that these attributes do not even have datatypes
yet because data types are a design issue.
Persistence
Exception handling
Messaging
Security
Legacy interface
Conclusion
In Part 1 of this series on Getting from use cases to code, we have traveled from a single use case, with no knowledge of classes in our system, to a point
where we have identified the classes needed to support the goals of that use case, the relationships among those classes, and the attributes needed by those
classes, and we have specified several analysis mechanisms that identify services we will need to refine into design and implementation perspectives.
If we repeat this use case analysis process with another use case, we will discover some additional analysis classes, define their responsibilities, new
relationships to other analysis classes, perhaps discover new analysis mechanisms, and we will develop another collaboration diagram or sequence diagram to
further demonstrate how our classes interact. This demonstrates the incremental aspect of RUP: each task, or iteration, builds on, and adds to, the work done
previously.
We have accomplished a lot, but we are not yet ready to begin writing code. Now we are at a point to turn our attention to Use-Case Design, which is the
subject of Part 2 in this series.
Acknowledgements
I am grateful to Peter Eeles and Zoe Eason of IBM Rational for their insightful comments and suggestions on an earlier draft of this paper.
References
Wirfs-Brock, Rebecca. Designing Object-Oriented Software. Prentice-Hall, 1990. A classic in object thinking and modeling. Introduces the significance of the
responsibility-driven approach to software modeling and design.
Rumbaugh, Jim, et al. Object-Oriented Modeling and Design. Prentice-Hall, 1991, pg. 21. The defining book on the Object Modeling Technique, a major
influence on the Unified Modeling Language.
The Rational Unified Process, version 2003.06.00.65. Rational Software Corporation.
Further Reading
Ambler, Scott. The Object Primer, 2nd ed. SIGS, 2001. Covers end-to-end object-oriented development with a single case study.
Fowler, Martin. UML Distilled, 3rd ed. Addison-Wesley, 2004. Best introduction to UML (version 2.0) for those learning UML for the first time.
Taylor, David. Object Technology: A Managers Guide. Addison-Wesley, 1998. One of the best introductions to object-thinking ever written.
Bell, Donald. UML basics An introduction to the Unified Modeling Language, in The Rational Edge, June 2003: http://www-106.ibm.com/developerworks/
rational/library/769.html
Bell, Donald. UML basics: The activity diagram, in The Rational Edge, September 2003: http://www-106.ibm.com/developerworks/rational/librarycontent/
RationalEdge/sep03/f_umlbasics_db.pdf
Bell, Donald. UML basics: The class diagram, in The Rational Edge, November 2003: http://www-106.ibm.com/developerworks/rational/librarycontent/
RationalEdge/nov03/t_modelinguml_db.pdf
Bell, Donald. UMLs sequence diagram, in The Rational Edge, January 2004: http://www-106.ibm.com/developerworks/rational/library/3101.html
Notes
1
All references in this series to RUP incorporate the content of RUP version 2003.06.00. All models and code in this series have been generated using IBM
Rational Extended Developer Environment (XDE) Developer Plus for Java version 2003.06.
For more information on the responsibility-driven approach, see Rebecca Wirfs-Brocks book, Designing Object-Oriented Software. Prentice-Hall, 1990.
Rumbaugh, Jim, et al., Object-Oriented Modeling and Design. Prentice-Hall, 1991, pg. 21.
Comments?
developerWorks
> Rational
About IBM
Privacy
Terms of use
Contact
Lame! (1)
Page 1 of 8
http://www-106.ibm.com/developerworks/rational/library/5170.html
Search for:
within
Use + - ( ) " "
IBM home
developerWorks
All of dW
Search help
> Rational
Contents:
Follow a structure
Use practices that ensure
quality
Elaborate with comments
Know the language
Follow guidelines
Follow a structure
All programming languages have a structure. Structure refers to how various parts of a program are defined and how they relate to each
other. Java programs are structured with classes, COBOL programs have various "divisions," and C programs have a main program with
subroutines.
Just as programs have a specific structure, so do requirements. Imagine if you were to put all the code you wrote for a C program into the
main program it would become unreadable and impossible to maintain. Similarly, if your requirements specification is merely a giant list
in no particular order, you will not be able to use it. A group of requirements always has structure, whether you realize it or not. The
optimum way to structure in requirements is to organize them by different types, which often correspond to different levels.
To understand the distinctions among different types, let's look at four example requirements for an insurance claims processing
application:
1.
2.
The system must be able to automatically check claim forms for eligibility issues.
3.
The system shall determine whether a claimant is already a registered user, based on his/her social security number.
4.
7/15/2004
Page 2 of 8
Your intuition may tell you that there is something different about each of these requirements. The first is very high level; it expresses a
business need without even mentioning a system. The second expresses what the system should do, but still at a pretty high level; it's still
too broad to translate directly into code. The third is a lower-level requirement; it does provide enough detail about what the software must
do to enable you to write code. And the fourth requirement, though very detailed, does not tell you what the system must do; instead, it
specifies how fast the system must be. These requirements are very typical of those you will get as you talk to users and other
stakeholders. Perhaps you can see why putting them all into one big, uncategorized list would lead to confusion.
You can make requirements much more usable by putting them into categories, or types, such as:
z
Business needs
Features
These are the types suggested in IBM Rational Unified Process, or RUP. They are by no means the only possible types, but they
represent one useful approach. Early in your project, you should decide on what types to use. Then, as you collect information from
stakeholders, decide which of the requirement types they are describing, and write the requirement.
Note that you can specify functional software requirements in one of two formats: declarative and use case. The third requirement above
is stated in declarative form; it is quite granular and uses a "shall" statement. The other form is a use case. It also specifies what the
system should do, at a level low enough to write code from. However, it provides more context about how the user and the system will
interact to perform something of value. (See below for more detail on use cases.) Before you begin collecting requirements for a project,
you should decide which type of functional requirement you want to use and then be consistent.
Mean time between system failures must be no greater than once per week.
2.
The system shall support 1,000 simultaneous users, all doing queries against the database at the same time, without crashing or
losing data.
3.
The average response time of the system shall be less than one second with up to 1,000 simultaneous users.
Quality requirements have many more attributes; see the IEEE guidelines for more information.1
7/15/2004
Page 3 of 8
have attributes information that makes the requirements more understandable or usable. As you elicit the requirements you should
also discover attribute information. For example, one important attribute is origin: Where did the requirement come from? Keeping track of
your sources will save significant time if you need to go back for more information. Another attribute is user priority. If a user gives you fifty
requirements, he should also let you know how important each one is relative to the others. Then later in the project lifecycle, when time
is getting short and you realize you cannot meet every requirement, at least you will know which ones are most important.
Just as there are no rules that tell you exactly what comments to write in your code, there is no universal list of the "right" attributes. Origin
and priority are almost always useful, but you should define others that are suited to your project. As you gather requirements, try to
anticipate what information the team might need when you start to design the system and write code.
Follow guidelines
Most development teams use coding guidelines such as the following:
7/15/2004
Page 4 of 8
Place the high-activity data elements at the beginning of each group of the WORKING STORAGE SECTION variables (COBOL).
You should use guidelines for writing requirements, too. For example, if you decide to specify software requirements with use cases, then
your guidelines should tell you how to write the flows of events. Use-case flows of events explain how the system and a user (actor)
interact to do something significant. Your guidelines should describe what goes in the main flow (the success scenario) and what goes in
alternate flows (exception scenarios), as well as how to structure these flows. They should also suggest lengths for both flows and
individual steps within them. If you decide to use traditional, declarative requirements, then the guidelines should explain how to write
them. Fortunately, many of these guidelines already exist in RUP and other respected sources, so you need not write them yourself.2
What does it mean? If the developer is not sure, she will investigate by looking in her code, the compiler documentation, and maybe even
via a search engine such as Google. Eventually she will figure it out: Her code is missing the default constructor for the applet she is
writing.
If you were collecting requirements for a weather forecasting system and a stakeholder told you that the system should be able to
"...display wind speed and direction at various heights in the atmosphere over a 200 square mile area, using standard arrows with little
tails," you would need to dig deeper. You might ask to see a report from a similar system, consult a book on meteorology, or ask another
stakeholder to describe the request more accurately. You would keep investigating until you had enough detail about the desired
functionality. Then you would restate the requirements to make them clear and unambiguous, providing enough detail to support a
design.
Another tip for eliciting requirements is to try not to ask leading questions. Although you may have ideas about what users should want, if
you let those slip out, you may not get a true picture of what they really want. Instead, ask open-ended questions such as, "What separate
data displays would you like to see?" and avoid questions such as, "Do you want to see a combined air pressure and temperature chart?"
Information hiding
This refers to the principle that the user/caller of a piece of code should not be able to access, or even know about, the data's internal
details. All access and modifications to the data should be through function calls. That way, you can change the internal data structures
without affecting the calling programs.
This is a good principle for requirements too, especially if you are expressing them in use cases. As we noted above, use cases have
flows of events. Poorly written use cases often have flows of events that are packed full of data definitions. Consider this basic flow of
events for a use case called Manage Purchase Request:
7/15/2004
Page 5 of 8
2.
Each pending request will include the following information about the request (limit by char):
{
PO #
Reference ID
Reason Codes
Amount Requested
Request Date
Assigned to (Internal)
Comments Indicator
3.
The Approval Admin can do one of the following 1) approve 2) reject 3) cancel or 4) assign the request. He/she chooses 1)
approve.
4.
Of the fifteen lines shown, eleven are dedicated to telling what data goes with a pending request. This is important information, but it
obscures what is happening in the use case. A better solution is to hide the data somewhere else. The steps would then look like this:
Basic flow of events:
1.
2.
The Approval Admin can do one of the following 1) approve 2) reject 3) cancel or 4) assign the request. He/she chooses 1)
approve.
3.
Pending purchase requests is underlined and italicized to indicate that the data is defined elsewhere (usually in the special requirements
section of the use case or perhaps in a glossary). This makes the flow of events, which represents the true functional requirements, much
easier to read and understand.
7/15/2004
Page 6 of 8
All the functionality in one use case should be about accomplishing one goal of an actor (i.e., have high cohesion). In a system for a
typical automated teller machine (ATM), one use case would be "Withdraw Cash" and another "Transfer Funds." Each use case
concentrates on a single goal. If you were to combine these functions into a single use case, it would have low cohesion (and undesirable
dependencies).
However, be aware that many use-case beginners go overboard and create too many low-level use cases. I once saw a model for a
bank's debt collection system that had 150 use cases with names such as "Modify Data." This project had a team of ten and was
scheduled to last about a year. However, the organization was having a lot of trouble moving forward because these use cases were too
fragmented. They described low-level functions that didn't specify value to the user; they were hard to understand and hard to use. Each
use case was extremely cohesive, but consequently the use cases had a high degree of coupling. Raising the level to more specific
activities such as "Collect Debt" yielded appropriate degrees of both cohesion and coupling.
Almost all RM tools allow you to import existing requirements documents into the tool. If both the tool and your documents are
good, the tool will be able to identify automatically the actual requirements in the document. IBM Rational RequisitePro provides
a dynamic link from the requirements in the document to those stored in the tool (or backend database), so that the requirements
are always "live."
RM tools allow you to easily create requirement types and give them attributes. This allows for sorting and filtering, giving the user
a flexible query mechanism to find requirements of interest quite easily. These tools also allow you to sort requirements by
attribute values. For example, if you had the attributes "user priority" and "risk" for your feature requirement type, you could create
the following query: "Show me all the high-priority, high-risk features." This could help you decide which features to implement in
early iterations to ensure that you do not leave out important functionality and that you mitigate risk early in the project.
Good RM tools provide traceability between requirements; a really good one provides traceability to other tools and artifacts, such
as designs and tests. Traceability is an important capability that helps you validate and verify your system.
A requirements management best practice is to track each requirement's history. An RM tool can help with this, too. It tells you not
only the requirements' origin, but also why decisions were made and who made them.
RM tools can also help with baselining: taking a "snapshot" of your requirements at a particular point in time that you can compare
to future snapshots. A baseline provides a stable set of requirements upon which to work. It also provides a branch point in the
project lifecycle that you can reference, should you want to copy your requirements for a new development effort.
So, like compilers and IDEs, RM tools help developers do things they could not easily do manually (or perhaps not at all) and helps them
achieve greater efficiency.
Manage change
Good development shops manage the changes to their code. Developers write code according to designs and specifications; they do not
add features at their own discretion. In addition, the code is under source control; when they change the code, developers specify why
7/15/2004
Page 7 of 8
they did it. Periodically, they also baseline the code, integrate it, and test it for release.
Requirements need change control, too. Change is inevitable; it is important to plan for it. At the beginning of a project, requirements are
usually (and appropriately) in a state of flux. But at some point, before too much code gets written, it is important to draw a line in the sand
and create a requirements baseline. After that, requirements changes must be approved, typically by an appointed Change Control Board
(CCB). However, some organizations designate just one or two people to review change requests periodically.
Teams that do not have a requirements change control process must field change requests from all quarters and often have difficulty
saying "no." If you want to avoid this, along with having to constantly rewrite code to keep pace with the requirements changes, start a
CCB or the equivalent. A process for reviewing changes can help ensure that the changes you make will provide business value and that
everyone understands their impact. Changes with no business value simply eat up resources with little reward. Similarly, changes that do
have business value but would also have great impact on existing requirements, designs, code, and tests may not be worth the effort.
Another way to assess a change's potential value and feasibility is through traceability. It allows you to track (trace) the justification for a
requirement and understand all related artifacts. By tracing a software requirements to higher-level business, or user requirements, you
can ensure that it has value. If you cannot trace it in this way, the software requirement probably does not have a business justification. In
addition, by tracing from high-level to low-level requirements and on to design, code, and test, you can easily see the impact of a
requirements change. A traceability matrix or better yet an RM tool will clearly show all relevant artifacts and provide the knowledge
necessary to decide whether a change request is worthwhile.
Planning
Most successful software development projects have a plan that guides the project, specifying who does what, how things will be done
and what the milestones will be. The architect typically creates a document that provides a comprehensive overview of the system's
architecture. It also enables communication between the architect and other project team members regarding architecturally significant
decisions and guides developers as they implement the system.
Like these plan documents, a requirements management (RM) plan can provide tremendous benefit to a project. For developers who
write requirements, the plan describes necessary requirements artifacts, along with requirement types and their respective attributes. It
specifies information the developers must collect and mechanisms for controlling requirements changes.
As we saw earlier, requirement types might include business needs, features, and functional and non-functional software requirements.
You may also have user requirements and marketing requirements. A plan encourages you to think about and specify requirement types
you will need, which in turn helps to ensure consistency and readability for written requirements.
As we also noted earlier, attributes provide supplemental information that helps you understand and use requirements specifications more
effectively.
The RM plan also describes the documents you will use. RUP recommends three categories: a vision document, use-case documents,
and a supplementary specification document describing requirements that do not warrant use cases.
The RM plan also describes the change management process so that everyone on the project will understand it.
If you are already working on a project that does not have an RM plan, you can write one yourself. It doesn't have to be long: One or two
pages might contain all the information you need to promote the creation of consistent, high-quality requirements.
Notes
1 IEEE Recommended Practice for Software Requirements Specifications, Software Engineering Standards Committee of the IEEE
Recommended Practice for Software Requirements Specifications, Software Engineering Standards Committee of the IEEE Computer
Society. Approved 25 June 1998
7/15/2004
Page 8 of 8
3 Unified Modeling Language, or UML, includes the concepts of extend and includes. You can learn about these advanced topics in IBM
Rational Unified Process. Another good reference is Use Case Modeling by Kurt Bittner and Ian Spence (Addison-Wesley 2003).
Lame! (1)
Comments?
Submit feedback
developerWorks
About IBM
> Rational
7/15/2004
Page 1 of 7
http://www-106.ibm.com/developerworks/rational/library/5360.html
Search for:
within
Use + - ( ) " "
IBM home
developerWorks
All of dW
Search help
> Rational
Contents:
The IBM Software
Development Platform
business partner ecosystem
The Eclipse tools integration
platform
Components of the IBM
Software Development
Platform
Support for the IBM
business partner ecosystem
About the author
Rate this article
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
One of the major success factors for enterprises pursuing an On Demand business model is software development capability. In fact,
software development capability is a strategic corporate resource. More than ever, corporate responsiveness and agility depend on IT
initiatives. And based on its experience with thousands of projects, IBM has learned that the most successful IT departments follow four
imperatives to deliver high-quality software quickly and at a lower cost than is typical:
z
z
z
z
Develop iteratively
Focus on architecture
Continuously ensure quality
Manage change and assets
These imperatives are the foundation of a multifaceted, integrated IBM Software Development Platform that can help developers build,
integrate, extend, modernize, and deploy software-based systems. IBMs primary objective for this Platform and its broad partner
ecosystem is to help clients optimize their software development processes and improve their ability to operate as an On Demand
business. Because the IBM Software Development Platform has an extensible architecture based on open standards, IBM clients can
choose from a range of complementary approaches and tools from IBM and other industry participants that effectively extend the Platform.
The IBM Software Development Platform is grounded in a holistic view of the application development lifecycle and its challenges. The On
Demand business model requires that development platforms support a rich, integrated development and deployment experience. This
approach is congruent with the desire developers have to acquire knowledge and skills that span the full lifecycle, from understanding the
business to monitoring and managing running applications. The Platform combines products and services from multiple sources that
support this full lifecycle involvement for corporate and individual developers, software vendors, and systems integrators.
By supporting open source and heterogeneous environments, and clearly defining application programming interfaces (APIs), the IBM
Software Development Platform ensures easy integration of new tools and lowers the cost of developing and integrating new enterprise
applications within existing environments. It also enables IT organizations to provide extended functionality quickly and easily, and at
relatively low cost.
Page 2 of 7
Horizontal extensions that add functionality for specific tasks, such as project risk
management, project impact assessment, and so on.
Horizontal integrations with other development tools, applications, and
frameworks to support work throughout the application development lifecycle.
Domain-specific extensions to enable functionality for specific industries and
industry applications.
The ecosystem is a key reason that the IBM Software Development Platform is an
industry leader. IBM plans to continue improving both its technology and the program
framework supporting the Platforms ecosystem to make it even easier for new partners
to join in.
7/15/2004
Page 3 of 7
Figure 1: Components of a development-tool chain based on the Eclipse framework, with potential
integration points
The Eclipse Modeling Framework
The Eclipse Modeling Framework (EMF) is a fundamental part of Eclipse, enabling the platforms modeling capabilities to interoperate
with other tools and applications. Developers can use the modeling framework and code generation facility to build tools and other
applications based on a structured data model. Described in the XML Metadata Interchange (XMI) specification an Object
Management Group (OMG) specification for adding information descriptors for data EMF provides tools and runtime support to
produce a set of Java classes for the model, a set of adapter classes that enable viewing and command-based editing of the model, and
a basic editor. Models can be specified using annotated Java, XML documents, or modeling tools such as IBM Rational Rose, and then
imported into EMF.
Most important, EMF serves as a common alphabet and provides a foundation for interoperability with other EMF-based tools and
applications. The UML standard for representing business and data models works in conjunction with EMF to create a common language.
Using this language, two applications that use the same API can exchange meaningful information. UML is currently evolving, based on
industry and user feedback; IBM, in conjunction with the OMG and other industry participants, is focusing significant effort on developing
UML 2.0.
7/15/2004
Page 4 of 7
processes from static code analysis through automated functional testing and performance testing.
Hyades will implement an OMG-defined UML testing profile to maintain test case, test trace, test objective, and verification artifacts. It will
allow testers to evaluate objectives related to performance and scalability for a range of real-world deployment environments, including
alternate mixes of server and network interconnection technologies. It will also support new approaches to quality assessment testing that
link the initial requirements definition, an object-oriented application model, and test-management evaluation tools.
Figure 2: The IBM Software Development Platform supports development teams and individuals in the
development process
The following sections describe the Platforms component products and relevant ecosystem member activities that add value to the
Platform.
7/15/2004
Page 5 of 7
IBM Lotus Domino Designer helps developers rapidly build, test, and deploy security- components, including ClearCase,
rich IBM Lotus Notes or Lotus Domino collaborative and/or mission-critical applications. ClearQuest, XDE and WebSphere Studio
Using the Lotus Domino Toolkit for WebSphere Studio, developers can start building
Application Developer. Flashline Inc. uses
JavaServer Pages simply by dragging and dropping existing Domino design elements, the IBM Software Development Platform to
such as forms, views, and agents.
increase enterprise visibility into how teams
are creating and using software assets. This
allows IT managers to determine whether
7/15/2004
Page 6 of 7
The strong market position of IBM Rational TestStudio has also encouraged strong
partner involvement. Products such as Scapa StressTest are integrated with Rationals
test products to broaden their value.We have already seen the benefits of integrating
our product with IBM Rational Visual Test software, and with the additional integration
of IBM Rational Suite TestStudio software, we provide a first-class test management framework option for our customers, says Scapa
CEO Mike Norman. This framework also allows companies to manage our Citrix testing tool in the same TestStudio they use to manage
their existing Rational test tools.
7/15/2004
Page 7 of 7
developerWorks.
Lame! (1)
Comments?
Submit feedback
developerWorks
About IBM
> Rational
7/15/2004
http://www-106.ibm.com/developerworks/rational/library/5318.html
Search for:
within
Use + - ( ) " "
IBM home
developerWorks
Page 1 of 15
All of dW
Search help
> Rational
Contents:
The approach
New process elements
Conclusion
from The Rational Edge: This paper traces the approach Unisys GPS Blueprinting used to evaluate
References
the Rational Unified Process in support of the Unisys Business Blueprint, a business and systems
modeling architecture that integrates business vision and IT execution to drive organizational agility. Appendix A: Related work
IBM Rational Unified Process, or RUP, provides an
outstanding foundation that allows Unisys to achieve a
higher level of process capabilities in many different CMMI
process areas. Moreover, RUP allows the selection and
customization of its process elements to adhere to the
particularities inherent in each Unisys Global Public
Sector project, program, or business unit.
Notes
About the author
Rate this article
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
7/15/2004
Page 2 of 15
CMMI is designed to help an organization improve processes used to manage the development, acquisition, and maintenance of products
or services. CMMI is used as a guide for selecting process improvement strategies by facilitating the determination of current process
capabilities and the identification of the issues most critical to software quality and process improvement.
The problem
Based on the assumption that there are fundamental practices that should be incorporated in all the processes executed in the
organization, a standard process for an organization is typically defined by considering best practices and suggestions from international
standards, industrial organizations, governmental guidelines, in-house best practices, etc. (e.g., RUP, ISO/IEC 12207, etc). But for each
project, the standard process must be adapted to the particularities of the organization and the project itself.
Following this strategy, Unisys created the Unisys Business Blueprint. This is a business and systems modeling architecture that
integrates business vision and IT execution to drive organizational agility. To make organizations successful in meeting the requirements
of today's fast-paced information world Unisys has developed Blueprinting to align business with information technology and provide
traceability across the whole enterprise. Blueprinting is now the foundation for most of the Unisys business operations, including Unisys
GPS geographies, programs, and projects. All are encouraged to use Unisys Business Blueprint Methodology for development,
management, and transition of Unisys solutions.
RUP is an important component of Unisys Business Blueprint. RUP allows us to select and customize its process elements to adhere to
the particularities inherent in each Unisys GPS project, program, or business unit. Moreover, RUP provides an outstanding foundation
that allows Unisys to achieve a higher level of process capabilities in many different CMMI process areas.
However, RUP is weak in some CMMI process areas. In a comprehensive study performed by the Software Engineering Institute, RUP
was assessed against CMMI Continuous Representation.4 Although RUP performed well in most of the CMMI process areas, the
following weaknesses were identified:
Supplier Agreement Management is out of the scope of RUP; that is, RUP in its current form does not explicitly deal with
managing work from external suppliers to the project. This is an issue for projects in which Unisys needs to employ
subcontractors.
RUP does not explicitly support all the Technical Solution Process Area's practices. For example, RUP does not explicitly
cover consideration of design alternatives except at the architectural level, and RUP does not explicitly cover the use of
selection criteria for product solutions or components.
In a 2003 study, Manzoni and Price evaluated RUP against SW-CMM.5 For each key practice (KP) identified in each key process area
(KPA) of SW-CMM levels 2 and 3, the Rational Unified Process was assessed to determine whether it satisfied the KPA or not. The report
concluded that an organization using RUP would need to complement it to conform to SW-CMM. According to the study, SW-CMM key
process areas best supported by RUP are requirements management, software project planning, software project tracking and oversight,
software configuration management, organization process definition, and software product engineering. RUP offers good support to both
integrated software management and inter-group coordination KPAs; RUP offers low support for software quality assurance, organization
process focus, and peer review KPAs; and RUP does not support software subcontract management or training KPAs.
Based on these analytical studies, we conclude that an organization would need to enhance its version of RUP to improve its process
capabilities.
The approach
In this section, I will describe the approach Unisys GPS Blueprint is using to enhance Unisys Blueprint Methodology to increase its level
of compliance with CMMI. As indicated in Figure 1, there is a symbiotic relationship between assessment, capability maturity
determination, and process improvement.6 The capacity determination of a process in our case, the Unisys Blueprint methodology, or
more precisely the RUP product is used to identify weaknesses that motivate improvements. Such improvements reflect changes in
the process in our case, changes to the RUP product.
7/15/2004
Page 3 of 15
Characterize and understand the organization and its process capabilities. To do so, perform capability determination and process
7/15/2004
Page 4 of 15
assessment of the current projects and its environment with respect to reference models and metrics.
2.
3.
Choose the appropriate process and supporting techniques, methods, and tools. New processes may need to be created.
However, it is much more likely that existing processes will be tailored to fulfill the gaps identified during the characterization and
understanding of the organization.
4.
Execute the processes, construct the products, and collect and validate the prescribed data. According to AINSI,9 after issues are
identified and improvement options determined, a pilot project should be executed using new practices and/or tools. The scope,
participants, and project evaluation strategy should be defined before its execution. After the pilot project execution is finished and
the results are analyzed, the technology might be transferred to the rest of the organization or other pilot projects should be
executed.
5.
Analyze the data to evaluate the current practices, determine problems, record findings, and recommend future project
improvements. This step is crucial to the success of this solution. It is here that both project and organization learning is leveraged.
The feedback obtained by analyzing the measurable goals and process effectiveness will support the continuous improvement of
both our business and our methodology.
6.
Package the experience in the form of models and other forms of structured knowledge.
The following sections outline the approach to be used in each of the above steps.
Capability determination and process assessment
In the study performed by the Software Engineering Institute, RUP was assessed against CMMI Continuous Representation.10 The
weaknesses of RUP regarding this reference model have been identified and suggestions for improvement have been outlined.
Set quantifiable goals
The Goal/Question/Metric (GQM) is the method for defining software measurement.11 GQM allows us to define a measurement model on
three levels:
z
Conceptual level (goal): A goal is defined for an object, for a variety of reasons, with respect to various models of quality, from
various points of view, and relative to a particular environment/project.
Operational level (question): A set of questions is used to define models of the object of study and then focuses on that object to
characterize the assessment or achievement of a specific goal.
Quantitative level (metric): A set of metrics, based on the models, is associated with every question in order to answer it in a
measurable way.
GOAL
Purpose
Improve RUP
Issue
Process Area
Viewpoint
Process Engineer
Environment
Solution Development
QUESTION What is the current level of compliance between RUP and CMMI Technical Solution process area?
METRIC
7/15/2004
Page 5 of 15
Table 2: Specific process practices from CMMI Technical Solution and Supplier Agreement Management
process areas weakly supported by RUP
Process Area
Specific Goal
Specific Process
Practice
Description
Technical Solution
SG 1 Select Product-Component
Solutions
TS SP 1.1-1
TS SP 1.1-2
TS SP 1.3-1
TS SP 2.4-3
SG 1 Establish Supplier
Agreements
SAM SP 1.1-1
SAM SP 1.2-1
Select Suppliers
SAM SP 1.3-1
SAM SP 2.1-1
SAM SP 2.2-1
SAM SP 2.3-1
SAM SP 2.4-1
Transition Products
Supplier Agreement
Management
SG 2 Satisfy Supplier
Agreements
Table 3 shows the process models we analyzed and their compliance with CMMI Technical Solution's Specific Process practices. CMMI
Supplier Agreement Management's Specific Process practices are not included since RUP does not provide any specific support to them.
The compliance level is indicated by Low, Medium or High (L, M, H).
7/15/2004
RUP
Page 6 of 15
Note that the RUP benchmarking was extracted from Gallagher & Brownsword 2001 RUP/CMMI tutorial.12 Our results can be further
explained as follows:
Rational Unified Process. We replicated here the results of the assessment conducted by SEI where RUP was benchmarked against
CMMI Continuous Representation. Only the specific practices considered as either low or medium supported by RUP are shown.
NASA SEL COTS-based process.13 After investigating fifteen projects developed according to NASA COTS-based software
development, Morisio and colleagues proposed new process elements for COTS (Commercial Off-the-Shelf available software)
identification, selection, and integration. For instance, the requirement process was enhanced with the following activities: make versus
buy decision, COTS identification and selection, and COTS familiarization. Table 4 shows the synergy between this process model and
the CMMI Technical Solution process area.
Table 4: Synergy between NASA SEL COTS-based process (Morisio et al., 2001) and CMMI Technical
Solution process area
Specific
Process
Procedure
Description
NASA SEL
COTS-based
process
Comments
TS SP 1.3-1
Requirements
Definition.
COTS
Identification and
Selection.
TS SP 2.4-3
OTSO COTS Selection Process. Kontio14 proposes a method for searching, screening and evaluting COTS. This method was
successfully applied in two case studies carried out with Hughes Corporation in the EOS program developed for NASA. Software
Productivity Consortium embraced this method as part of its COTS purchase process (SPC, 1989). Table 5 presents the synergy
between OTSO and CMMI Technical Solution and Supplier Management process areas.
Table 5: Synergy between OTSO and CMMI Technical Solution and Supplier Management process areas
Specific
Process
Procedure
Description
OTSO Process
Elements
Comments
TS SP 1.1-1
Search criteria
definition
TS SP 1.1-2
Detailed
evaluation
criteria
definition
Weighing of
criteria
7/15/2004
TS SP 1.3-1
SAM SP 2.1-1
Analysis of results
Page 7 of 15
SPC's Subcontracting Products or Services for Software-Intensive Systems Guidebook. This provides a process for managing
subcontracting of products or services. The first activity of this process is to perform the make vs. buy analysis. This activity describes the
use of a balanced scorecard to identify and focus on business needs when evaluating make versus buy alternatives (SPC, 2001). The
scorecard contains financial performance, customer satisfaction, internal process, learning and innovation, and sourcing liability factors,
along with strategies to optimize performance for those factors that relate to business needs. Table 6 presents the synergy between this
process, more specifically between the activity to perform make vs. buy analsyis and the CMMI Technical Solution.
Table 6: Synergy between SPC's guidebook and CMMI Technical Solution and Supplier Management
process areas
Specific
Process
Practices
Description
SPC's Process
Element
TS SP 2.4-3
SAM SP
1.1-1
SAM SP
1.2-1
Comments
7/15/2004
SAM SP
1.3-1
Agree to Terms
SAM SP
2.1-1
SAM SP
2.2-1
Perform
Make vs.
Buy
Analysis
Solicit and
Select
Supplier
Manage the
Relationship
z
z
Accept the
Products and
Services
Transition the
Product or
Service
SAM SP
2.4-1
SOW
Supplier agreement (e.g., contract, MOU)
Update of the project's plans and risk plans
Supplied product or service specifications
SMP (Supplier Management Plan)
z
z
z
SAM SP
2.3-1
Page 8 of 15
In this section, we presented an overview of the process models we investigated to address the weakness of RUP with regards to CMMI
Technical Solution and Supplier Management process areas. Three process models (in addition to RUP) were analyzed. We indicated the
level of synergy of these processes and CMMI. The three cited processes inspired us to propose the creation of new process elements to
extend RUP. Later on, we will present how this was done.
7/15/2004
Page 9 of 15
7/15/2004
Page 10 of 15
7/15/2004
Page 11 of 15
in the component evaluation process.17 The organizational characteristics provided in the Software Development Document, customer
needs indicated in the Vision document, and project specifications provided in the Software Requirement Specification (SRS) and
Supplementary Specification are used by the project manager to create the component evaluation plan. This plan would enrich the
Software Development Document and defines the level of effort for each activity to be performed in the component evaluation process.
Each iteration may require this plan be redefined for one or more of the process activities. Further details about Software Development
Document, SRS, Supplementary Specification and Vision artifacts can be found in RUP.
Perform COTS evaluation. This activity addresses the problems of evaluating, comparing, and selecting components.18 This activity
would complement the Analysis and Design discipline more precisely, the workflow detail: perform architectural synthesis activity.
Although this activity focuses on off-the-shelf components, it applies to all types of components large or small. This activity is strongly
related to the architectural synthesis. It deals with evaluating components that already exist within the project or that have been created in
previous iterations or system versions, or COTS that have been requested to be part of the system. The architect is primarily responsible
for this activity. As recommended by Kontio (1995) and SPC, this activity can be decomposed in the following sub-activities: search and
screen candidates, define evaluation criteria, evaluate component alternatives, and analyze evaluation results. Figure 4 shows the
product flow of these sub-activities.
Based on the results provided by this activity, the architect can generate change requests related to the proposed architecture and/or
requirements. These change requests would be managed using the project change management process as recommended in RUP. The
main output of this activity would be a list of selected components indicating the components chosen for inclusion in the system as a
result of the evaluation process. As far as RUP artifacts are concerned, this list would be included in the Software Architecture Document.
7/15/2004
Page 12 of 15
Transition COTS product. This activity's main goal is to transit the acquired products from the supplier to the project.20 The project
manager must ensure that an adequate infrastructure is in place to receive, store, use, and maintain the acquired components. In
addition, appropriate training must be provided for those involved in receiving, storing, using, and maintaining the acquired products.
Finally, the project manager should make sure that storing, distributing, and using the acquired products are performed according to the
terms and conditions specified in the supplier agreement or license.
Conclusion
RUP is the de facto industry standard for project lifecycle development and management. Unisys integrates RUP into its Business
Blueprint methodology to provide a highly mature process across the entire organization. However, RUP presents low-process capability
regarding some CMMI software process areas and needs improvement. To clearly identify these weaknesses and improve RUP to
overcome them, we have used an empirically validated and technically sound software process improvement approach called QIP. As a
result, a process model based on the Rational Unified Process concepts was proposed to enhance RUP compliance to CMMI. To verify
the efficiency and efficacy of the proposed process model, we are currently validating it on pilot projects. To roll it out in the entire
organization, we are proposing the integration of this new capability via a CMMI plug-in for RUP. Finally, we believe that other groups can
apply the approach we have described in this paper to mitigate risks in other process areas.
References
V. Basili, G. Caldiera and D. Rombach, "The Goal Question Metric Approach."Encyclopedia of Software Engineering. Wiley 1994.
V. R. Basili, M. K. Daskalantonakis, R. H. Yacobellis. "Technology Transfer at MOTOROLA," IEEE Software, 11(2): 70-76.
L. Briand; K. El Eman; W. L. Melo. "AINSI: An inductive method for software process improvement: concrete steps and guidelines." In K.
El Eman and N. H, Madhavji (eds.), Elements of Software Process Assessment and Improvement. 1999. IEEE Press.
CMMI Product Team. Capability Maturity Model Integration (CMMISM), Version 1.1, Continuous Representation, CMU/SEI-2002-TR-011,
2002.
CMMI Product Team. Capability Maturity Model Integration (CMMISM), Version 1.1, Staged Representation, CMU/SEI-2002-TR-012,
ESC-TR-2002-012, 2002.
K. El Emam; J.-N. Drouin; W. Melo. SPICE: The Theory and Practice of Software Process Improvement and Capability Determination.
IEEE Press. 1998.
B. Gallagher & L. Brownsword. "The Rational Unified Process and the Capability Maturity Model Integrated Systems/Software
Engineering." RUP/CMMI Tutorial ESEPG, 2001.
R. Grady, Successful Software Process Improvement, Prentice-Hall, 1997.
T. Kilpi, "Implementing a Software Metrics Program at Nokia," IEEE Software, 18(6):72-77, 2001.
J. Kontio. "A Case Study in Applying a Systematic Method for COTS Selection,"Proc. of the 18th Int. Conf. on Software Engineering, IEEE
CS Press, March 1996.
F. McGarry et .al. "An Overview of the NASA Software Engineering Laboratory." NASA SEL, Technical Reports, SEL-94-005, 1994.
ISO/IEC TR 15504-1. "Information technology Software process assessment Part 1: Concepts and introductory guide." 1998.
L.V. Manzoni, "Using a Workflow Management System to Support Software Development Based on Extended Rational Unified Process to
Reach Maturity Model Levels 2 and 3," Master Dissertation, Inst. of Informatics, Federal Univ. of Rio Grande do Sul, Porto Alegre, Brazil,
2001, http://www.inf.ufrgs.br/amadeus/atuais/lisandra.html.
L. V. Manzoni & R. T. Price. "Identifying Extensions Required by RUP to Comply with CMM Levels 2 and 3." IEEE TSE, Vol. 29, No. 2,
February 2003.
M. Morisio, C.B. Seaman, V.R. Basili, A.T. Parra, S.E. Kraft, S.E. Condon. "COTS-Based Software Development: Processes and Open
Issues."Journal of Software and Systems, 2001.
M. Paulk. Capability Maturity Model for Software, Version 1.1. Addison-Wesley.1993.
7/15/2004
Page 13 of 15
Notes
1Any opinions, findings, and conclusions or recommendations expressed in this paper are those of the author(s) and do not necessarily
reflect the views of Unisys Corporation.
2B. Gallagher & L. Brownsword. "The Rational Unified Process and the Capability Maturity Model Integrated Systems/Software
7/15/2004
Page 14 of 15
February 2003.
6 K. El Emam; J.-N. Drouin; W. Melo. SPICE: The Theory and Practice of Software Process Improvement and Capability Determination.
Process Improvement, Prentice-Hall, 1997. For NASA, see F. McGarry et. al. "An Overview of the NASA Software Engineering
Laboratory," NASA SEL, Technical Reports, SEL-94-005, 1994. For Nokia, see T. Kilpi, "Implementing a Software Metrics Program at
Nokia", IEEE Software, 18(6):72-77, 2001. For Motorola, see V. R. Basili, M. K. Daskalantonakis, R. H. Yacobellis. "Technology Transfer
at Motorola," IEEE Software, 11(2): 70-76.
8 V. Basili, "Software Improvement Feedback Loops: The SEL Experience," 10th Software Development Expo & Conference (SODEC),
7/15/2004
Page 1 of 13
http://www-106.ibm.com/developerworks/rational/library/5335.html
Search for:
Use + - ( ) " "
IBM home
developerWorks
All of dW
within
Search help
> Rational
Contents:
Input artifacts
Creating the iteration plan
Summary
Notes
About the author
Rate this article
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
Input artifacts
To create your iteration plan you really only need two
basic inputs. First, you need to know what RUP phase the planned iteration belongs to, and second, you need a well-written RUP
development case. Knowing the phase will allow you to create the right kind of plan. Having the development case will tell you exactly
what the plan should contain.
7/15/2004
Page 2 of 13
7/15/2004
Page 3 of 13
7/15/2004
Page 4 of 13
Based on these descriptions and the description of Inception, I would probably expect analyze the problem, understand stakeholder
needs, define the system, and manage the scope of the system to be planned for the first inception iteration, but not the other two
workflow details. If Inception had more than one iteration I might see manage changing requirements kicking in, but still not refine the
system definition. Your decisions might be different and it might also differ for each project under your care.
It is not the project managers job to decide which workflow details to perform in each iteration; it is the teams decision. Basically, the job
of the project manager comes down to three tasks, and everything else folds up into them: 1. Plan/Re-Plan 2. Track to Plan 3. Manage
Risks to the Plan. Thats pretty much it. I consider status activities part of tracking-to-plan. And Im open to disagreement on this
simplification.
After the team decides what to do via a development case, the project manager should create the plan from the development case they
create. Lets consider one more example of how to tailor the generic RUP workflow based on the current RUP phase, this time using the
Analysis and Design workflow in RUP.
7/15/2004
Page 5 of 13
support the requirements of the solution. This requires taking the highest-risk requirements all the way through code to test and possibly
internal or external deployment. Given this, we will probably need all five of the other workflow details in the Elaboration phase.
During the Construction phase, we build the rest of the flows that we didnt build as part of elaboration, and we are no longer worried
about architecture, focused instead on delivering the highest value solution possible. Based on this, we probably would only need analyze
behavior, design components, and design the database.
During the Transition phase, when we are supporting the solution once it has been fully deployed, we would use the same activities as in
Construction; but the focus would be more on change requests than use cases.
You can repeat this exercise for the workflow details of the Requirements discipline shown above and for all of the other seven disciplines
of RUP. The best part is that you dont need to do this for all four phases at once! Remember that writing the development case and
planning based on it is iterative, so you can focus on this iteration only and, therefore, only on the current phase. If the next iteration on
the plan will belong to the next RUP phase, then you can proceed to detail your next phase in your development case. This is easier,
quicker, and more accurate than waterfall planning for an entire project at once.
Children tasks
If you do the above for each workflow it shouldnt take too long to create a development case for a single phase. But we do need to add a
few children tasks. Many managers try to add the activities within each workflow detail, but in general this will cause problems.
First, this will result in significant delays to creating your plan, as there are an awful lot of activities within the workflow details. You will
likely spend more time planning some of these tasks than implementing them. You can create a very manageable plan without that added
level of detail. Second, many of the activities repeat in different workflow details. Just check out the first four workflow details in the
requirements discipline, and you will see the develop vision activity appear every time, with no indication of what is different in each RUP
phase. So I recommend that you avoid using the RUP activities on your project plan.
On the other hand, we do need to understand what resources are being applied to what tasks. So instead of making each activity a child
task to the workflow detail in our development case, we should create one child task per role involved in the workflow detail that we plan
to use. Lets look at some examples.
7/15/2004
Page 6 of 13
Notice in Figure 4, in the yellow rectangle, that there is only one resource with three activities. In this case we do not need to add any
children tasks to the plan, as the single role will handle all activities.
7/15/2004
Page 7 of 13
Identifying the knock-off tasks is an area in which a consultant or someone with significant RUP experience can dramatically reduce the
time to value. We are NOT trying to duplicate RUP here. We are simplifying RUP considerably in this step. You will still need to use RUP
for additional details.
Here are a couple of examples. For Analysis and Design, the knock-off tasks for each workflow detail might look like the list in Table 1,
which Ive taken from the standard development case I give to my clients.
7/15/2004
Page 8 of 13
7/15/2004
Page 9 of 13
This standard example is fairly simple. It does not describe the input and output artifacts, but this amount of detail is extremely valuable to
the team. And although this development case is fairly simplistic, it fits on a single page, which also can be an advantage to a new team.1
Table 2 shows more complex entry for a single workflow detail in the project management discipline. This is taken from another
development case template that I share with my clients (note that the business context in Table 2 is different from that in Table 1).
z
z
z
Write business
case
Write Risk List
Share with PRA
and gain
funding for
Inception phase
Purpose
Role
Project
manager
Average time
Established
environment
New
environment
1 day
1 day
In the example shown in Table 2, far more detail has been provided. This level of detail evolved over time. Trying to get to this level of
detail on every workflow detail at once would take more time than our projects have to spare.
Remember, while it is the job of the project manager to ensure a development case is written to guide their planning, the team that will be
following the plan should create the development case together. This is how the team influences what gets placed on the plan.
7/15/2004
Page 10 of 13
7/15/2004
Page 11 of 13
So the plan was in sequential order, but the development case was in discipline order, and the project managers had a harder time trying
to reconcile the two. To fix this problem, the project managers attempted to modify the template so that the workflow details were in
sequential order to better match the iteration plan. The table of contents then looked more like Table 4.
7/15/2004
Page 12 of 13
This worked well for planning because the project managers could, for the most part, cut and paste the table of contents into their project
plan. But now it became harder for the rest of the team to find the tasks they owned, since they were no longer logically grouped, so
ultimately this was deemed a poor choice. We saved the template, of course, to remind ourselves of the attempt. By the way, the current
recommendation for iteration plans in RUP is to organize both the plan and the development case by discipline.
Writing queries to identify critical tasks
During that project, we also created a few Microsoft Project queries to help the project managers look for a clear, single view of
interdependent tasks. This is because the plans could span pages vertically, and a task listed low on a given page might be slated for the
first week with many entries for subsequent weeks above it.
The queries are easy to write: List all tasks starting this week (or whatever dates you choose), list all tasks ending this week, and list all
tasks ongoing this week. The project manager would then run these three queries and print out the results, then proactively wander
around to the team asking Are you going to start this on time? Are you going to complete this on time? How are these items going? How
can I help?
Using the RUP work order
In addition to the workflow details, I recommend that you put in the role-specific children tasks as well, and assign them the appropriate
resources. But DONT put in the knock-off tasks, or your plan will be too granular to manage well. It will take too long to create and will be
difficult to modify when changes become necessary.
Instead, use another RUP artifact called the work order, which RUP defines as follows: The work order is the project manager's means of
communicating what is to be done, and when, to the responsible staff. It becomes an internal contract between the Project Manager and
those assigned responsibility for completion.
It goes on to say you can use a whiteboard, and the project plan for tracking, or use IBM Rational ClearQuest to track them automatically.
The idea is you jot down the knock-off tasks with the resource responsible for the task separate from the project plan. When the knock-off
tasks are done, the work order is complete and we mark it complete in MS Project. There is even an integration between MS Project and
ClearQuest that allows you to plan in MS Project, generate work order records, and have the plan update itself when the work orders are
marked complete in ClearQuest.
Another technique is to assign all the work orders to the team member, who can jump from one to another if the work orders get blocked,
raising any needed risks (also via IBM Rational ClearQuest) in the process. If a team member ever runs out of work orders he can camp
out in front of the PMs office with a sandwich until he gets new ones, or he can switch to another project and get new work orders from
different managers.
The point is this: If you plan too deeply, your planning will simply take too long and be difficult to manage and track against. Work orders
can give you the granular level of management you need without the overhead.
7/15/2004
Page 13 of 13
Summary
A well-written development case should show the projects process not just the artifacts. The process is described by outlining which
workflow details the project will be targeting. The project team writes the development case. The project manager uses the development
case to create a work breakdown structure in his preferred tool and works with the team to assign times and dependencies. The plan
should not detail the activity level but should have one subtask per workflow detail if there is more than one role involved. The
development case should list detailed knock-off tasks for each task, but these should not be in the iteration plan. Instead, work orders
should be used to track the more granular knock-off tasks.
Notes
1 In appearance, this development case differs widely from the standard RUP template in that it doesnt discuss artifacts at all. See my
article on the artifacts of Analysis and Design to understand the three artifacts you will need to use for all six of these steps.
Lame! (1)
Comments?
Submit feedback
developerWorks
About IBM
> Rational
7/15/2004
Page 1 of 10
http://www-106.ibm.com/developerworks/rational/library/5317.html
Search for:
within
Use + - ( ) " "
IBM home
developerWorks
All of dW
Search help
> Rational
Contents:
What is a work component?
Structure of a work
component
Realizing a work component
Setting up a RUP project
schedule using work
components
Benefits of work components
Assessing project status
using work components
Developing organizationwide work components
Estimating projects using
work components
Even when project managers do succeed in creating a Gantt chart, the major units of work get
shredded across various disciplines and the work does not flow in the typical way, from top left to
bottom right in the chart. This makes it hard for business and technical managers to see continuity
for the work unit.
Subscriptions:
dW newsletters
Notes
About the author
Rate this article
dW Subscription
(CDs and downloads)
Often such charts evolve into big, incoherent artifacts that demand a lot of maintenance on the
project manager's part but deliver little incremental planning value.
Figure 1 below shows a typical Gantt chart for the RUP Elaboration phase, including workflow details under disciplines. For example,
"design components" is a workflow detail under the Analysis and Design discipline.
7/15/2004
Page 2 of 10
The PMO wants to look at the summary tasks (disciplines and then workflow details) to quickly understand the chart's main themes
major objectives the project team plans to accomplish. Unfortunately, the project manager did not make the chart easy to understand; the
major objectives, who owns them, and their expected results are inconspicuous.
So how do you capture the essence of RUP in a Gantt chart, while keeping the chart readable and manageable?
7/15/2004
Page 3 of 10
Figure 2 : RUP Elaboration Gantt chart showing a work component that encapsulates workflow details
Click to enlarge
We define work components as follows:
A work component is a work planning entity that encapsulates all work done towards achieving one objective under the
responsibility of one owner, in terms of one or more workflows enacted by one or more workers. These workflows may
generate none or more work products based on none or more inputs, and deliver one result that fulfils the objective and is
tangible to the key beneficiaries of the work component.
Put simply, a work component has:
{
One objective
One owner
A work component is somewhat like a printed circuit board1 with well-defined I/O (inputs/outputs) and a specific functionality. Just as with
a circuit board, as long as the work component satisfies its objective, the "wiring" inside need not concern the user. And, like circuit
boards, work components can range from very complex to quite simple, depending upon the depth of activities it encapsulates.
For example, the work component "define QA strategy" might be very simple because a knowledgeable QA manager is the owner and
sole resource for it, whereas the work component "build architectural prototype" might be very complex. (In some organizations the
complexity level might be reversed!)
Work components are polymorphic; you can reuse them if you first customize them for your particular implementation. In other words, two
work components might have the same name, objective, owner, and result but different workflow details, roles, activities, and work
7/15/2004
Page 4 of 10
An organization might create this work component for a greenfield project to prototype the architecture. Subsequently, if it wanted to use
the work component for a project to enhance an application developed in a previous project, it might keep the same name, objective,
owner, and result but omit the workflow details "analyze behavior" and "structure the implementation model." Or, if it wanted to use the
work component in a project to implement RUP within the organization, again it would keep the same name, objective, owner, and result
but use very different workflow details, roles, activities, and work products related to process architecture rather than application
architecture.
7/15/2004
Page 5 of 10
Objective
Owner
Inputs (optional)
Workflow
Result
Note that the term workflow as we use it in Figure 1 and Table 1 is synonymous with RUP workflow detail. Also, an input is not
synonymous with an entry point. You can have entries and dependencies between work components anywhere within a workflow detail
(similar to the entries and dependencies on a printed circuit board).
Figure 4 is an example of the work component "build architectural prototype," which could be used in the Elaboration phase of a RUP
project.
7/15/2004
Page 6 of 10
7/15/2004
Page 7 of 10
Figure 6: Example specification (partial) for the work component "define scope"
A full explanation of this process is beyond the scope of this article. Organizations using work components (such as Covansys) make
step-by-step guidelines available for users on their intranets.3
The completed plan could look like the one in Figure 7.
7/15/2004
Page 8 of 10
The PMO now understands the Gantt chart's main themes major things the project will accomplish. The PM has made these
conspicuous by encapsulating planning elements into work components.
They reduce the complexity of Gantt charts that detail widely dispersed tasks by encapsulating workflow details.
Unlike summary tasks, they assign single ownership and a single result to major chunks of work, thereby improving accountability
and assessment capability.
They present stakeholders with a clear, functional picture of what they need to know (e.g., in Figure 7, a business owner could
readily identify the work component "define scope").
Organizations can store and make them available to users through work component libraries with corresponding online help.
7/15/2004
Page 9 of 10
Standard work components can have default workflow details, activities, resources, and work products that users can instantiate
and customize.
They provide common measures for assessment and work estimation across organizations.
Work products
Individual disciplines
Individual workflows
Develop an organization-wide framework for collecting and reviewing feedback on work components in active projects.
A project management work component team consisting of work component owners for "set up project," "manage
Inception," and so forth.
A requirements work component team consisting of owners of work components for "define scope", "detail requirements"
and "detail user interface."
Have each work component team collect feedback on its components from designated pilot projects.
Have the teams modify and finalize the work components, based on the guidelines and feedback. As we mentioned above, you
can have multiple implementations of a work component (e.g., complex, medium, and light).
Have the teams formally archive and publish their work components for organization-wide use.
7/15/2004
Page 10 of 10
and the user interface. An organizational record of the effort required for "define scope" on small, medium and large projects would
provide a basis for estimating the effort required to define Inception-level scope for a given project type.
Notes
1 A printed circuit board contains electronic components and pins for input and output connections. Once the board is plugged in to a
circuit, it delivers specific functionality amplifying the sound in a radio, for example.
2 A grouping of activities performed in close collaboration to accomplish some result. Typically, the activities are performed either in
parallel or iteratively, with output from one activity serving as input for another activity. Grouping these activities in a workflow detail
provides a higher level of abstraction and improves the comprehensibility of workflows.
3 If you or your organization is interested in using work components, I invite you to contact me at 847-969-3049 or
kvaidya@covansys.com.
Lame! (1)
Comments?
Submit feedback
developerWorks
About IBM
> Rational
7/15/2004
Page 1 of 6
http://www-106.ibm.com/developerworks/rational/library/5390.html
Search for:
within
Use + - ( ) " "
IBM home
developerWorks
All of dW
Search help
> Rational
Contents:
What are formal methods?
UML and OCL
OCL as a specification
from The Rational Edge: This article discusses various uses of OCL (Object Constraint Language)
language
for both developers and testers. IT also enumerates the many advantages of the language, which is
Testers like it, too
part of the UML specification.
Conclusion
If you were a computer science or software engineering
References
major in college, you probably had to take a course in the
Notes
foundations of computer science or formal methods. And
if you did, you probably thought, What will I ever use this
About the author
for?
Rate this article
Since I have devoted a significant part of my career to
working with language tools, formal methods are
important to me. But they also have a lot of value for
software practitioners, especially when they are
embedded in a specification language, such as OCL
(Object Constraint Language). In this article, I will share
with you why I value OCL and how I apply it.
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
7/15/2004
Page 2 of 6
However, OCL, a formal specification language that is part of the UML specification, enables you to annotate models with expressions
that clarify meaning. In UML 1.1, the main purpose of OCL was to identify the constraints on model elements. For example, it could help
you indicate that, to be assigned a room, a specific course must have at least six students enrolled. With OCL you could annotate the
association between the Course and Classroom classes to represent the constraint, as shown in Figure 1. As an alternative to the note
shown in this figure, you could use a constraint connector between the Course and Classroom classes.
7/15/2004
Page 3 of 6
A simple example
In last months column we looked at a triangle tester program that accepted three numbers and determined what type of triangle, if any,
has sides with corresponding lengths. Lets specify this in OCL.
Our method, kindOfTriangle, returned the object TriangleType, which enabled us to determine the type of triangle. The specification
for this method is shown in Code sample 1.
http://qacma.cupertino.ibm.com/cma/PreviewXMLArticle?CONTENT_ID=5390
7/16/2004
Page 4 of 6
implementation details, such as what the data storage mechanism should be. If we remove implementation details, we get to the heart of
the problem and create a clearer specification.
The third feature of an OCL specification is that it is declarative, specifying only the what and not the how. There is no description of any
change in state or assignment to variables. OCL expressions are said to be side-effect free. In short, what you see is what you get.
Now lets go back and analyze Code sample 1. The first line tells us what the specification applies to its context. It is for the
kindOfTriangle operation in the TriangleTester class, and the operation returns a value of type TriangleType. Other kinds of context
declarations are defined in OCL for UML classifiers, attributes, and operations.
The second line describes the preconditions for this operation things that must be true for the operation to work properly. If you are
practicing design by contract,5 and the client must guarantee that contract conditions are met before invoking an operation, the clients
part of the contract is specified by the preconditions.
The rest of the specification consists of the post-conditions. This is the service side of the contract. If the preconditions are met, the
implementer agrees to produce the results specified by the post-conditions. If you have programmed in almost any modern programming
language, you should be able to read and understand the post-condition specification.
There is more to OCL than just context, preconditions, and post-conditions. It has syntax for describing invariants in a context, initial
values, queries, and so on. Also, OCL does not employ a lot of mathematical notation. Most of its notation is readily accessible to
software developers.
Jotting down specifications in OCL, whether you are planning to include them in a formal document, make them into comments in your
code, or throw them away, is a useful exercise. It helps you, as a software developer, to clarify what your real task is. But its not the only
use for OCL.
7/15/2004
Page 5 of 6
The tests described in Table 1 clearly are not complete. However they provide at least a basic test of the post-conditions defined in the
Code sample 1 specification. Depending upon the priority and criticality of the feature and the risks of not completely testing all possible
combinations, we can either stop here or add as many test cases as necessary.
I have found that creating test cases from OCL specifications is a straightforward task. Programmers and testers who use OCL can
become very good at ensuring that the specifications are correct and the tests really address them. In fact, you could use OCL in
combination with the TFP technique I described in last months column to design tests from a well-formed, independent specification.
When I teach software testing classes at WPI, I have students write OCL specifications for methods that lack other specifications. This
helps them do a better job of testing because they are able to isolate the methods real requirements or those the implementer
perceives and write appropriate tests for them. Sometimes, implementers find that perceived requirements do not match actual ones.
OCL can help by creating a concise, readable, and analyzable specification.
Conclusion
OCL is not the only formal language that can be used for specification, nor is it the most rigorous or complete one. But it does have some
important things going for it:
z
You do not even need to use OCL with the rest of UML to realize its benefits. Like any new technique, you have to learn it, begin to use it,
refine your skills, and keep in mind the end goal: producing reliable software.
In general, it is useful to study and embrace formal methods as a way of thinking. The software professionals I know who have done so
are, in my opinion, some of the best analysts, designers, and programmers that I have ever had the privilege of working with. There is
something about thinking formally that is well-suited to developing computer software. If you have a chance to take a course in formal
methods, I urge you to do so and then note how it makes you better at what you do.
References
Information about OCL and the OCL specification can be found at http://www.omg.org.
Jos Warmer and Anne Kleppe, The Object Constraint Language, 2e. Addison-Wesley, 2003 (ISBN: 0321179366)
7/15/2004
Page 6 of 6
Joseph A. Goguens Web page contains his publications on software engineering, architecture, formal methods, and methodology:
http://www.cs.ucsd.edu/users/goguen/projs/swarch.html
Peter Ryan and Chris Sennett, eds., Formal Methods in Systems Engineering. Springer-Verlag, 1993. (ISBN: 3540197516)
Notes
1 Joseph A. Goguen in the Introduction to Formal Methods in Systems Engineering, Ryan and Sennett, ed., Springer-Verlag, 1993.
2 This particular expression declares succinctly that an ordered collection, x, of n+1 integers, or some other comparable type, is sorted in
ascending order.
3 The predicate calculus is a logic consisting of predicate expressions that evaluate whether something is true or false. It has the typical
logical operations, such as AND and OR, and relational operators such as =, <, and so on.
4 An order of magnitude is a factor of ten. Two orders of magnitude sounds much more impressive than 100 times, dont you think?
5 Design by contract is associated mainly with Dr. Bertrand Meyer and his Eiffel programming language. See
business modelers to use and understand. OCL can be quite flexible in the syntax area.
Lame! (1)
Comments?
Submit feedback
developerWorks
About IBM
> Rational
7/15/2004
Book review: Eric Meyer on CSS: Mastering the Language of Web Design
Copyright IBM Corporation 2004.
http://www-106.ibm.com/developerworks/rational/library/5188.html
Search for:
within
Use + - ( ) " "
IBM home
developerWorks
Page 1 of 2
All of dW
Search help
> Rational
Contents:
Notes
About the author
from The Rational Edge: McKay reviews a book designed for experienced HTML users who want to Rate this article
improve their Web design capabilities. Using a project-oriented approach, the book takes readers
Subscriptions:
step by step through ways of applying cascading style sheet (CSS) techniques for purposes
dW newsletters
ranging from online greeting cards to input forms.
Eric A. Meyer
New Riders, 2002
ISBN: 0-7357-1245-X
Cover price: US$45.00
352 pages
dW Subscription
(CDs and downloads)
This is a wonderful book for HTML-proficient coders who wish to enhance the look and feel of their Web pages. In it, Meyer shows various
cascading style sheet (CSS) techniques that coders can use to update outdated HTML-only sites into manifestations of modern Web
technology. He assumes that readers have a basic knowledge of HTML and CSS, and will edit pure text files rather than using
WYSIWYG1 editors or Web editing tools such as Dreamweaver.
Meyer briefly examines motives for moving from the realm of straight HTML into the
Projects in Eric Meyer on CSS
world of a global style configuration with CSS. An external CSS file works just like a
1. Converting an existing page (stripping
configuration file, defining the aesthetic attributes of a page. By defining style elements in
a bloated HTML document down to a
a central location either a separate file or at the beginning of an HTML document
streamlined HTML file with
you can more easily change the look of an element type without having to modify each
accompanying CSS)
instance of it.
2. Styling a press release
3. Styling an events calendar
The book's style is very casual and interactive, which makes it feel like direct guidance
4. Bringing hyperlinks to life
from a teacher rather than a formal, impersonal manual or how-to book. Meyer's
5. How to skin a menu (adding effects to
discussions are also very detailed without being verbose, and he throws in the
make a menu attractive)
occasional (sometimes corny) joke. All the examples are straightforward and
6. Styling for print
unambiguous; Meyer's instructions leave nothing to question.
7. Making an input form look good
8. Creating an online greeting card
Each of the book's thirteen chapters contains an independent project (see sidebar).
9. Creating a multicolumn layout
Every project is a hands-on tool, carefully designed to give you everything you need to
10. Sneaking out of the box (adding
understand a particular task. At the beginning of each one, Meyer explicitly describes the
curves and acute/obtuse angles)
point of the project. From there, he starts with a plain, basic file and progressively
11. Positioning a better design (creating
modifies the style sheet and HTML in small, easy-to-digest steps. The book highlights
interesting page layouts without
the code changes at each step and includes a browser snapshot as well. By the time you
tables)
arrive at the end of a chapter, you know exactly what each line of code in the project's
12. Fixing your backgrounds (creating
style sheet means and why it is there.
cool, scrolling effects with fixed
backgrounds)
13.
Eric Meyer on CSS in CSS (recreating
For those who like to play along at home, the book has a companion Web site
the book layout in a browser)
(http://www.ericmeyeroncss.com) containing the projects' code. Meyer also provides
bonus materials and more examples for the book's lessons on this site. Although it does
not offer explanations for some of the fancier tricks, you can simply grab the style sheets and work through them on your own.
Overall, this book is extremely useful and easy to follow. Its clean, elegant examples would translate well for almost any use. For me, the
only disappointment was the book's length; it's awfully short for the price, especially considering how much space the illustrations take up.
Nevertheless, I found the content to be of high enough quality to interest me in purchasing the sequel: More Eric Meyer on CSS. And
7/15/2004
Book review: Eric Meyer on CSS: Mastering the Language of Web Design
Page 2 of 2
personally, I'd toss this book at any friend who ever mutters, "I'm thinking of making a Web site..."
Notes
1 "What You See Is What You Get" editors require you to know little or nothing about the underlying structure of a document. The editor
Lame! (1)
Comments?
Submit feedback
developerWorks
About IBM
> Rational
7/15/2004
Page 1 of 1
http://www-106.ibm.com/developerworks/rational/library/5419.html
Search for:
within
Use + - ( ) " "
IBM home
developerWorks
All of dW
Search help
> Rational
Contents:
Rate this article
from The Rational Edge: From a new introductory book on Java designed for both novice and
experienced programmers, this chapter covers arrays and references, programming with arrays,
and multidimensional arrays.
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
Written by one of the most widely read authors in the area of programming, Absolute Java offers complete coverage of the Java
programming language. It provides all the tools necessary for both experienced and novice programmers to master the language,
including thorough coverage of the Java Library, complete and fully executable code samples, sections highlighting programming tips and
common pitfalls, and logically ordered coverage of Java topics. To reinforce learning, the books chapters conclude with a summary,
answers to self-test exercises, and programming projects.
In Chapter 6, Savitch discusses arrays, including arrays and references, programming with arrays, and multidimensional arrays.
*Chapter 6 is posted in its entirety by permission from Addison-Wesley.
Chapter 6 pdf file (192 K)
Lame! (1)
Comments?
Submit feedback
developerWorks
About IBM
> Rational
7/15/2004
CHAPTER
Arrays
6.1
6.2
6.3
Arrays
Memory is necessary for all the operations of reason.
Blaise Pascal, Penses
INTRODUCTION
An array is a data structure used to process a collection of data that is all of the
same type, such as a list of numbers of type double or a list of strings. In this
chapter we introduce you to the basics of defining and using arrays in Java.
PREREQUISITES
Section 6.1 requires only Chapters 1 through 3 and Section 4.1 of Chapter 4.
Indeed, much less than all of Section 4.1 is needed. All you really need from
Section 4.1 is to have some idea of what an object is and what an instance
variable is.
The remaining sections require Chapters 1 through 5 with the exception
that Section 5.4 on packages and javadoc is not required.
6.1
Introduction to Arrays
It is a capital mistake to theorize
before one has data.
Sir Arthur Conan Doyle,
Scandal in Bohemia (Sherlock Holmes)
Suppose we wish to write a program that reads in five test scores and performs
some manipulations on these scores. For instance, the program might compute the highest test score and then output the amount by which each score
falls short of the highest. The highest score is not known until all five scores
are read in. Hence, all five scores must be retained in storage so that after the
highest score is computed each score can be compared to it. To retain the five
scores, we will need something equivalent to five variables of type int. We
could use five individual variables of type int, but keeping track of five variables is hard, and we may later want to change our program to handle 100
scores; certainly, keeping track of 100 variables is impractical. An array is the
perfect solution. An array behaves like a list of variables with a uniform naming mechanism that can be declared in a single line of simple code. For example, the names for the five individual variables we need might be score[0],
Introduction to Arrays
307
score[1], score[2], score[3], and score[4]. The part that does not change, in this
case score, is the name of the array. The part that can change is the integer in the
square brackets [].
These individual variables that together make up the array are referred to in a variety of
different ways. We will call them indexed variables, though they are also sometimes
called subscripted variables or elements of the array. The number in square brackets is
called an index or a subscript. In Java, indices are numbered starting with 0, not starting
with 1 or any number other than 0. The number of indexed variables in an array is called
the length or size of the array. When an array is created, the length of the array is given
in square brackets after the array name. The indexed variables are then numbered (also
using square brackets) starting with 0 and ending with the integer that is one less than
the length of the array.
The following
indexed variable
subscripted
variable
index, subscript
size, length
The first statement declares the variable score to be of the array type double[]. The
second statement creates an array with five indexed variables of type double and makes
the variable score a name for the array. You may use any expression that evaluates to a
nonnegative int value in place of the 5 in square brackets. In particular you can fill a
variable with a value read from the keyboard and use the variable in place of the 5. In
this way the size of the array can be determined when the program is run.
An array can have indexed variables of any type, but they must all be of the same
type. This type is called the base type of the array. In our example, the base type of the
array score is double. To declare an array with base type int, simply use the type name
int instead of double when the array is declared and created. The base type of an array
can be any type. In particular it can be a class type.
base type
308
Chapter 6 Arrays
DECLARING
AND
CREATING
AN
ARRAY
You declare an array name and create an array in almost the same way that you create and name
objects of classes. There is only a slight difference in the syntax.
SYNTAX:
Base_Type[] Array_Name = new Base_Type[Length];
The Length may be given as any expression that evaluates to a nonnegative integer. In particular
Length can be an int variable.
EXAMPLES:
char[] line = new char[80];
double[] reading = new double[300];
Person[] specimen = new Person[100];
Person is a class.
Each of the five indexed variables of our example array score can be used just like
any other variable of type double. For example, all of the following are allowed in Java:
score[3] = 32;
score[0] = score[3] + 10;
System.out.println(score[0]);
The five indexed variables of our sample array score are more than just five plain
old variables of type double. That number in square brackets is part of the indexed variables name. So, your program can compute the name of one of these variables. Instead
of writing an integer constant in the square brackets, you can use any expression that
evaluates to an integer that is at least 0 and at most 4. So, the following is allowed:
System.out.println(score[index] + " is at position " + index);
where index is a variable of type int that has been given one of the values 0, 1, 2, 3, or 4.
When we refer to these indexed variables grouped together into one collective item,
we will call them an array. So, we can refer to the array named score (without using
any square brackets).
The program in Display 6.1 shows an example of using our sample array score as
five indexed variables, all of type double.
Note that the program can compute the name of an indexed variable by using a variable as the index, as in the following for loop:
for (index = 0; index < 5; index++)
System.out.println(score[index] + " differs from max by "
+ (max score[index]));
Introduction to Arrays
309
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class ArrayOfScores
{
/**
Reads in 5 scores and shows how much each
score differs from the highest score.
*/
public static void main(String[] args) throws IOException
{
BufferedReader keyboard =
new BufferedReader(new InputStreamReader(System.in));
double[] score = new double[5];
int index;
double max;
This form of input is covered in
String inputLine;
Chapter 2, Section 2.3.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
310
Chapter 6 Arrays
Indices
80
99.9
75
100
85.5
square
brackets []
score[3]
Do not confuse the three ways to use the square brackets [] with an array name.
First, the square brackets can be used to create a type name, such as the double[] in the
following:
double[] score;
Second, the square brackets can be used with an integer value as part of the special
syntax Java uses to create a new array, as in
score = new double[5];
The third use of square brackets is to name an indexed variable of the array, such as
or score[3], as illustrated by the following line:
score[0]
max = score[0];
Introduction to Arrays
311
As we mentioned previously, the integer inside the square brackets can be any
expression that evaluates to a suitable integer, as illustrated by the following:
int next = 1;
score[next + 3] = 100;
System.out.println(
"Score at position 4 is " + score[next + 3]);
Note that, in the preceding code, score[next + 3] and score[4] are the same
indexed variable, because next + 3 evaluates to 4.
Tip
WITH
ARRAYS
The second for loop in Display 6.2 illustrates a common way to step through an entire array
using a for loop:
for (index = 0; index < score.length; index++)
System.out.println(score[index] + " differs from max by "
+ (max score[index]));
The technical details are as follows: The instance variable length is created when the array is
created and is declared to be public final int.
Chapter 6 Arrays
312
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Pitfall
WITH
ZERO
The indices of an array always start with 0 and end with the integer that is one less than the size of the
array.
Introduction to Arrays
313
Pitfall
OF
BOUNDS
The most common programming error made when using arrays is attempting to use a nonexistent
array index. For example, consider the following:
int[] a = new int[6];
When using the array a, every index expression must evaluate to one of the integers 0 through 5.
For example, if your program contains the indexed variable a[i], the i must evaluate to one of
the six integers 0, 1, 2, 3, 4, or 5. If i evaluates to anything else, that is an error. When an index
expression evaluates to some value other than those allowed by the array declaration, the index is
said to be out of bounds. If your program attempts to use an array index that is out of bounds,
then your program will end with an error message.2 Note that this is a run-time error message, not
a compiler error message.
Array indices get out of bounds most commonly at the first or last iteration of a loop that processes the array. So, it pays to carefully check all array processing loops to be certain that they
begin and end with legal array indices.
INITIALIZING ARRAYS
An array can be initialized when it is declared. When initializing the array, the values
for the various indexed variables are enclosed in braces and separated with commas.
The expression with the braces is placed on the right-hand side of an assignment operator. For example:
int[] age = {2, 12, 1};
The array length (size) is automatically set to the number of values in the braces. So,
this initializing declaration is equivalent to the following statements:
int[] age = new int[3];
age[0] = 2;
age[1] = 12;
age[2] = 1;
You can also initialize array elements using a for loop. For example:
double[] reading = new double[100];
int index;
for (index = 0; index < reading.length; index++)
reading[index] = 42.0;
2
Technically speaking, an ArrayIndexOutOfBoundsException is thrown. We will discuss
exceptions in Chapter 9. Until you learn about handling exceptions, exceptions will simply
appear as error conditions to you.
illegal
array index
314
automatic
initialization
Chapter 6 Arrays
If you do not initialize the elements of an array, they will automatically be initialized
to a default value for the base type. The default values are the usual ones. For numeric
types the default value is the zero of the type. (For base type char the default value is the
nonprintable zeroth character (char)0, not the space character.) For the type boolean
the default value is false. For class types, the default value is null. For example, if you
do not initialize an array of doubles, each element of the array will be initialized to 0.0.
Self-Test Exercises
1. In the array declaration
String[] word = new String[5];
what is
a. the array name?
b. the base type?
c. the length of the array?
d. the range of values an index accessing this array can have?
e. one of the indexed variables (or elements) of this array?
2. In the array:
double[] score = new double[10];
what is
a. the value of score.length?
b. the first index of score?
c. the last index of score?
3. What is the output of the following code?
char[] letter = {'a', 'b', 'c'};
for (int index = 0; index < letter.length; index++)
System.out.print(letter[index] + ", ");
Introduction to Arrays
However, to be safe we want our program to test the array and issue a warning in case it
turns out that some elements are out of order. The following code is supposed to output
such a warning, but it contains a bug; what is the bug?
double[] a = new double[10];
<Some code to fill the array a goes here.>
for (int index = 0; index < a.length; index++)
if (a[index] > a[index + 1])
System.out.println("Array elements " + index +
" and " + (index + 1) + " are out of order.");
Pitfall
AN ARRAY
OF
CHARACTERS IS NOT
STRING
An array of characters, such as the array a created below, is conceptually a list of characters and
so is conceptually like a string:
char[] a = {'A', ' ', 'B', 'i', 'g', ' ', 'H', 'i', '!'};
However, an array of characters, like a, is not an object of the class String. In particular, the following is illegal in Java:
String s = a;
Similarly, you cannot normally use an array of characters, like a, as an argument for a parameter
of type String.
It is, however, easy to convert an array of characters to an object of type String. The class
String has a constructor that has a single parameter of type char[]. So, you can obtain a
String value corresponding to an array of characters, like a, as follows:
String s = new String(a);
The object s will have the same sequence of characters as the array a. The object s is an independent
copy; any changes made to a will have no effect on s. Note that this always uses the entire array a.
315
316
Chapter 6 Arrays
There is also a String constructor that allows you to specify a subrange of an array of characters
a. For example,
String s2 = new String(a, 2, 3);
produces a String object with 3 characters from the array a starting at index 2. So, if a is as
above, then
System.out.println(s2);
outputs
Big
Although an array of characters is not an object of the class String, it does have some things in
common with String objects. For example, you can output an array of characters using
println, as follows,
System.out.println(a);
6.2
Just like a variable of one of the class types youve seen, a variable of an array type holds
a reference. In this section we explore the consequences of this fact, including a discussion of array parameters. We will see that arrays are objects and that array types can be
considered class types, but somewhat different kinds of class types. Arrays and the
kinds of classes weve seen before this chapter are a little more than kin, and less than
kind.
317
An array can be viewed as a single item whose value is a collection of values of the
base type. An array variable (as opposed to an array indexed variable) names the array as
a single item. For example, the following declares a variable of an array type:
double[] a;
This variable a can and will contain a single value. The expression
new double[10]
creates an array object and stores the object in memory. The following assignment
statement places a reference to (the memory address of ) this array object in the variable a:
a = new double[10];
Notice that this is almost exactly the same as the way that we view objects of a class
type. In Java, an array is considered an object. Whenever Java documentation says that
something applies to objects, that means that it applies to arrays as well as objects of the
class types weve seen up to now. You will eventually see examples of methods that can
take arguments that may be objects of any kind. These methods will accept array
objects as arguments as well as objects of an ordinary class type. Arrays are somewhat
peculiar in how they relate to classes. Some authorities say array types are not classes
and some authorities say they are classes. But, all authorities agree that the arrays themselves are objects. Given that arrays are objects, it seems that one should view array
types as classes, and we will do so. However, although an array type double[] is a class,
the syntax for creating an array object is a bit different. To create an array, you use the
following syntax:
double a = new double[10];
You can view the expression new double[10] as an invocation of a constructor that uses
a nonstandard syntax. (The nonstandard syntax was used to be consistent with the syntax used for arrays in older programming languages.)
As we have already seen, every array has an instance variable named length, which is
a good example of viewing an array as an object. As with any other class type, array
variables contain memory addresses, or, as they are usually called in Java, references. So
array types are reference types.3
Since an array is an object, you might be tempted to think of the indexed variables
of an array, such as a[0], a[1], and so forth, as being instance variables of the object.
3
In many programming languages, such as C++, arrays are also reference types just as they are
in Java. So, this detail about arrays is not peculiar to Java.
318
Chapter 6 Arrays
This is actually a pretty good analogy, but it is not literally true. Indexed variables are
not instance variables of the array. Indexed variables are a special kind of variable peculiar to arrays. The only instance variable in an array is the length instance variable.
An array object is a collection of items of the base type. Viewed as such, an array is
an object that can be assigned with the assignment operator and plugged in for a
parameter of an array type. Since an array type is a reference type, the behaviors of
arrays with respect to assignment =, ==, and parameter passing mechanisms are the
same as what we have already described for classes. In the next few subsections we discuss these details about arrays.
Pitfall
ARRAYS
WITH A
The base type of an array can be of any type, including a class type. For example, suppose Date
is a class and consider the following:
Date[] holidayList = new Date[20];
This creates the 20 indexed variables holidayList[0], holidayList[1], ..., holidatList[19]. It is important to note that this creates 20 indexed variables of type Date. This
does not create 20 objects of type Date. (The index variables are automatically initialized to
null, not to an object of the class Date.) Like any other variable of type Date, the indexed variables require an invocation of a constructor using new to create an object. One way to complete
the initialization of the array holidayList is as follows:
Date[] holidayList = new Date[20];
for (int i = 0; i < holidayList.length; i++)
holidayList[i] = new Date();
319
If you omit the for loop (and do not do something else more or less equivalent), then when you
run your code, you will undoubtedly get an error message indicating a null pointer exception.
If you do not use new to create an object, an indexed variable like holidayList[i] is just a
variable that names no object and hence cannot be used as the calling object for any method.
Whenever you are using an array with a class base type and you get an error message referring to
a null pointer exception, it is likely that your indexed variables do not name any objects and
you need to add something like the above for loop.
ARRAYS PARAMETERS
You can use both array indexed variables and entire arrays as arguments to methods,
although they are different types of parameters. We first discuss array indexed variables
as arguments to methods.
An indexed variable can be an argument to a method in exactly the same way that
any variable of the array base type can be an argument. For example, suppose a program contains the following declarations:
indexed variable
arguments
double n = 0;
double[] a = new double[10];
int i;
If myMethod takes one argument of type double, then the following is legal:
myMethod(n);
Since an indexed variable of the array a is also a variable of type double, just like n, the
following is equally legal:
myMethod(a[3]);
There is one subtlety that does apply to indexed variables used as arguments. For
example, consider the following method call:
myMethod(a[i]);
If the value of i is 3, then the argument is a[3]. On the other hand, if the value of i is
0, then this call is equivalent to the following:
myMethod(a[0]);
entire array
parameters
320
Chapter 6 Arrays
AS
ARGUMENTS
An array indexed variable can be used as an argument anyplace that a variable of the arrays
base type can be used. For example, suppose you have the following:
double[] a = new double[10];
Indexed variables such as a[3] and a[index] can then be used as arguments to any method
that accepts a double as an argument.
form Base_Type[], so this is how you specify a parameter type for an entire array, For
example, the method doubleArrayElements, given in what follows, will accept any
array of double as its single argument:
public class SampleClass
{
public static void doubleArrayElements(double[] a)
{
int i;
for (i = 0; i < a.length; i++)
a[i] = a[i]*2;
}
<The rest of the class definition goes here.>
}
To illustrate this, suppose you have the following in some method definition,
double[] a = new double[10];
double[] b = new double[30];
and suppose that the elements of the arrays a and b have been given values. Both of the
following are then legal method invocations:
SampleClass.doubleArrayElements(a);
SampleClass.doubleArrayElements(b);
Note that no square brackets are used when you give an entire array as an argument to
a method.
An array type is a reference type just as a class type is, so, as with a class type argument, a method can change the data in an array argument. To phrase it more precisely,
a method can change the values stored in the indexed variables of an array argument.
This is illustrated by the preceding method doubleArrayElements.
An array type determines the base type of an array argument that may be plugged in
for the parameter, but it does not specify the length of the array. An array knows its
321
length and stores it in the length instance variable. The same array parameter can be
replaced with array arguments of different lengths. Note that the preceding method
doubleArrayElements can take an array of any length as an argument.
ARRAY PARAMETERS
AND
ARRAY ARGUMENTS
An argument to a method may be an entire array. Array arguments are like objects of a class, in
that the method can change the data in an array argument; that is, a method can change the values stored in the indexed variables of an array argument. A method with an array parameter is
defined and invoked as illustrated by the following examples. Note that the array parameter
specifies the base type of the array, but not the length of the array.
EXAMPLES (OF
ARRAY PARAMETERS):
EXAMPLES (OF
ARRAY ARGUMENTS):
Note that a
rra
different le ys a and b have
ngths. Also
note that n
square bra
o
cke
arguments ts are used with arra
y
.
length of array
arguments
Chapter 6 Arrays
322
Self-Test Exercises
7. Consider the following class definition:
public class SomeClass
{
public static void doSomething(int n)
{
<Some code goes in here.>
}
<The rest of the definition is irrelevant to this question.>
8. Write a method definition for a static void method called oneMore, which has a formal
parameter for an array of integers and increases the value of each array element by one.
(The definition will go in some class, but you need only give the method definition.)
9. Write a method named outOfOrder that takes as a parameter an array of double and
returns a value of type int. This method will test the array for being out of order, meaning
that the array violates the condition:
a[0] <= a[1] <= a[2] <= ...
The method returns -1 if the elements are not out of order; otherwise, it returns the index
of the first element of the array that is out of order. For example, consider the declaration
double[] a = {1.2, 2.1, 3.3, 2.5, 4.5,
7.9, 5.4, 8.7, 9.9, 1.0};
In the array above, a[2] and a[3] are the first pair out of order, and a[3] is the first
element out of order, so the method returns 3. If the array were sorted, the method would
return 1.
10. What is wrong with the following method definition? It will compile but does not work as
you might hope.
public static void doubleSize(int[] a)
{
a = new int[a.length * 2];
}
323
Pitfall
USE
OF = AND == WITH
ARRAYS
Array types are reference types; that is, an array variable contains the memory address of the
array it names. The assignment operator copies this memory address. For example, consider the
following code:
assignment
with arrays
The assignment statement b = a; copies the memory address from a to b so that the array variable b contains the same memory address as the array variable a. After the assignment statement,
a and b are two different names for the same array. Thus, when we change the value of a[2], we
are also changing the value of b[2].
Unless you want two array variables to be two names for the same array (and on rare occasions
you do want this), you should not use the assignment operator with arrays. If you want the arrays
a and b in the preceding code to be different arrays with the same values in each index position,
then instead of the assignment statement
b = a;
Note that the above code will not make b an exact copy of a, unless a and b have the same length.
The equality operator == does not test two arrays to see if they contain the same values. It tests
two arrays to see if they are stored in the same location in the computers memory. For example,
consider the following code:
int[] c = new int[10];
int[] d = new int[10];
==
with arrays
324
Chapter 6 Arrays
int i;
for (i =
c[i]
for (i =
d[i]
if (c == d)
System.out.println("c and d are equal by ==.");
else
System.out.println("c and d are not equal by ==.");
even though c and d contain the same integers in the same indexed variables. A comparison
using == will say they are not equal because == only checks the contents of the array variables c
and d, which are memory addresses, and c and d contain different memory addresses.
If you want to test two arrays to see if they contain the same elements, then you can define an
equalArrays method for the arrays, just as you defined an equals method for a class. Display
6.3 contains one possible definition of equalArrays for arrays in a small demonstration class.
10
11
12
int i;
for (i = 0; i < c.length; i++)
c[i] = i;
13
14
The arrays
ca
same integ nd d contain the
ers in each
index
position.
if (c == d)
System.out.println("c and d are equal by ==.");
else
System.out.println("c and d are not equal by ==.");
19
20
21
22
23
24
25
if (equalArrays(c, d))
System.out.println(
"c and d are equal by the equalArrays method.");
else
System.out.println(
"c and d are not equal by the equalArrays method.");
26
27
System.out.println(
"An equalArrays method is usually a more useful test.");
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
return true;
}
}
SAMPLE DIALOGUE
c and d are not equal by ==.
== only tests memory addresses.
c and d are equal by the equalArrays method.
An equalArrays method is usually a more useful test.
325
326
Chapter 6 Arrays
The identifier args is in fact a parameter of type String[]. Since args is a parameter, it
could be replaced by any other non-keyword identifier. The identifier args is traditional, but it is perfectly legal to use some other identifier.
We have never given main an array argument, or any other kind of argument, when
we ran any of our programs. So, what did Java use as an argument to plug in for args?
If no argument is given when you run your program, then a default empty array of
strings is automatically provided as a default argument to main when you run your
program.
It is possible to run a Java program in a way that provides an argument to plug in for
this array of String parameters. You do not provide it as an array. You provide any
number of string arguments when you run the program, and those string arguments
will automatically be made elements of the array argument that is plugged in for args
(or whatever name you use for the parameter to main). This is normally done by running the program from the command line of the operating system, like so:
java YourProgram Do Be Do
This will set args[0] to "Do", args[1] to "Be", args[2] to "Do", and args.length
to 3. These three indexed variables can be used in the method main, as in the following
sample program:
public class YourProgram
{
public static void main(String[] args)
{
System.out.println(args[1] + " " + args[0]
+ " " + args[1]);
}
}
Be sure to note that the argument to main is an array of strings. If you want numbers,
you must convert the string representations of the numbers to values of a number type
or types.
AN
327
ARRAY PARAMETER
The identifier args is a parameter for an array of base type String. The details are explained in
the text.
Self-Test Exercises
11. Give the definition of a method called halfArray that has a single parameter for an array
of base type double and that returns another array of base type double that has the same
length and in which each element has been divided by 2.0. Make it a static method. To
test it, you can add it to any class or, better yet, write a class with a test program in the
method main.
12. What is wrong with the following method definition? It is an alternate definition of the
method by the same name defined in the previous subsection. It will compile.
public static char[] upperCaseVersion(char[] a)
{
char i;
for (i = 0; i < a.length; i++)
a[i] = Character.toUpperCase(a[i]);
return a;
}
328
Chapter 6 Arrays
RETURNING
AN
ARRAY
A method can return an array. The details are basically the same as for a method that returns an
object of a class type.
SYNTAX (FOR
The method need not be static and need not be public. You do not necessarily need to use a local
array variable like temp.
EXAMPLE (ASSUMED
TO BE IN A CLASS DEFINITION):
SYNTAX:
Base_Type[]
EXAMPLES:
double[] a = new double[10];
int[] giveIntArray(char[] arrayParameter)
{ ... }
6.3
329
In this section we discuss partially filled arrays and discuss how to use arrays as class
instance variables.
partially filled
array
1
2
3
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
4
5
6
7
8
9
10
11
12
13
14
15
/**
Shows differences
*/
public static void
{
double[] score
int numberUsed
Chapter 6 Arrays
330
20
21
22
23
24
25
26
27
28
29
/**
Reads values into the array a. Returns the number of values placed in the array a.
*/
public static int fillArray(double[] a) throws IOException
{
System.out.println("Enter up to " + a.length
+ " nonnegative numbers, one per line.");
System.out.println("Mark the end of the list with a negative number.");
BufferedReader keyboard =
new BufferedReader(new InputStreamReader(System.in));
30
31
32
33
34
35
36
37
38
39
40
double next;
int index = 0;
next = stringToDouble(keyboard.readLine( ));
while ((next >= 0) && (index < a.length))
{
a[index] = next;
index++;
next = stringToDouble(keyboard.readLine( ));
//index is the number of array indexed variables used so far.
}
//index is the total number of array indexed variables used.
41
42
43
if (next >= 0)
System.out.println("Could only read in "
+ a.length + " input values.");
44
45
return index;
46
47
48
49
50
/**
Precondition: numberUsed <= a.length.
a[0] through a[numberUsed-1] have values.
Returns the average of numbers a[0] through a[numberUsed-1].
*/
331
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
Precondition: numberUsed <= a.length.
The first numberUsed indexed variables of a have values.
Postcondition: Gives screen output showing how much each of the first
numberUsed elements of the array a differ from their average.
*/
public static void showDifference(double[] a, int numberUsed)
{
double average = computeAverage(a, numberUsed);
System.out.println("Average of the " + numberUsed
+ " scores = " + average);
System.out.println("The scores are:");
for (int index = 0; index < numberUsed; index++)
System.out.println(a[index] + " differs from average by "
+ (a[index] average));
}
}
332
Chapter 6 Arrays
but the program uses only as much of the array as it needs. The variable numberUsed
keeps track of how many elements are stored in the array. The elements (that is, the
scores) are stored in positions score[0] through score[numberUsed 1]. The details
are very similar to what they would be if numberUsed were score.length and the entire
array were used. Note that the variable numberUsed usually must be an argument to any
method that manipulates the partially filled array. For example, the methods showDifference and computeAverage use the argument numberUsed to ensure that only meaningful array indices are used.
Self-Test Exercises
13. Complete the definition of the following method that could be added to the class GolfScores in Display 6.4:
/**
Precondition: numberUsed <= argumentArray.length;
the first numberUsed indexed variables of argumentArray
have values.
Returns an array of length numberUsed whose ith element
is argumentArray[i] - adjustment.
*/
public static double[] differenceArray(
double[] argumentArray, int numberUsed, double adjustment)
14. Rewrite the class GolfScores from Display 6.4 using the method differenceArray
from exercise 13.
333
15. Rewrite the class GolfScores from Display 6.4 making the array of scores a static variable.
Also, make the int variable numberUsed a static variable. Start with Display 6.4, not with the
answer to exercise 14. Hint: All, or at least most, methods will have no parameters.
Example
A CLASS
FOR
If you are going to use some array in a disciplined way, such as using the array as a partially filled
array, then it is often best to create a class that has the array as an instance variable and to have
the constructors and methods of the class provide the needed operations as methods. For example, in Display 6.5 we have written a class for a partially filled array of doubles. In Display 6.6 we
have rewritten the program in Display 6.4 using this class.
In Display 6.6 we have written the code to be exactly analogous to that of Display 6.4 so that you
could see how one program mirrors the other. However, this resulted in occasionally recomputing
a value several times. For example, the method computeAverage has the following expression
three times:
a.getNumberOfElements()
Since the PartiallyFilledArray a is not changed in this method, these each return the same
value. Some programmers advocate computing this value only once and saving the value in a
variable. These programmers would use something like the following for the definition of computeAverage rather than what we used in Display 6.6. The variable numberOfElementsIna is
used to save a value so it need not be recomputed.
public static double computeAverage(PartiallyFilledArray a)
{
double total = 0;
double numberOfElementsIna = a.getNumberOfElements( );
for (int index = 0; index < numberOfElementsIna; index++)
total = total + a.getElement(index);
if (numberOfElementsIna > 0)
{
return (total/numberOfElementsIna);
}
else
{
System.out.println(
"ERROR: Trying to average 0 numbers.");
System.out.println("computeAverage returns 0.");
return 0;
}
}
alternative coding
334
Chapter 6 Arrays
This is not likely to produce a noticeable difference in the efficiency of the program in Display 6.6,
but if the number of elements in the PartiallyFilledArray were large so that the for loop
would be executed many times, it might make a difference in a situation where efficiency is critical.
/**
Class for a partially filled array of doubles. The class enforces the
following invariant: All elements are at the beginning of the array in
locations 0, 1, 2, and so forth up to a highest index with no gaps.
*/
public class PartiallyFilledArray
{
private int maxNumberElements; //Same as a.length
private double[] a;
private int numberUsed; //Number of indices currently in use
11
12
13
14
15
16
17
18
19
/**
Sets the maximum number of allowable elements to 10.
*/
PartiallyFilledArray()
{
maxNumberElements = 10;
a = new double[maxNumberElements];
numberUsed = 0;
}
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
Precondition arraySize > 0.
*/
PartiallyFilledArray(int arraySize)
{
if (arraySize <= 0)
{
System.out.println("Error Array size zero or negative.");
System.exit(0);
}
maxNumberElements = arraySize;
a = new double[maxNumberElements];
numberUsed = 0;
}
PartiallyFilledArray(PartiallyFilledArray original)
{
if (original == null)
{
System.out.println("Fatal Error: aborting program.");
System.exit(0);
Note that the instance variable a is
}
a copy of orignal.a. The
maxNumberElements =
following
would not be correct:
original.maxNumberElements;
a
=
original.a;
numberUsed = original.numberUsed;
This point is discussed in the
a = new double[maxNumberElements];
subsection entitled Privacy Leaks
for (int i = 0; i < numberUsed; i++)
with Array Instance Variables.
a[i] = original.a[i];
}
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
Adds newElement to the first unused array position.
*/
public void add(double newElement)
{
if (numberUsed >= a.length)
{
System.out.println("Error: Adding to a full array.");
System.exit(0);
}
else
{
a[numberUsed] = newElement;
numberUsed++;
}
}
64
65
66
67
68
69
70
71
72
return a[index];
335
336
Chapter 6 Arrays
/**
index must be an index in use or the first unused index.
*/
public void resetElement(int index, double newValue)
{
if (index < 0 || index >= maxNumberElements)
{
System.out.println("Error:Illegal index.");
System.exit(0);
}
else if (index > numberUsed)
{
System.out.println(
"Error: Changing an index that is too large.");
System.exit(0);
}
else
a[index] = newValue;
}
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
Deletes the element in position index. Moves down all elements with
indices higher than the deleted element.
*/
public void delete(int index)
{
if (index < 0 || index >= numberUsed)
{
System.out.println("Error:Illegal or unused index.");
System.exit(0);
}
113
114
115
116
337
121
122
123
124
125
126
127
128
129
130
131
132
133
134
Display 6.6 Display 6.4 Redone Using the Class PartiallyFilledArray (Part 1 of 3)
1
2
3
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
4
5
6
7
8
/**
Demonstrates Using the class PartiallyFilledArray,
*/
public class GolfScoresVersion2
{
10
11
12
13
14
15
16
/**
Shows the differences between each of a list of golf scores and their average.
*/
public static void main(String[] args) throws IOException
{
PartiallyFilledArray score =
new PartiallyFilledArray(MAX_NUMBER_SCORES);
338
Chapter 6 Arrays
Display 6.6 Display 6.4 Redone Using the Class PartiallyFilledArray (Part 2 of 3)
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
Reads values into the PartiallyFilledArray a.
*/
public static void fillArray(PartiallyFilledArray a) throws IOException
{
System.out.println("Enter up to " + a.getMaxCapacity( )
+ " nonnegative numbers, one per line.");
System.out.println("Mark the end of the list with a negative number");
BufferedReader keyboard = new BufferedReader(
new InputStreamReader(System.in));
33
34
35
36
37
38
39
40
41
42
if (next >= 0)
System.out.println("Could only read in "
+ a.getMaxCapacity( ) + " input values.");
}
43
44
45
46
47
48
49
50
51
52
53
54
/**
Returns the average of numbers in the PartiallyFilledArray a.
*/
public static double computeAverage(PartiallyFilledArray a)
{
double total = 0;
for (int index = 0; index < a.getNumberOfElements( ); index++)
total = total + a.getElement(index);
339
Display 6.6 Display 6.4 Redone Using the Class PartiallyFilledArray (Part 3 of 3)
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
Gives screen output showing how much each of the
elements in the PartiallyFilledArray a differ from the average.
*/
public static void showDifference(PartiallyFilledArray a)
{
double average = computeAverage(a);
System.out.println("Average of the " + a.getNumberOfElements( )
+ " scores = " + average);
System.out.println("The scores are:");
for (int index = 0; index < a.getNumberOfElements( ); index++)
System.out.println(a.getElement(index) + " differs from average by "
+ (a.getElement(index) average));
}
80
if (a.getNumberOfElements() > 0)
{
return (total/a.getNumberOfElements());
}
else
{
System.out.println("ERROR: Trying to average 0 numbers.");
System.out.println("computeAverage returns 0.");
return 0;
}
Tip
340
Chapter 6 Arrays
As indicated in the comment, this definition has a problem. The problem is that this
accessor method allows a programmer to change the array object named by the private
instance variable a in ways that bypass the checks built into the mutator methods of the
class PartiallyFilledArray. To see why this is true suppose we had added this definition
of the method getInsideArray to the class PartiallyFilledArray, and consider the following code:
PartiallyFilledArray leakyArray =
new PartiallyFilledArray(10);
double[] arrayName = leakyArray.getInsideArray( );
The variable arrayName and the private instance variable a now contain the same reference, so both arrayName and the private instance variable a name the same array. Using
arrayName as a name for the array named by the private instance variable a, we can now
fill the indexed variables of a in any order and need not fill the array starting at the first
element. This violates the spirit of the private modifier for the array instance variable
a. For this reason, the accessor method getInsideArray should return a deep copy of
the array named by the private instance variable a. A safe definition of getInsideArray
is the following:
public double[] getInsideArray()// Good version
{
//Recall that maxNumberElements == a.length.
double[] temp = new double[maxNumberElements];
for (int i = 0; i < maxNumberElements; i++)
temp[i] = a[i];
return temp;
}
341
If a private instance variable is an array type that has a class as its base type, then you
need to be sure to make copies of the class objects in the array when you make a copy
of the array. This is illustrated by the toy class in Display 6.7.
Display 6.7 also includes a copy constructor. As illustrated in that display, the copy
constructor should make a completely independent copy of the array instance variable
(that is, a deep copy) in the same way that the accessor method does. This same point is
also illustrated by the copy constructor in Display 6.5.
Display 6.7 Accessor Method for an Array Instance Variable
1
2
3
4
5
6
7
/**
Demonstrates the correct way to define an accessor
method to a private array of class objects.
*/
The class Date is defined in Display 4.11, but you
public class ToyExample
do not need to know the details of the definition
{
to understand the point of this example.
private Date[] a;
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Accessor method
342
Chapter 6 Arrays
A PREVIEW OF VECTORS
Java and many other programming languages have objects known as vectors, which are
very much like objects of our class PartiallyFilledArray in Display 6.5. However,
even after you learn about vectors, there will still be situations where the class PartiallyFilledArray is preferable to vectors. We will discuss vectors in Chapter 15.
Self-Test Exercises
16. Define a method named removeAll that can be added to the class PartialyFilledArray. The method removeAll has no parameters. When invoked the method removeAll
deletes all the elements in its calling object.
17. Define a method named increaseCapacity that can be added to the class PartiallyFilledArray in Display 6.5. The method has one int parameter named newCapacity
that increases the capacity of the PartialyFilledArray so that it can hold up to newCapacity numbers. If newCapacity is less than or equal to maxNumberOfElements, then
the method does nothing. If newCapacity is greater than maxNumberOfElements, then
maxNumberElements is set equal to newCapacity and a new array of length newCapacity is created for the array instance variable a. The old values of the array instance variable
are copied to the newly created array.
Example
SORTING
AN
ARRAY
In this example we define a method called sort that will sort a partially filled array of numbers so
that they are ordered from smallest to largest.
The procedure sort has one array parameter a. The array a will be partially filled, so there is an
additional formal parameter called numberUsed, which tells how many array positions are used.
Thus, the heading for the method sort will be
public static void sort(double[] a, int numberUsed)
The method sort rearranges the elements in array a so that after the method call is completed,
the elements are sorted as follows:
a[0] a[1] a[2] ... a[numberUsed 1]
selection sort
The algorithm we use to do the sorting is called selection sort. It is one of the easiest of the sorting algorithms to understand.
343
One way to design an algorithm is to rely on the definition of the problem. In this case the problem is to sort an array a from smallest to largest. That means rearranging the values so that a[0]
is the smallest, a[1] the next smallest, and so forth. That definition yields an outline for the
selection sort algorithm:
for (int index = 0; index < numberUsed; index++)
Place the indexth smallest element in a[index]
There are many ways to realize this general approach. The details could be developed by using
two arrays and copying the elements from one array to the other in sorted order, but using one
array should be both adequate and economical. Therefore, the method sort uses only the one
array containing the values to be sorted. The method sort rearranges the values in the array a by
interchanging pairs of values. Let us go through a concrete example so that you can see how the
algorithm works.
Consider the array shown in Display 6.8. The selection sort algorithm will place the smallest value
in a[0]. The smallest value is the value in a[4]. So, the algorithm interchanges the values of
a[0] and a[4]. The algorithm then looks for the next smallest element. The value in a[0] is now
the smallest element, so the next smallest element is the smallest of the remaining elements a[1],
a[2], a[3],..., a[9]. In the example in Display 6.8 the next smallest element is in a[6], so the
algorithm interchanges the values of a[1] and a[6]. This positioning of the second smallest element is illustrated in the fourth and fifth array pictures in Display 6.8. The algorithm then positions the third smallest element, and so forth. As the sorting proceeds, the beginning array
elements are set equal to the correct sorted values. The sorted portion of the array grows by adding elements one after the other from the elements in the unsorted end of the array. Notice that
the algorithm need not do anything with the value in the last indexed variable, a[9], because
once the other elements are positioned correctly, a[9] must also have the correct value. After all,
the correct value for a[9] is the smallest value left to be moved, and the only value left to be
moved is the value that is already in a[9].
The definition of the method sort, included in a class, is given in Display 6.9. sort uses the
method indexOfSmallest to find the index of the smallest element in the unsorted end of the
array, then it does an interchange to move this next smallest element down into the sorted part of
the array.
The method interchange, shown in Display 6.9, is used to interchange the values of indexed
variables. For example, the following call will interchange the values of a[0] and a[4]:
interchange(0, 4, a);
indexOfSmallest
Chapter 6 Arrays
344
a[1]
a[2]
a[3]
a[4]
a[5]
a[6]
a[7]
a[8]
a[9]
11
17
15
19
28
12
11
17
15
19
28
12
11
17
15
19
28
12
11
17
15
19
28
12
11
17
15
19
28
12
11
12
15
17
19
28
.
.
.
3
Self-Test Exercises
18. How would you need to change the method sort in Display 6.9 so that it can sort an array
of values of type double into decreasing order, instead of increasing order?
19. If an array of int values has a value that occurs twice (like b[0] == 42 and b[7] == 42)
and you sort the array using the method SelectionSort.sort, will there be one or two
copies of the repeated value after the array is sorted?
345
346
Chapter 6 Arrays
6.4
Multidimensional Arrays
Two indices are better than one.
Anonymous
Java allows you to declare arrays with more than one index. In this section we describe
these multidimensional arrays.
It is sometimes useful to have an array with more than one index, and this is allowed in
Java. The following creates an array of characters called page. The array page has two
indices: the first index ranging from 0 to 29 and the second from 0 to 99.
char[][] page = new char[30][100];
The indexed variables for this array each have two indices. For example, page[0][0],
page[15][32], and page[29][99] are three of the indexed variables for this array. Note
that each index must be enclosed in its own set of square brackets. As was true of the
one-dimensional arrays we have already seen, each indexed variable for a multidimensional array is a variable of the base type, in this case the type char.
Multidimensional Arrays
347
6
7
8
9
10
11
12
13
14
15
16
17
18
SelectionSort.sort(b, b.length);
}
}
SAMPLE DIALOGUE
Array contents before sorting:
7.7 5.5 11.0 3.0 16.0 4.4 20.0 14.0 13.0 42.0
Sorted array values:
3.0 4.4 5.5 7.7 11.0 13.0 14.0 16.0 20.0 42.0
An array may have any number of indices, but perhaps the most common number
of indices is two. A two-dimensional array can be visualized as a two-dimensional display with the first index giving the row and the second index giving the column. For
example, the array indexed variables of the two-dimensional array a declared and created as
char[][] a = new char[5][12];
a[0][1],
a[1][1],
a[2][1],
a[3][1],
a[4][1],
a[0][2],
a[1][2],
a[2][2],
a[3][2],
a[4][2],
...,
...,
...,
...,
...,
a[0][11]
a[1][11]
a[2][11]
a[3][11]
a[4][11]
348
Chapter 6 Arrays
You might use the array a to store all the characters on a (very small) page of text that
has five lines (numbered 0 through 4) and 12 characters on each line (numbered 0
through 11).
DECLARING
AND
CREATING
MULTIDIMENSIONAL ARRAY
You declare a multidimensional array variable and create a multidimensional array object in
basically the same way that you create and name a one-dimensional array. You simply use as
many square brackets as there are indices.
SYNTAX:
Base_Type[]...[] Variable_Name = new Base_Type[Length_1]...[Length_n];
EXAMPLES:
char[][] a = new char[5][12];
char[][] page = new char[30][100];
double[][] table = new double[100][10];
int[][][] figure = new int[10][20][30];
Person[][] entry = new Person[10][10];
Person is a class.
A
multidimensional
array is an
array of arrays
Multidimensional Arrays
349
a[1][2]
10
11
a[1]
a
a[2]
t
a[3]
a[4]
a
350
Chapter 6 Arrays
Lets analyze this nested for loop in a bit more detail. The array page is actually a
one-dimensional array of length 30, and each of the 30 indexed variables page[0]
through page[29] is a one-dimensional array with base type char and with a length
of 100. That is why the first for loop is terminated using page.length. For a twodimensional array like page, the value of length is the number of first indices or, equivalently, the number of rowsin this case, 30. Now lets consider the inside for loop.
The 0th row in the two-dimensional array page is the one-dimensional array page[0],
and it has page[0].length entries. More generally, page[row] is a one-dimensional array
of chars, and it has page[row].length entries. That is why the inner for loop is terminated
using page[row].length. Of course, in this case, page[0].length, page[1].length, and so
forth through to page[29].length are all equal and all equal to 100. (If you read the
optional section entitled Ragged Arrays, you will see that these need not all be equal.)
Self-Test Exercises
20. What is the output produced by the following code?
int[][] myArray = new int[4][4];
int index1, index2;
for (index1 = 0; index1 < myArray.length; index1++)
for (index2 = 0;
index2 < myArray[index1].length; index2++)
myArray[index1][index2] = index2;
for (index1 = 0; index1 < myArray.length; index1++)
{
for (index2 = 0;
index2 < myArray[index1].length; index2++)
System.out.print(myArray[index1][index2] + " ");
System.out.println();
}
Multidimensional Arrays
351
21. Write code that will fill the array a (declared and created below) with numbers typed in at
the keyboard. The numbers will be input five per line, on four lines.
int[][] a = new int[4][5];
RAGGED ARRAYS
There is no need for each row in a two-dimensional array to have the same number of
entries. Different rows can have different numbers of columns. These sorts of arrays are
called ragged arrays.
To help explain the details, lets start with an ordinary, nonragged two-dimensional
array, created as follows:
double[][] a = new double[3][5];
The line
a = new double[3][];
makes a the name of an array with room for 3 entries, each of which can be an array of
doubles that can be of any length. The next three lines each create an array of doubles
of length 5 to be named by a[0], a[1], and a[2]. The net result is a two-dimensional
array of base type double with three rows and five columns.
If you want, you can make each of a[0], a[1], and a[2] a different length. The following code makes a ragged array b in which each row has a different length:
double[][] b;
b = new double[3][];
b[0] = new double[5];
b[1] = new double[10];
b[2] = new double[4];
Chapter 6 Arrays
352
There are situations in which you can profitably use ragged arrays, but most applications do not require them. However, if you understand ragged arrays, you will have a
better understanding of how all multidimensional arrays work in Java.
Methods may have multidimensional array parameters and may have a multidimensional array type as the type for the value returned. The situation is similar to that of
the one-dimensional case, except that you use more square brackets when specifying
the type name. For example, the following method will display a two-dimensional
array in the usual way as rows and columns:4
public static void showMatrix(int[][] a)
{
int row, column;
for (row = 0; row < a.length; row++)
{
for (column = 0; column < a[row].length; column++)
System.out.print(a[row][column] + " ");
System.out.println();
}
}
returning an array
If you want to return a multidimensional array, you use the same kind of type specification as you use for a multidimensional array parameter. For example, the following
method returns a two-dimensional array with base type double:
/**
Precondition: Each dimension of a is at least
the value of size.
The array returned is the same as the size-by-size
upper-left corner of the array a.
*/
public static double[][] corner(double[][] a, int size)
{
double[][] temp = new double[size][size];
int row, column;
for (row = 0; row < size; row++)
for (column = 0; column < size; column++)
temp[row][column] = a[row][column];
return temp;
}
It is worth noting that this method works fine for ragged arrays.
Multidimensional Arrays
353
Example
Self-Test Exercises
23. Write a method definition for a method with the following heading. The method is to be
added to the class GradeBook in Display 6.12.
/**
Returns the grade that student numbered studentNumber
received on quiz number quizNumber.
*/
public int getGrade(int studentNumber, int quizNumber)
no-argument
constructor
354
Chapter 6 Arrays
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public GradeBook(int[][] a)
{
if (a.length == 0 || a[0].length == 0)
{
System.out.println("Empty grade records. Aborting.");
System.exit(0);
}
18
19
20
21
22
23
numberOfStudents = a.length;
numberOfQuizzes = a[0].length;
fillGrade(a);
fillStudentAverage();
fillQuizAverage();
}
24
25
26
27
28
29
30
31
32
33
34
35
Multidimensional Arrays
355
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
fillStudentAverage();
fillQuizAverage();
}
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Chapter 6 Arrays
356
/**
Fills the array studentAverage using the data from the array grade.
*/
private void fillStudentAverage()
{
studentAverage = new double[numberOfStudents];
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
Fills the array quizAverage using the data from the array grade.
*/
private void fillQuizAverage()
{
quizAverage = new double[numberOfQuizzes];
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
Multidimensional Arrays
357
117
118
119
120
121
122
123
quiz 2
quiz 3
student 1
10
10
10
10.0
studentAverage[0]
student 2
1.0
studentAverage[1]
student 3
7.7
studentAverage[2]
student 4
10
7.3
studentAverage[3]
7.0
5.0
7.5
quizAverage[0]
quizAverage[1]
quizAverage[2]
studentAverage
quizAverage
Chapter 6 Arrays
358
import java.io.IOException;
public class GradeBookDemo
{
public static void main(String[] args) throws IOException
{
GradeBook book = new GradeBook();
book.display();
}
}
SAMPLE DIALOGUE
Enter number of students:
4
Enter number of quizzes:
3
Enter score for student number 1
on quiz number 1
10
Enter score for student number 1
on quiz number 2
10
<The rest of the input dialog is omitted to save space.>
Student 1 Quizzes: 10 10 10 Ave = 10.0
Student 2 Quizzes: 2 0 1 Ave = 1.0
Student 3 Quizzes: 8 6 9 Ave = 7.66666666667
Student 4 Quizzes: 8 4 10 Ave = 7.33333333333
Quiz averages:
Quiz 1 Ave = 7.0 Quiz 2 Ave = 5.0 Quiz 3 Ave = 7.5
24. Write a method definition for a method with the following heading. The method is to be
added to the class GradeBook in Display 6.12.
/**
Changes the grade for student number studentNumber
on quiz number quizNumber to newGrade.
*/
public void changeGrade(int studentNumber,
int quizNumber, int newGrade))
Chapter Summary
359
25. Write a method definition for a method with the following heading. The method is to be
added to the class GradeBook in Display 6.12.
/**
Returns an array with the average quiz score for each student.
*/
public double[] getStudentAverages()
26. Write a method definition for a method with the following heading. The method is to be
added to the class GradeBook in Display 6.12.
/**
Returns an array with the average score for each quiz.
*/
public double[] getQuizAverages()
Chapter Summary
An array can be used to store and manipulate a collection of data that is all of the
same type.
The indexed variables of an array can be used just like any other variables of the base
type of the array.
Arrays are objects that are created with new just like the class objects we discussed
before this chapter (although there is a slight difference in the syntax used).
A for loop is a good way to step through the elements of an array and perform
some program action on each indexed variable.
The most common programming error made when using arrays is to attempt to
access a nonexistent array index. Always check the first and last iterations of a loop
that manipulates an array to make sure it does not use an index that is illegally small
or illegally large.
The indexed variables of an array can be used as an argument to be plugged in for a
parameter of the arrays base type.
A method can have parameters of an array type. When the method is invoked, an
entire array is plugged in for the array parameter.
A method may return an array as the value returned by the method.
When using a partially filled array, your program needs an additional variable of
type int to keep track of how much of the array is being used.
An instance variable of a class can be of an array type.
If you need an array with more than one index, you can use a multidimensional
array, which is actually an array of arrays.
360
Chapter 6 Arrays
ANSWERS
TO
SELF-TEST EXERCISES
1. a. word
b. String
c. 5
d. 0 through 4 inclusive
e. any of the following would be correct:
word[0], word[1], word[2], word[3], word[4]
2. a. 10
b. 0
c. 9
3. a, b, c,
4. 1.1 2.2 3.3
1.1 3.3 3.3
5. The for loop uses indices 1 through sampleArray.length, but the correct indices are 0
through sampleArray.length 1. The last index, sampleArray.length, is out of
bounds. What was probably intended is the following:
int[] sampleArray = new int[10];
for (int index = 0; index < sampleArray.length; index++)
sampleArray[index] = 3*index;
6. The last value of index is a.length 1, which is the last index of the array. However,
when index has the value a.length 1, a[index + 1] has an index that is out of bounds
since index + 1 is one more than the largest array index. The for loop ending condition
should instead be index < a.length 1.
7. SomeClass.doSomething(number); //Legal.
SomeClass.doSomething(a[2]); //Legal.
SomeClass.doSomething(a[3]); //Illegal. Index out of bounds.
SomeClass.doSomething(a[number]); //Legal.
SomeClass.doSomething(a); //Illegal.
361
10. This method is legal but pointless. When invoked, it has no effect on its argument. The
parameter a is a local variable that contains a reference. The reference does indeed get
changed to a reference to an array of double the size of the argument, but that reference
goes away when the method ends. A method can change the values of the indexed
variables of its argument, but it cannot change the reference in the array variable used as
an argument.
11. public static double[] halfArray(double[] a)
{
double[] temp = new double[a.length];
for (int i = 0; i < a.length; i++)
temp[i] = a[i]/2.0;
return temp;
}
12. The method will compile and run. However, it will change the values of its array argument.
If you want to change the values in the array argument, a void method would make more
sense. If you want to return an array, you should probably return a new array (as in the version in the previous subsection), not return a changed version of the argument array.
13. /**
Precondition: numberUsed <= argumentArray.length;
the first numberUsed indexed variables of argumentArray
have values.
Returns an array of length numberUsed whose ith element
is argumentArray[i] - adjustment.
*/
public static double[] differenceArray(
double[] argumentArray, int numberUsed, double adjustment)
{
double[] temp = new double[numberUsed];
for (int i = 0; i < numberUsed; i++)
temp[i] = argumentArray[i] adjustment;
return temp;
}
14. The only changes are to add the method differenceArray and to rewrite the method
showDifference as follows (the complete class definition is in the file GolfScoresExercise.java on the accompanying CD):
public static void showDifference(double[] a,
int numberUsed)
{
double average = computeAverage(a, numberUsed);
System.out.println("Average of the " + numberUsed
+ " scores = " + average);
extra code on CD
362
Chapter 6 Arrays
double[] difference =
differenceArray(a, numberUsed, average);
System.out.println("The scores are:");
for (int index = 0; index < numberUsed; index++)
System.out.println(a[index] +
" differs from average by "
+ difference[index]);
}
extra code
on CD
15. The main differences are to remove parameters, replace the array name a by score, and
make the method fillArray a void method. This code is in the file GolfScoresStaticExercise.java on the accompanying CD.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class GolfScoresStaticExercise
{
public static final int MAX_NUMBER_SCORES = 10;
private static double[] score =
new double[MAX_NUMBER_SCORES];
private static int numberUsed = 0;
/**
Shows differences between each of a list of golf scores
and their average.
*/
public static void main(String[] args) throws IOException
{
System.out.println(
"This program reads golf scores and shows");
System.out.println(
"how much each differs from the average.");
System.out.println("Enter golf scores:");
fillArray();
showDifference();
}
/**
Reads values into the array score.
*/
public static void fillArray() throws IOException
{
System.out.println("Enter up to " + score.length
+ " nonnegative numbers, one per line.");
System.out.println(
"Mark the end of the list with a negative number.");
BufferedReader keyboard = new BufferedReader(
new InputStreamReader(System.in));
double next;
int index = 0;
next = stringToDouble(keyboard.readLine( ));
while ((next >= 0) && (index < score.length))
{
score[index] = next;
index++;
next = stringToDouble(keyboard.readLine( ));
//index is the number of
//array indexed variables used so far.
}
//index is the total number of array indexed variables used.
if (next >= 0)
System.out.println("Could only read in "
+ score.length + " input values.");
numberUsed = index;
}
/**
Precondition: numberUsed <= score.length.
score[0] through score[numberUsed-1] have values.
Returns the average of numbers ascore[0] through
score[numberUsed-1].
*/
public static double computeAverage()
{
double total = 0;
for (int index = 0; index < numberUsed; index++)
total = total + score[index];
if (numberUsed > 0)
{
return (total/numberUsed);
}
else
{
System.out.println(
"ERROR: Trying to average 0 numbers.");
System.out.println("computeAverage returns 0.");
return 0;
}
}
363
364
Chapter 6 Arrays
18. All you need to do to make your code work for sorting into decreasing order is to replace
the < with > in the following line of the definition of indexOfSmallest:
if (a[index] < min)
However, to make your code easy to read, you should also rename the method
indexOfSmallest to indexOfLargest, rename the variable min to max, and rename the
variable indexOfMin to indexOfMax. You should also rewrite some of the comments to
reflect these changes.
365
19. If an array has a value that occurs more than once and you sort the array using the method
SelectionSort.sort, then there will be as many copies of the repeated value after the
array is sorted as there originally were in the array.
20. 0 1 2 3
0 1 2 3
0 1 2 3
0 1 2 3
21. The answer is given along with the answer to exercise 22.
22. This program is on the CD that comes with this book.
import
import
import
import
extra code
on CD
java.io.BufferedReader;
java.io.InputStreamReader;
java.io.IOException;
java.util.StringTokenizer;
366
Chapter 6 Arrays
23. If the array indices are out of bounds, then Java will halt the program with an error message, so no other checks on the parameters are needed.
/**
Returns the grade that student numbered studentNumber
received on quiz number quizNumber.
*/
public int getGrade(int studentNumber, int quizNumber)
{
return grade[studentNumber][quizNumber];
}
24. If the array indices are out of bounds, then Java will halt the program with an error message, so no other checks on the parameters are needed.
/**
Changes the grade for student number studentNumber
on quiz number quizNumber to newGrade.
*/
public void changeGrade(int studentNumber,
int quizNumber, int newGrade)
{
grade[studentNumber][quizNumber] = newGrade;
}
25. /**
Returns an array with the average quiz score for each student.
*/
public double[] getStudentAverages()
{
int arraySize = studentAverage.length;
double[] temp = new double[arraySize];
for (int i = 0; i < arraySize; i++)
temp[i] = studentAverage[i];
return temp;
}
Programming Projects
367
26. /**
Returns an array with the average score for each quiz.
*/
public double[] getQuizAverages()
{
int arraySize = quizAverage.length;
double[] temp = new double[arraySize];
for (int i = 0; i < arraySize; i++)
temp[i] = quizAverage[i];
return temp;
}
PROGRAMMING PROJECTS
Many of these Programming Projects can be solved using AWs CodeMate.
To access these please go to: www.aw-bc.com/codemate.
1. Write a program that reads in the average monthly rainfall for a city for each month of the
year and then reads in the actual monthly rainfall for each of the previous 12 months. The
program then prints out a nicely formatted table showing the rainfall for each of the previous 12 months as well as how much above or below average the rainfall was for each
month. The average monthly rainfall is given for the months January, February, and so
forth, in order. To obtain the actual rainfall for the previous 12 months, the program first
asks what the current month is and then asks for the rainfall figures for the previous 12
months. The output should correctly label the months. There are a variety of ways to deal
with the month names. One straightforward method is to code the months as integers and
then do a conversion to a string for the month name before doing the output. A large
switch statement is acceptable in an output method. The month input can be handled in
any manner you wish so long as it is relatively easy and pleasant for the user. Include a loop
that allows the user to repeat this entire calculation until the user requests that the program
end.
2. Write a static method called deleteRepeats that has a partially filled array of characters as
a formal parameter and that deletes all repeated letters from the array. Since a partially
filled array requires two arguments, the method will actually have two formal parameters:
an array parameter and a formal parameter of type int that gives the number of array positions used. When a letter is deleted, the remaining letters are moved one position to fill in
the gap. This will create empty positions at the end of the array so that less of the array is
used. Since the formal parameter is a partially filled array, a second formal parameter of
type int will tell how many array positions are filled. This second formal parameter cannot
be changed by a Java method, so have the method return the new value for this parameter.
For example, consider the following code:
char
a[0]
a[1]
a[2]
a[10];
= 'a';
= 'b';
= 'a';
368
Chapter 6 Arrays
a[3] = 'c';
int size = 4;
size = deleteRepeats(a, size);
After this code is executed, the value of a[0] is 'a', the value of a[1] is 'b', the value of
a[2] is 'c', and the value of size is 3. (The value of a[3] is no longer of any concern,
since the partially filled array no longer uses this indexed variable.) You may assume that
the partially filled array contains only lowercase letters. Write a suitable test program for
your method.
3. The standard deviation of a list of numbers is a measure of how much the numbers deviate
from the average. If the standard deviation is small, the numbers are clustered close to the
average. If the standard deviation is large, the numbers are scattered far from the average.
The standard deviation of a list of numbers n1, n2, n3, and so forth is defined as the square
root of the average of the following numbers:
(n1 - a)2, (n2 - a)2, (n3 - a)2, and so forth.
The number a is the average of the numbers n1, n 2, n3, and so forth.
Define a static method that takes a partially filled array of numbers as its argument and
returns the standard deviation of the numbers in the partially filled array. Since a partially
filled array requires two arguments, the method will actually have two formal parameters,
an array parameter and a formal parameter of type int that gives the number of array positions used. The numbers in the array will be of type double. Write a suitable test program
for your method.
4. Write a program that reads numbers from the keyboard into an array of type int[]. You
may assume that there will be 50 or fewer entries in the array. Your program allows any
number of numbers to be entered up to 50 numbers. The output is to be a two-column
list. The first column is a list of the distinct array elements; the second column is the count
of the number of occurrences of each element. The list should be sorted on entries in the
first column, largest to smallest.
For the array
12 3 12 4 1 1 12 1 1 1 2 3 4 2 3 12
Count
2
3
2
4
1
4
5. An array can be used to store large integers one digit at a time. For example, the integer
1234 could be stored in the array a by setting a[0] to 1, a[1] to 2, a[2] to 3, and a[3] to
Programming Projects
369
4. However, for this exercise you might find it more useful to store the digits backward;
that is, place 4 in a[0], 3 in a[1], 2 in a[2], and 1 in a[3]. In this exercise you will write
a program that reads in two positive integers that are 20 or fewer digits in length and then
outputs the sum of the two numbers. Your program will read the digits as values of type
char so that the number 1234 is read as the four characters '1', '2', '3', and '4'. After
they are read into the program, the characters are changed to values of type int. The digits
will be read into a partially filled array, and you might find it useful to reverse the order of
the elements in the array after the array is filled with data from the keyboard. (Whether or
not you reverse the order of the elements in the array is up to you. It can be done either way
and each way has its advantages and disadvantages.) Your program will perform the addition by implementing the usual paper-and-pencil addition algorithm. The result of the
addition is stored in an array of size 20 and the result is then written to the screen. If the
result of the addition is an integer with more than the maximum number of digits (that is,
more than 20 digits), then your program should issue a message saying that it has encountered integer overflow. You should be able to change the maximum length of the integers
by changing only one named constant. Include a loop that allows the user to continue to
do more additions until the user says the program should end.
6. Design a class called BubbleSort that is similar to the class SelectionSort given in Display 6.9. The class BubbleSort will be used in the same way as the class SelectionSort,
but it will use the bubble sort algorithm.
The bubble sort algorithm checks all adjacent pairs of elements in the array from the beginning to the end and interchanges any two elements that are out of order. This process is
repeated until the array is sorted. The algorithm is as follows:
The bubble sort algorithm is good for sorting an array that is almost sorted. It is not
competitive to other sorting methods for most other situations.
7. Enhance the definition of the class PartiallyFilledArray (Display 6.5) in the following
way: When the user attempts to add one additional element and there is no room in the array
instance variable a, the user is allowed to add the element. The object creates a second array
that is twice the size of the array a, copies values from the array a to the users new array,
makes this array (or more precisely its reference) the new value of a, and then adds the element to this new larger array a. Hence, this new class will have no limit (other than the
physical size of the computer) to how many numbers it can hold. The instance variable
maxNumberElements remains and the method getMaxCapacity is unchanged, but these
now refer to the currently allocated memory and not to an absolute upper bound. Write a
suitable test program.
370
Chapter 6 Arrays
8. Write a program that will allow two users to play tic-tac-toe. The program should ask for moves
alternately from player X and player O. The program displays the game positions as follows:
1
4
7
2
5
8
3
6
9
The players enter their moves by entering the position number they wish to mark. After
each move, the program displays the changed board. A sample board configuration is
X
4
O
X
5
8
O
6
9
9. Write a program to assign passengers seats in an airplane. Assume a small airplane with seat
numberings as follows:
1
2
3
4
5
6
7
A
A
A
A
A
A
A
B
B
B
B
B
B
B
C
C
C
C
C
C
C
D
D
D
D
D
D
D
The program should display the seat pattern, with an 'X' marking the seats already
assigned. For example, after seats 1A, 2B, and 4C are taken, the display should look like:
1
2
3
4
5
6
7
X
A
A
A
A
A
A
B
X
B
B
B
B
B
C
C
C
X
C
C
C
D
D
D
D
D
D
D
After displaying the seats available, the program prompts for the seat desired, the user types
in a seat, and then the display of available seats is updated. This continues until all seats are
filled or until the user signals that the program should end. If the user types in a seat that is
already assigned, the program should say that that seat is occupied and ask for another
choice.