Read Part 1: Driving Design with Use Cases
Welcome to the second in a series of five articles that provide a pre-publication look at the annotated example from our forthcoming book Applied Use Case Driven Object Modeling(Addison-Wesley, 2001; tentatively scheduled for April). We're following the process detailed in our first book, Use Case Driven Object Modeling with UML (Addison-Wesley, 1999), as we dissect the design of an Internet bookstore.
The focus of this article is domain modeling. The term "problem domain" refers to the area that encompasses real-world things and concepts related to the problem that the system is being designed to solve. Domain modeling is the task of discovering "objects" (classes, actually) that represent those things and concepts.
You may wonder why we're starting a series on use case driven object modeling by writing about the seemingly unrelated subject of domain modeling. The reason is that we write our use cases in the context of the object model (which we'll discuss in next month's article), instead of from an abstract, pure user viewpoint. This process allows us to connect the static and dynamic portions of the model, which is essential if we're going to drive our application design forward from the use cases. The domain model serves as a glossary that the writers of use cases can use in the early stages of that effort.
Within the ICONIX process, domain modeling involves working outward from the data requirements to build a static model of the problem domain relevant to the proposed system. This inside-out approach contrasts with the outside-in approach we take toward user requirements, which we'll describe in the third article in this series. (The fourth article, about robustness analysis, will describe how the domain modeling and use case development paths merge.)
|Figure 1. The "Big Picture" for Use Case Driven Object Modeling|
The diagram portrays the essence of a streamlined approach to software development that includes a minimal set of UML diagrams and some valuable techniques that take you from use cases to code quickly and efficiently.
Figure 1 illustrates where domain modeling resides within the "big picture" for the ICONIX process.
Key Elements of Domain Modeling
The first thing you must do when building a static model of your system is find appropriate classes that accurately represent the real abstractions that the problem domain presents. If you execute this activity well, you will not only have a solid foundation on which to build the system, but also excellent prospects for reuse by systems that will be designed and built over time.
The best sources of classes are likely to be the high-level problem statement, lower-level requirements and expert knowledge of the problem space. To get started, lay out as many relevant statements from these areas (and even others, such as marketing literature) as you can find, and then circle, or highlight, all the nouns and noun phrases. As you work, refine the lists; gradually, nouns and noun phrases will become objects and attributes, while verbs and verb phrases will become operations and associations. Possessives ("its," "ours" and "theirs") tend to indicate that nouns should be attributes, rather than objects.
Next, sift through your list of candidate classes and eliminate unnecessary items. Look for classes that are redundant, irrelevant, incorrect or vague. Unessential classes may also represent concepts outside the scope of the model, or represent actions even though they're phrased as nouns: For example, Order Processor represents the nounification of the verb pharse, "process order."
You should also make some initial decisions about generalization ("kind of" or "is a" relationships among classes) while building your class diagram(s). If you need to, and you're comfortable doing so at this stage, generalize to more than one level of a subclass. Remember to look for kind-of statements that are true in the real world. Domain modeling is also the appropriate area for decisions about aggregations ("part of" or "has" relationships among classes).
Finally, much like an entity-relationship diagram (ERD), your domain model, updated to show associations—the static relationships between pairs of classes—should be a true statement about the problem space, independent of time (that is, static). This model serves as the foundation of your static class model.
The Top 10 Domain Modeling Errors
The flip side of the principles that we just discussed are a number of common errors that our students make when they're doing domain modeling for their projects. Our "top 10" list follows:
10. Don't immediately assign multiplicities to associations. Make sure that every association has an explicit multiplicity. Some associations on a class diagram represent one-to-one relationships, while others represent one-to-many relationships. These are both called multiplicities. However, you can avoid dealing with multiplicity altogether during domain modeling—it chews up time and can be a major cause of analysis paralysis, which we'll signal with this symbol.
9. Don't do such an exhaustive noun and verb analysis that you pass out along the way. Kurt Derr's Applying OMT (SIGS Books, 1995) is a good source of information about "grammatical inspection." If you follow Derr's advice to the letter, however, you'll likely reach such an extreme level of detail, at such a low level of abstraction, with regard to your objects, that you can't breathe. Use this technique to get your object discovery started, but take care not to get carried away.
8. Don't assign operations to classes without exploring use cases and sequence diagrams.Take a minimalist approach to defining operations during domain modeling. In fact, don't assign any operations to classes during domain modeling, because there isn't enough information available with which to make good design decisions about operations at that stage. Wait until you begin interaction modeling, before you assign operations to classes.
7. Don't optimize your code for reusability before making sure you've satisfied the user's requirements. The more general your objects and classes, the higher the probability that you'll be able to reuse those objects and classes for other projects. A complete class is one that is theoretically reusable in any number of contexts. However, in order to achieve reusability and completeness, you must consider both attributes and operations, and we just told you why you shouldn't be assigning operations to classes during domain modeling. So don't worry too much about making classes reusable when you're doing high-level class diagrams.
6. Don't debate whether to use aggregation or composition for each of your part-of associations. Grady Booch's original descriptions of "has by reference" relationships morphed into aggregation within UML. Similarly, "has by value" became a "strong" form of aggregation called "composition" within which a "piece" class is "owned by" one larger class. Trying to differentiate between these two during a domain modeling effort is a definite way to do some serious tail-chasing. We much prefer to focus on simple aggregation during domain modeling. Aggregation versus composition is a detailed design issue.
5. Don't presume a specific implementation strategy without modeling the problem space. As part of the ongoing refinement of your domain model, you should remove anything that clearly states an action rather than a dependency or that is specifically related to implementation. Don't introduce things on your high-level class diagrams that represent commitments to specific technologies, whether it's a relational database or a particular kind of server. Leave implementation issues to implementation.
4. Don't use hard-to-understand names for your classes, like cPortMgrIntf, instead of intuitively obvious ones, like PortfolioManager. Doing domain modeling up front helps everyone on the project team agree on what classes should be called. The more obvious the class names, the easier that task will be. Save acronyms and other kinds of abbreviations (if you insist on having them) for implementation.
3. Don't jump directly to implementation constructs such as friend relationships and parameterized classes. UML offers lots of opportunities to add what we call "Booch stuff" to class diagrams. This includes constructs that come more or less directly from C++, such as abstract and parameterized classes and friend relationships. These are more relevant to the solution space than to the problem space, though, and the focus of domain modeling should definitely be the problem space.
2. Don't create a one-for-one mapping between domain classes and relational database tables. If you're reengineering a legacy system that uses a relational database, the tables within that database are likely to be an excellent source of domain classes. However, be careful not to just bring them over to your static model wholesale. Relational tables can have lots of attributes that might not belong together in the context of an object model. You should use aggregation to factor groups of attributes into "helper" classes, which contain attributes and operations that are relevant to more significant classes.
1. Don't perform "premature patternization," which involves building cool solutions, from patterns, that have little or no connection to user problems. Patterns often become visible during robustness analysis. As we'll explore in the fourth article of this series, there are two strategies, "control in the screen" and "use case controller," that lend themselves to discovering patterns connected to use cases. Looking ahead to interaction modeling, design patterns can be highly useful in the context of sequence diagrams and design-level class diagrams. However, domain modeling is not the time to start thinking in terms of patterns.
|Figure 2. A Flawed Class Diagram|
This class diagram violates the third, fifth, sixth, eighth and ninth rule from our top 10 list of domain modeling mistakes.
Figure 2 shows a class diagram that violates five of the top 10 rules.
Did you spot the violations?
- The cBinaryTree class is a parameterized class (also known as a template class within UML). This violates rule number three. There is no good reason to define an implementation construct such as a binary tree at this stage of modeling.
- The name of the cSessionBeanShpngCrt class indicates that the modeler has decided to represent the concept of a shopping cart using a session Enterprise Java Bean (EJB). This violates rule number five. Robustness analysis, which we'll discuss in the fourth article in this series, is the appropriate stage to explore how to map classes to Java Beans and so on.
- This class also has a composition relationship with the Order class. This violates rule number six. The modeler has committed to the idea that an order disappears when the shopping cart object to which it belongs is destroyed. This may or not make sense in the long run, but it's certainly too soon to be thinking along those lines.
- The cLoginMgr class has an operation named verifyPassword. This violates rule number eight. It's too early to make decisions about which operations go on which classes, and besides, chances are good that the operation belongs on the Login Info class anyway.
- The names of the two classes we just discussed should be Shopping Cart and Login Manager. The current names both violate rule number four.
|Figure 3. A Corrected Class Diagram|
The rule violations found in Figure 2 are corrected here.
See the diagram in Figure 3 to see how the mistakes are corrected.