Building a UML Domain Model - Part 2

Last month I initiated a case study in a small hotel reservation domain. In that newsletter for Part 1, I identified a process for producing a domain class diagram:

  1. Identify the domain classes in your project
  2. Identify which of these classes have knowledge of, or relationship with, any of the other domain classes
  3. Identify the semantics (e.g., association, aggregation, etc.) of the relationships between these classes that know about each other
  4. For non-inheritance relationships, identify the multiplicity on these relationships

I split Step 1 into two smaller sub-steps:

Step 1a. Produce a list of "candidate" classes, then

Step 1b. Challenge these candidates to eliminate those that are just simple attributes, synonyms, meaningless terms, etc. - that is, weed-out anything that does not merit "classhood".

Step 1a produced the following candidate classes:

Clerk
reservation
arrival date
duration of stay
System
available bedroom

bedroom
guest information
credit card information
payment reserve
credit card
confirmation number

Step 1b. Challenge the Candidates

Now we need to challenge these candidates, and identify the "real" classes in our domain. To accomplish this I ask 4 questions. These questions are applied to each candidate above with the purpose of eliminating from consideration all obvious non-classes. The four questions are:

  1. Is this candidate inside our system boundary?
  2. Does this candidate have identifiable behavior (methods)?
  3. Does this candidate have identifiable structure (data)?
  4. Does this candidate have relationships with any other candidates or "real" classes?

The algorithm we follow is really simple: if we get a "no" to any question, we conclude the candidate is not a class and we move to the next candidate. Every "yes" takes us to the next question for a candidate. If we get "yes" to all four questions, we conclude the candidate is a class.

Let's see how this works by applying these questions to some of our candidates.

Candidate: Clerk

1. Is Clerk inside our system boundary? No. I stipulated in the first installment of this series that we only want to track the identity -- e.g., a name -- of which clerk makes a reservation. The human Clerk is an actor, or user of the reservation system, and actors are by definition outside the system boundary. Not a class.

Candidate: Reservation

1. Is Reservation inside our system boundary? Yes. It is a central business concept. Next question.

2. Does Reservation have identifiable behavior? Yes. And if "yes" you should identify two or three potential operations (methods) that provide business value in our domain, and getters and setters don't count (I will qualify this below). I can imagine calling Reservation.Assign(aGuest), Reservation.Assign(aBedroom) and Reservation.CalculateCost(). Next question.

3. Does Reservation have identifiable structure? Yes. And if "yes" you should identify one or two attributes (data members) in the candidate. Question 2 informs us that Reservation should have a Cost attribute, and a reference to a bedroom and a guest. It would also have an ArrivalDate and NumberOfNights. Next question.

4. Does Reservation have relationships with any other candidates or "real" classes? Yes. From Questions 2 & 3 it is already clear that Reservation should have relationships with a bedroom, and a guest.

Yes to all four questions - Reservation is a class.

Candidate: Guest Information

1. Is Guest Information inside our system boundary? Yes, our requirements stipulated we want our system to maintain long-lived information about any guest who makes a reservation. Next question.

2. Does Guest Information have identifiable behavior? Yes, there is behavior we can identify, but they would seem only getters and setters. Should we then reject this candidate and move to the next candidate?

Ahh..here we hit a bit of a snag, and why we have to use a light and "thoughtful" application of our challenges. Yes, we need to maintain guest information, but what is going to hold this information? The information is for a guest. So, should we infer a class called Guest to represent what this information is for? Is Guest an important concept in our domain? It would seem reasonable to do so to maintain the concept of a Guest making a Reservation. By allowing Guest as a class I can surmise behavior such as Guest.GetActiveReservations() which would return all current Reservations for a given guest, obviously not just a getter/setter method, and behavior of clear business advantage. Alternately, I could imagine a method in Guest called RevenueOver(aTimePeriod) to determine how much money we have received from a guest over a month, year, or other time period.

Note that this example illustrates the singular fragility of this grammatical dissection approach: it is wholly dependent upon how the requirements are expressed. In our Use Case: Make a Reservation, line 3 was written as: "Clerk selects a bedroom and enters guest information." What if line 3 had been written: "Clerk selects a bedroom and enters information describing guest making the reservation"? In this latter version "guest" would have been a noun, rather than an adjective as in the former sentence. Next question, now using "Guest" as the candidate.

3. Does Guest have identifiable structure? Yes - at the very least all of the guest information, plus references to Reservation(s). Next question.

4. Does Guest Information have relationships with any other candidates or "real" classes? Yes, at least a relationship to Reservation(s).

If we continue our challenge to each of our 12 candidates we will find the following real classes:

Reservation
Bedroom

Guest
CreditCardPayment (renamed from Credit Card)

This is certainly a very small number of classes, but this series is about the process of identifying these classes. Now that we have found these 4 classes, we need to build our UML domain model. That will be the topic in next month's newsletter.


Have a productive month,

    Gary K. Evans



Agile Testing: A New Book

Agile development can be confusing at one's first initiation. Starting a project without all of the requirements, writing tests in code before you write the project code...all of this can be very disorienting. But of all the curiosities that I am asked to clarify, the absolute most frequent questions I encounter are: when does QA do its testing, and how do we handle bugs found in an iteration? Fortunately, we can all now share in the most cogent and lucid explanation of where testing fits in agile development. Agile Testing, written by Lisa Crispin and Janet Gregory, is simply magnificent. Both authors have extensive agile project experience, and their book is replete with sidebars explaining both problems and solutions they have experienced in test effectiveness.

Their book is built around a unifying concept they call the Testing Quadrant. This concept carefully addresses each of the goals of various types of testing: some are technology-facing to support the programmers (e.g., automated unit tests and supporting tools), some are intended to support the team (e.g., automated & manual functional testing), some are business-facing (usability testing & acceptance testing), and some are developed in response to critique & requests for improvement of the product (e.g., when a customer provides feedback on the product's scalability, usability, etc.).

If you are following an agile process, or have just been reading about agile, you know that the Prime Test Directive is: automate, automate, and automate your tests! Chapter 14 is a panoramic presentation of "An Agile Test Automation Strategy". It has already helped me make this transition simpler with a client I am working with this month. If you are confused about, or resistant to, the idea of test automation I believe this one chapter will illuminate the dark corners of your concerns.

Chapters 17 through 19 discuss beginning, executing, and ending an iteration (sprint), respectively. A couple of highlights on test activity at the beginning of an iteration should suffice to motivate you to consider purchasing this book. What testing does QA do at the beginning of a sprint? The code hasn't even been completely written yet! Do the programmers just throw the iteration code over to QA at the end? Crispin and Gregory offer comments and examples from their projects to guide us. Here is a summary just from testing at the beginning of an iteration:

The testers consume user stories and add tests that will validate the story has been implemented correctly. The Team then make their story estimates including performing these tests, because "no story is done until it is tested". The Team commit to a story only if they include the effort needed to conduct all of the tests. Testers collaborate with customers (or surrogates) to explore stories in more detail and begin defining high-level test cases that the developers will know their code has to pass.

If you are involved in any way on an agile team, whether as designer, developer or tester, I cannot recommend this book highly enough. This one is going to be a classic.

Subscribe to our newsletter!

Send an email to
with subject = "Subscribe"

You will find all prior
Evanetics Newsletters here.

About Evanetics

Evanetics provides on-site consulting, training, and assessments for teams and management in Business Analysis, Object-Oriented Modeling, Project Definition, Iterative process, RUP, Agile principles and practices.

How We Can Help

Our Training Offerings

Contact Us

Phone: 803-781-7628

Evanetics' Training

Challenging times such as today can be the best time to enlarge the skillset of your people, so they will be even more prepared when our economy inevitably recovers.

Here is a set of Evanetics' course offerings that may assist your organization:

Agile Development with Scrum. For teams moving to Scrum, or teams who are finding agile development to be not so agile.

Business System Analysis for Object-Oriented Projects. Business analysis and specification for the more technically-savvy system analyst. Thorough coverage of UML for the Business System Analyst.

Writing Effective Use Cases. Written by Alistair Cockburn and based on Cockburn’s award-winning book, this course focuses exclusively on Cockburn’s approach for writing useful and effective use cases for any type of software project.

Use Cases for the Rational Unified Process. Use cases according to the Rational way. Focus is on how to write useful and effective use cases, efficiently.

Rational Unified Process Ver. 7. Describes the latest version of the Unified Process, the Unified Method Architecture, the 9 RUP Disciplines, and how RUP affects the major project roles in your organization.

Use Cases to Code: Analysis with UML. Focuses on how to first represent “what” functionality object-oriented software systems will provide their users, rather than “how” the software will be designed.

Use Cases to Code: Design with UML. Covers software architecture and software design in detail, including Gang of Four design patterns, Web architecture and Model-View-Controller, the evolution of Service-Oriented Architecture and Web Services, and how to develop a persistence layer for mapping classes to a Relational DBMS.

Offshore & Off Course

In line with this issue's topic of testing (and mixed with not a little hard-won cynicism), a column in this month's Visual Studio magazine brings home the real costs of offshore development and not testing properly. Alex Papadimoulis' Dev Disasters Column recounts a tale from Steve of how his company embraced offshoring with the usual mantra that "it is inexpensive". So they offshored a small project...that eventually became a 10,000 person-hour rewrite of their document management system, a major part of the company's main product. Then testing was offshored - it is inexpensive. And then first-line customer support was also offshored.

Soon reports of anomalies started appearing: document changes were being lost. The offshore customer support declared "user error" and proceeded to inform the users how to save their documents - which the customers already knew how to do quite well, thank you. When the company's major client threatened to go to another vendor, Steve was assigned to research the issues. He and another developer eventually found two data declarations for disaster:

public static string UserID;
public static int DocumentID;

Static data. Read: global.

Read: classic race condition.

In this multi-user system, these data fields held the identifiers for the current (i.e., latest) document being manipulated, and saved. When user #1 and user #2 opened documents, the latest DocumentID was placed in this field. When the first user saved changes, then the second user saved, the latter overwrote the former. Hence, changes were not "sticking" - but only for some users, not the last to save.

When the customers learned the defects in the code and its horrific design, many jettisoned the product and its vendor, others demanded refunds. And their bread-and-butter customer? They sued. But the offshoring was "inexpensive".

I am not against all offshoring. My point in describing Papadimoulis' column is to remind all of us - managers, developers, testers - that sending our software overseas does not make our software better or safer. Offshoring successfully is more difficult and requires more effort than in-house development. I have worked with too many groups who have learned in the hardest possible way that if they cannot successfully run a software project between the 2nd and 4th floors of their own corporate headquarters, how could they expect to do it across 9 time zones, and 2 or 3 language and cultural divides?