This is the second part of a two-part series on transforming the requirements
captured in use cases into implementable representations and code. In "Part 1, Use case analysis," I traced the major steps in the Use Case Analysis activity
of the Rational Unified Process®, or RUP®1.
I introduced a simple case study for a vehicle rental system (let's now call
it Deals on Wheels) to be developed to offer browser-access to customers
wishing to reserve a vehicle, cancel a reservation, view a rental history, etc.
I presented a single use case, Reserve a Vehicle, first in a very generic
version, then in a supplemented version, introducing more of the external
interactions that have to take place in this use case.
Then I used the simple technique of grammatical dissection to identify candidate entities in the use case, and introduced four questions to challenge these candidates. These questions distilled our forty-one candidates down to eight entities that passed the test of being analysis classes. Then I identified the responsibilities of each analysis class, so we could have what James Rumbaugh et. al. call a "crisp boundary" in our definition of each class.
With the eight analysis classes identified, I then introduced four steps that I used to construct an initial analysis class diagram to capture the relationships and multiplicities among these classes. Next, I constructed an analysis-level sequence diagram of the main scenario of the Reserve a Vehicle use case. This was strictly constrained to be an analysis-level diagram containing only analysis classes, and no design or implementation classes. To improve understandability of the sequence diagram, I introduced a generic use case controller object to mediate the messages received by the human customer actor. With the analysis classes and their relationships identified, I then populated each analysis class with attributes (data members) that were in accord with the responsibilities of each class. Lastly, I identified the analysis mechanisms for this little case study.
In Part II of this series, we will perform the steps of RUP's Use Case Design activity.
The elements of Use Case Design in RUP
Figure 1 is taken from RUP's Analysis and Design Activity Overview. It illustrates where the Use Case Design activity occurs within the context of the other Analysis and Design activities.
Figure 1: Use Case Design activity in RUP
In RUP the stated purpose of Use Case Design is:
- To refine use case realizations in terms of interactions
- To refine requirements on the operations of design classes
- To refine requirements on the operations of subsystems and/or their interfaces.
We can alternately express that the goal of Use Case Design is to transform each business abstraction in our system (i.e., the analysis classes) into one or more design classes that are implementable representations, taking into account the properties of the target execution environment. Note that the design classes are implementable representations. The implementation (i.e., coding) of the design classes occurs after design is stable (although we sometimes write code to explore design options). In design, we want to express, in appropriate detail, how we will approach the implementation so that the actual programming is a matter only of language and platform issues. Figure 2 illustrates the steps that constitute Use Case Design.
Figure 2: The steps of Use Case Design
The activity of design involves maintaining multiple perspectives simultaneously on the software system you are building. Good designers successfully juggle separate, and often competing, views of their target system. Just as a cube has six faces which are independent yet part of the same whole, a software system's design is multi-faceted, including: logical, process, implementation, deployment, and operational views; system and software architecture; components and classes; patterns and interfaces; static structure and interactions, and more. I am not going to cover all of the practices of software design in this article. But I will provide some concrete examples of what we might actually do inside the major Use Case Design steps, as shown in Figure 2.
Object-oriented and component-based design strategies focus on classes -- which are named units of data and bound functions that operate on that data. In the design discipline, we describe our classes, and their relationships to other classes or subsystems, in a manner that now takes all technology concerns into account.
Some of these concerns are:
- How do I represent a one-to-many, or many-to-many, relationship between
two classes?
- How do I represent access to and from a data store?
- What aspects of my class should be visible to objects of other classes?
- Which aspects should be invisible to other classes?
- How do I provide a simplified interface to multiple objects?
- How do I appropriately separate the business behavior in my business classes from the technology behavior that my executable system requires?
The result of our activities in Use Case Design will produce the contents of the RUP Design Model, including (but certainly not limited to):
- The design classes (i.e., analysis classes plus technology classes) needed
in our system.
- Realization of the Software Architecture Document (SAD) content through
the design classes.
- The operations and attributes that each design class will own.
- Specification of actual data types, initial values, or interfaces for specific
subsystems or vendor-provided software.
- Partitioning of our system functionality by subsystem or architectural category.
- Interaction (i.e., collaboration and sequence) diagrams showing how our design classes will collaborate to carry out the business process captured in our use cases.
The Design Model will become the raw material that our implementation discipline will transform into executable code. I reiterate that this discussion will focus on a pure object-oriented approach for new system development (often called "green-field" development) in C#, Java, or C++.
When I do Use Case Design activity, I follow the steps depicted in Figure 2, with the exception that I add a step, as you can see in the following revised list:
- Create use case realizations
- Describe interactions between design objects
- Simplify sequence diagrams using subsystems (optional)
- Describe persistence-related behavior
- Define design mechanisms (normally a Software Architect activity in RUP)
- Refine the flow of events description
- Unify classes and subsystems
- Evaluate your results
It is important to recognize that the order of these steps is not fixed. The sequence you follow may differ based on your understanding of the domain you are designing, your experience with RUP, your personal preferences for the models you use, or the metaphor you follow for characterizing the properties of your design classes (e.g., applying design patterns, or following principles such as Separation of Concerns or the Interface Segregation Principle). What is important is that you achieve a comprehensive expression of the solution approach you will eventually implement.
Of the steps listed above, we will look closely at the subtleties of only the five following steps:
- Create use case realizations
- Describe interactions between design objects
- Simplify sequence diagrams using subsystems (optional)
- Describe persistence-related behavior
- Define design mechanisms
To get started, since design is intimately constrained by and related to architecture, let's consult our Software Architect (SA) and get an idea of the overall architecture envisioned for our reservation system. For this discussion, let's stipulate that the SA has produced a Software Architecture Document (SAD) that indicates our architecture must support the following technical criteria:
- Scalability. Multiple, simultaneous customer sessions must be supported
in the Deals on Wheels reservation system and RDBMS. Each session must
be independent of all others, and the system must scale transparently to thousandss
of simultaneous customers.
- Maintainability. Updates to software components must be made easily
and centrally, with no distribution of business logic to browser platforms.
- Technical simplicity. Our rental company does not want to incur the
expense of training or hiring staff competent in full-fledged component environments
such as J2EE or .NET. These are overkill for our limited needs. The existing
staff are knowledgeable in Java, Java ServerPages, servlets, and JavaScript.
- Leverage technology. The Internet must be the communications medium between browser and servers and the system must use existing programmatic interfaces to legacy platforms.
With these criteria as givens, and knowing that the Deals on Wheels project has Java and servlet developers on staff, the SA adds to the SAD the simple UML architectural models shown in Figure 3.
Figure 3: Initial deployment diagram for kiosk system
Figure 3 illustrates the simplest view of the layout between an individual client browser and the legacy Reservation DBMS, which contains reservation, customer, and vehicle information. Figure 4 shows more internal detail as well as some inter-process communication.
Figure 4: High-level physical architecture diagram
The diagram in Figure 4 reflects the high-level structure of our application based on the JavaServerPage (JSP) Model 2 architecture. The customer interacts with a browser on a client computer. The browser communicates via HTTP (Hypertext Transmission Protocol) to the Web server, invoking servlets on the Web server. I have shown only the Reserve a Vehicle servlet specifically. The servlet acts in the role of a controller, coordinating the steps needed to carry out the work of the Reserve a Vehicle use case. The servlet creates and interacts with the business objects, such as Reservation, Customer, Protection Product, etc., that the JSPs will need. The business objects (to be implemented as JavaBeans) obtain their content from the legacy relational database management system (DBMS) via a Java Database Connectivity (JDBC) protocol and interface. The servlet forwards the service request to the appropriate JSP.
Use Case Design step 1: Create use case realization for each use case
In Part 1 of this series, I indicated that a use case realization is really a collection of several UML diagrams and other textual artifacts, such as RUP's Use Case Realization Specification document, which together validate that we have the classes, responsibilities, and object interactions necessary to provide the behavior in our use case process.
In analysis, our use case realization contains only analysis classes and objects, which may populate various UML diagrams such as class diagrams and interaction diagrams. In design, our realization will contain design-level information explaining how the steps of a use case will be carried out by collaborating design objects. Class diagrams, interaction diagrams, and description, of derived requirements will populate our design-level realizations. If you are using a modeling tool such as Rational®Rose or Rational's XDE product, creating a use case realization may simply involve creating a use case model element in the tool, and then creating UML collaborations and interaction diagrams under that. If you are not using a modeling tool, your realization may be a desk drawer containing hand-drawn models or photographs of whiteboard models. Identifying and naming a use case realization provides traceability from the interactions diagrams and textual commentary back to the use case. The remainder of this article is basically a discussion of the contents of the design-level use case realizations.
Use Case Design step 2: Describe interactions between design objects
This is a complex step, so be prepared to refer to several different figures throughout this article, and to observe the iterative process at work. First, note that as part of our Use Case Analysis activity in Part 1 of this series, we produced the analysis class diagram shown in Figure 5 with attributes for our vehicle rental system:
Figure 5: Analysis-level class diagram
This is an adequate, initial description of our analysis classes, and the relationships between various classes, but it is not yet in an implementable form. For example, how do we express in design that a given Reservation must have access to zero or more ProtectionProduct objects? What does it mean that the relationship between VehicleInventory and Vehicle is aggregation, but the relationship between RentalLocation and VehicleInventory is composition? What data types do we specify for Vehicle's status and specialEquipment attributes, or Reservation's dates, times, or estimatedCost attributes? Where do we discover operations to put into our classes? And, how do we represent an interface to the Reservation RDBMS that lets us request, or store changes to, a Reservation or Vehicle status?
Before addressing those questions, note that we can also review the analysis-level Sequence Diagram (SQD) we described in Part 1 for the Check in a Passenger use case, as shown in Figure 6.
Figure 6: Analysis-level sequence diagram (SQD)
Click to enlarge,
then find the four-headed arrow in the lower right of the screen to expand the
graphic to full size.
In Use Case Analysis, our goal was to prove feasibility -- that our business objects had the right responsibilities to carry out the steps of the Reserve a Vehicle use case. We simplified our task by assuming all objects are eternal, and we ignored creation and destruction of objects. But now, in design, we have to explicitly demonstrate creation (and destruction, depending on the programming language used) of our objects. We must also ask "who is in charge" of accessing and "hooking up" the objects needed to service a customer request.
Let's move into how we transform this sequence diagram into a design perspective on the interactions among our objects. We start again with the Reserve a Vehicle use case, specifically the "happy path" scenario where nothing goes wrong.
How will this Reserve a Vehicle use case really start? The sequence diagram snippet in Figure 7 captures a plausible interaction among objects. (For simplicity, I am omitting in this sequence diagram the handling of the customer profile that is in the analysis SQD.)
Figure 7: Design SQD of Reserve a Vehicle
Click to enlarge,
then find the four-headed arrow in the lower right of the screen to expand the
graphic to full size.
When the customer visits the Deals on Wheels Website in Step 1, the home page is visible on the customer's browser, presenting input fields that the customer can fill-in to designate the location, dates, and category of the vehicle she wishes to reserve. When the customer indicates in Step 2 she wants the system to search for vehicles matching these critieria, the JSP posts the form data to the Reservation servlet (RsvnServlet) in Step 3. The reservation servlet has to verify that the selected rental location is actually open on the dates and times selected by the customer, so in Step 4 the servlet creates an empty RentalLocation object, and in Step 5 directs this object to populate itself with the data for the location designated by the selected location identifier. The RentalLocation has to obtain this existing information from our on-line Reservation RDBMS, and in Step 6 I have added a new design class, DataAccess, that implements the Façade pattern. This pattern lets us hide a complicated interface by substituting a class or component with a simplified interface. The RentalLocation object invokes a retrieveLocation(locationID) operation on the DataAccess object, which returns a structured data row. In Step 7 the RentalLocation calls a private operation on itself, fill(dbRecord), which parses the data row and assigns the fields to its appropriate instance variables. At the conclusion of Step 7, this instance of RentalLocation is fully populated for a specific rental location. In Step 8 the servlet asks this specific rental location, "Are you open at these dates and times?" through a validate(dates) operation. In the "happy path" scenario we are discussing, the RentalLocation replies "yes" (OK).
Since the location is open at the selected dates and times, the servlet will obtain the list of vehicles matching the customer's request and have them displayed to the customer. In Step 9 the RsvnServlet creates an empty instance of VehicleInventory to hold the available vehicles matching the customer's criteria. In Step 10, the servlet invokes a populate( ) operation on the VehicleInventory, passing the selection critieria. Since the location inventory and knowledge of vehicle availability is in an on-line data store, in Step 11 the VehicleInventory invokes a method, retrieveVehicles(collection), on the DataAccess object. The intelligence in this method knows to create an empty Vehicle object (Step 12), obtain the vehicle information from the corporate RDBMS (not shown), and then in Step 13 invoke an operation, fill(dbRecord), on the just-created Vehicle object. In fill(dbRecord) the Vehicle object parses the data from the dbRecord (a data row), and fills in its own instance variables. In Step 14 the DataAccess object adds the now-filled in Vehicle object to the VehicleInventory. Steps 12-14 are repeated until all matching vehicles in the result set have been deserialized into objects. Following Step 14, the VehicleInventory and the servlet are notified that their requests have been completed.
The system now has to display the available matching vehicles to the customer. In Steps 15 and 16, the reservation servlet stores the VehicleInventory object in the Session object to be retrieved by the next JSP, and invokes the RequestDispatcher.forward( ) operation to display the ShowInventory JSP in Step 17.
In just this small snippet of our design SQD, we have almost as many messages as the entire analysis sequence diagram. But in our evolution of the design SQD, we have strictly demonstrated how our analysis and technical objects will interact with each other to carry out the work of our Reserve a Vehicle use case. We have determined that VehicleInventory really is just a collection class to hold multiple Vehicle objects, and if we continued the SQD, we would add another collection class to hold all the ProtectionProduct objects that could be assigned to a Reservation.
At this point, we can reconstruct our class diagram (recall Figure 5) based on the new technology classes and new operations discovered while developing this part of the Reserve a Vehicle SQD, as shown in Figure 8.
Figure 8: First class diagram updated with operations
Click to enlarge,
then find the four-headed arrow in the lower right of the screen to expand the
graphic to full size.
Let's step back and look at the larger picture that is developing. As depicted in Figure 7, we adopted an approach that is known as the Java Server Page Model 2 Architecture. This approach is a variation of the separation of concerns principle embodied in the Model-View-Controller architecture. On the left side of Figure 7, there are two JSPs. These are the presentation pages, or views, that are displayed in a browser. In the middle of the SQD is the reservation servlet, which is a controller that knows the steps that have to be carried out to allow a customer to reserve a vehicle. On the right are the entity objects, known as model objects, that have the business knowledge and business relationships we need.
In our development of the SQD snippet shown in Figure 7, we discovered new operations on three of our model classes: Vehicle, VehicleInventory, and RentalLocation. So far, these are operations only to obtain data from on-line storage. As we develop later parts of this SQD, or SQDs for other use cases, we would discover more operations in all of our classes: operations for retrieval, storage, computation, etc.
So let's not stop here. We've only looked at the behavior of getting existing data from online storage into our objects. The next part of the rental process starts when the customer selects a specific vehicle to reserve. In Figure 9, I show the SQD for this part of the process.
Figure 9: Design SQD for second part of Reserve a Vehicle
Click to enlarge,
then find the four-headed arrow in the lower right of the screen to expand the
graphic to full size.
In Step 1 the human customer indicates that she wishes to reserve a specific vehicle. This request is posted to the servlet, which asks the VehicleInventory to mark the vehicle, denoted by a vehicleID, as unavailable temporarily. This marking will prevent other rental customers from trying to reserve the same vehicle. The VehicleInventory forwards this request to the Vehicle object for the vehicle selected by the customer. The VehicleInventory does this with the mark(expiry) operation, in which the expiry parameter is a timeout period in case the customer leaves the page without completing the reservation.
Note that I have included a UML Note ("Update DB status as well?") here. As a practitioner of agile development, I highly recommend that you use a modeling tool only for models that have long-term value. But if you have a long-term model with questions still awaiting resolution, feel free to include the questions right into the model. You may not do this often, but the important point is to get the issue into the open for all to see, and not lose it.
After marking the vehicle, the servlet needs to prepare for displaying the Renter Information page, in which the customer verifies our information on her, and the contents of her Customer Profile. Recall that I omitted the SQD section in Figure 7 that described searching for the CustomerProfile, but now we need the profile and the Customer object, too. In Step 5 the servlet obtains (presumably from the HttpSession object, which is not shown) the customerID that would have been entered on the Deals on Wheels home page. With this ID, the servlet creates (in Step 6) a Customer object, directing it to populate( ) its instance variables using the customer ID. In Steps 8 and 9 the Customer object follows the now-familiar pattern of requesting its content as a dbRecord from the DataAccess object. With the Customer object now instantiated and populated for our specific human customer, in Step 10 the servlet notifies the Customer object of its corresponding CustomerProfile. In Step 11 the Customer notifies the profile that it is the profile's parent. Now we have a bi-directional assocation between these two objects.
With this processing complete, the servlet is ready to display the RenterInformation page, which it does with a RequestDispatcher.forward( ) operation. In Step 13, the RenterInfo JSP page is active. In Steps 14-16, the JSP will obtain generic information from the Customer and CustomerProfile objects and corresponding data will display for confirmation. At Step 17 the RenterInfo page is displayed to the customer's browser for confirmation and completion. In Step 18 the customer indicates she has affirmed, changed, or entered data onto the RenterInfo page, and she is ready to continue the reservation. In Step 19, I again show generically that the JSP will interact with the Customer and CustomerProfile objects (remember, these are JavaBeans) to update them from the screen data. In Step 20, the RenterInfo page posts to the servlet, indicating the renter information is complete. After this we would model how the system presents the summary information on the reservation, including offers to purchase protection products, etc.
We have mapped out quite a bit of interaction in this SQD, and we have discovered more operations on our classes. By promoting our SQD messages to operations on the receiving classes, we have a new version of the class diagram, as shown in Figure 10.
Figure 10: Second class diagram updated with operations
Click to enlarge,
then find the four-headed arrow in the lower right of the screen to expand the
graphic to full size.
Now we see that we have added new operations to Vehicle, Customer, and CustomerProfile. This is the iterative, use case driven approach at work. Starting with our use case and list of classes, we choose objects from those classes to interact, and we construct a SQD to show that interaction. The messages in analysis are assigned to the classes based on the responsibilities we have given each class. Then, the messages are promoted to operations on the class of the object receiving the message. These operations are (in an ideal world) guaranteed to be needed because they are generated to meet the goals of the use case that contains many of the functional requirements of our system. Recall that this Use Case Design step is named Describe Interactions Between Design Objects. In our SQDs, we have certainly done that, and captured the static structure enabling that interaction in our class diagrams.
Use Case Design Step 3: Simplify sequence diagrams using subsystems (optional)
The next Use Case Design step is to simplify repeated behavior by replacing common groupings of objects with a subsystem. In our example, we have already identified a subsystem, the DataAccess object. This subsystem exposes the retrieve ...( ) operations for obtaining object data from the datastore. There is really a lot going on inside the DataAccess subsystem: generation of SQL statements, error handling, result set management, etc. But the gory details are hidden from the client objects requesting data retrieval (and later, data storing).
Often we do not realize we need a subsystem (with simplified interface) until we struggle with a complex set of classes and interfaces that we eventually recognize have a natural affinity for each other (e.g., the classes in a Printing Subsystem: Spooler, QueueManager, PrinterDrivers, etc.) A wonderful principle for grouping classes into subsystems is Robert Martin's Common Closure Principle:
The classes in a package [or subsystem] should be closed together against the same kind of changes. A change that affects a closed package [or subsystem] affects all the classes in that package and no other packages.
In other words, we need to group classes that have a common goal within a clear boundary, so that changes within that package/subsystem are isolated to that package/subsystem. And when we simplify our models by introducing subsystems, we replace large sections of the sequence diagram with a single message to the subsystem. This isolates the former complexity within the subsystem, and we can develop separate models for the internal interactions of the subsystem, which can now be a reusable component in our overall system.
Use Case Design Step 4: Describe persistence-related behavior
But, while we have correctly hidden some of the DBMS details behind the DataAccess subsystem, we have actually made an egregious design mistake: Our analysis objects (Vehicle, RentalLocation, ...) have knowledge of the DBMS. Analysis objects should only know business-logic, not storage locations or storage methods, or dbRecord structure layouts. Why is this bad? Consider the effect of a simple change, which is the primary key for an object changes, and recall that our current design has our analysis objects (e.g., RentalLocation) passing a specific identifier (e.g., locationID) to the DataAccess object. If this identifier is used as a primary key, and then changes, we will have to change the logic in our RentalLocation object.
Is there a way to limit or eliminate this consequence on our analysis objects?
Yes. We can accomplish this logical isolation, in addition to the explicit physical isolation described in our Software Architecture Document, by introducing three new objects:
- A factory object, which creates our analysis objects for us, fully
populated from the DBMS
- A DB object, which is the DBMS-aware "twin" of an analysis
object
- A persistence interface, a subsystem that specializes in getting information in and out of a datastore.
In the sequence diagram shown in Figure 11, we have introduced these three objects and re-created the interactions where the servlet needs a Customer object restored from on-line storage.
Figure 11: Design sequence diagram with persistence layer
Click to enlarge,
then find the four-headed arrow in the lower right of the screen to expand the
graphic to full size.
This is a much more encapsulated design, and allows for great reuse. For each analysis object (e.g., Customer) that must be stored or retrieved from the DBMS, we create a "DB-aware" ("database aware") object (e.g., DBCustomer) that understands the data fields and format of its "normal" twin. These DB-aware objects will reside on the Web server, and will be created and used by one of the servlets. The DB-aware object knows how and where to connect, how to build a SQL statement and get it executed, and how to take the result data and store it into the analysis object. Now, changes to the DBMS format or result set data structure are isolated behind the ObjectFactory layer, and the analysis objects are not affected at all.
We must also evaluate our storage structure to make sure we can store, and retrieve, the data required by our objects. Tables 1-7 indicate a sample logical model of the Reservation DBMS layout. Notice that most of the fields in these tables match the attributes in our classes. But some table fields (e.g., Table 3: Vehicle Date of Purchase) are not in our corresponding class because fields like this are not relevant to the Reserve a Vehicle use case.
Table 1: Rental location
|
Table 2: Reservation
|
Table 3: Vehicle
|
Table 4: Protection product
|
Table 5: Customer
|
Table 6: Customer profile
|
Table 7: Award program
|
Also, notice how the primary key (<PK>) and foreign key (<FK>) properties represent the relationships on the Deals on Wheels class diagram. The Reservation table knows about its corresponding Customer through the CustomerID <FK> field. The RentalLocation table can obtain all of its assigned vehicles through the Assigned Location primary key field in the Vehicle table. The SQL statement created by the DB-aware objects will be generated based on the physical data model for the database being accessed. The SQL statement "SELECT * FROM VEHICLE WHERE ASSIGNEDLOCATION = 42355 ORDER BY VEHICLE.VEHICLECATEGORY" will return a result set of all vehicles assigned to that rental location, ordered by vehicle category (economy, compact, etc.).
Now we can appreciate this very important statement: the design classes you discover and use will depend on the design approach you take. In our first approach to addressing persistence, we put DBMS knowledge in the object representing our business abstractions (i.e., analysis classes). But in our second approach we created an additional layer of DB-aware objects that specialized in getting data into and out of the DBMS.
Use Case Design Step 5: Describe design mechanisms
In our analysis of our vehicle rental system, we identified a need for the following analysis mechanisms:
Persistence. In a normal reservation session, or change reservation session, the Reservation and Vehicle objects will undergo change of data and/or state. So we need a persistence mechanism to store the new object data. In analysis we need only to specify a meaningful name for the persistence store, but the details of how we achieve this persistence will be addressed later in design.
Security. We do not want to show any reservation other than that of the correct individual, so we specify a mechanism to assure authentication security.
Legacy interface. All vehicle information comes from the Corporate Vehicle System that maintains centralized vehicle information for all rental locations. How we talk with the Corporate Vehicle System depends on the design mechanism choices we can use.
In design, we reevaluate and map these into design mechanisms that are specific solutions to the analysis needs for persistence (Table 8), security (Table 9), and legacy interface (Table 10). For each of these, I have additionally shown the implementation mechanisms that will satisfy the design mechanisms, as shown in Table 8.
Table 8:
|
|
|
In this two-part series of articles, I have provided numerous examples to illustrate how to move from initial use cases containing many of our system requirements, to analysis of our problem domain, to design of our solution domain in the context of the specific technical dependencies of our production environment. There are many more topics that have to be considered in system development, but I believe these examples satisfy my limited goal of offering a practical tour of the process. Given the level of detail in our design-level sequence diagrams and class diagrams, the reader should be able to see that translating these representations into Java class definitions or JSPs is a straightforward exercise. With our design artifacts, we can move directly into coding a proof-of-concept, or writing the production code for our system. Each use case will follow the process in these articles until, when all use cases have completed this iterative cycle, we will have most of our system coded, and we will have coded all of the significant business functionality that was captured in our use cases.
Rumbaugh et al., Object-Oriented Modeling and Design. Prentice-Hall, 1991.
Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices. Prentice-Hall, 2003. An award-winning book that covers a broad menu of essential design practices.
Eric Gamma, et al., Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995. Required reading for any developer doing serious development today.
Scott Ambler, Agile Modeling. Wiley, 2002. How to do more with less modeling and overhead.
Len Bass, et al., Software Architecture in Practice. Addison-Wesley, 1998. Excellent coverage of what software architecture really is.
1 All references in this series to RUP incorporate the content of RUP version 2003.06.00. All UML models in this series have been generated using IBM/Rational Extended Developer Environment (XDE) Developer Plus for Java version 2003.06.
Gary K. Evans is the founder of Evanetics, Inc. (www.evanetics.com), a consulting company dedicated to reducing risk on software projects through agile techniques and process. He is the author of over a dozen papers on object technology and tools, and is a frequent speaker at major software conferences. He is an avid soccer player, but loves even more working with small development teams, training them in OOAD and agile RUP, and then working with them side-by-side to deliver the right software faster than they ever thought possible. He can be reached at gkevans@evanetics.com.
Comments (Undergoing maintenance)





