Structural models

Structural models of software display the organization of a system in terms of the components that make up that system and their relationships. Structural models may be static models, which show the structure of the system design or dynamic models, which show the organization of the system when it is executing. These are not the same things—the dynamic organization of a system as a set of interacting threads may be very different from a static model of the system components.

You create structural models of a system when you are discussing and designing the system architecture. Architectural design is a particularly important topic in software engineering and UML component, package, and deployment diagrams may all be used when presenting architectural models. Deeper details on architectural modeling will be covered in the next chapter. Here we focus on the creation of the analysis-level class diagrams only that are useful for better understanding of the problem domain.

Domains represent the different subject matters that we need to understand to build a system. A domain is an autonomous, real, hypothetical or abstract world inhabited by a set of conceptual entities that behave accordingto characteristic rules and policies. (Definition from [MELLOR2002].) We abstract like things and and call them classes. In forming such abstractions, we ignore most of the things as our aim is to leave out details and concentrate only on the important aspects. The remaining things are are grouped according to some perceptions about what is means to be "like".

Important

A domain model is a representation of real-world conceptual classes, not of software components. It is not a set of diagrams describing software classes, or software objects with responsibilities. A domain model serves as a visual dictionary of abstractions.

UML uses class diagrams at all abstraction levels to describe the static structure of a system. Starting from domain classes and abstract concepts through design patterns till the constructs of programming language(s) used for the implementation, we use classes. However, you should not think that the same name means the same construct: a UML class and a Java class, for example, might be quite similar and very different, as well. This is because UML uses 4 interpretations when talking about classes:

Table 3.1. UML interpretations of classes

Class as a conceptClasses can be used to document and define concepts. We use classes to describe (more) abstract concepts based on some existing concepts.
Class as a data typeClasses can be considered as data types. Object instances are considered to be the values of the data type so a class is defined by its internal structure (intension).
Class as a set of objectsClasses can be seen as a set of similar objects that belong to the same class (extension).
Class as implementationIn object-oriented programming languages classes play only the role of an implementation that is shared among the instances.


Class diagrams appear in different contexts. It is very convenient to classify them based on the stages of the software engineering lifecycle where they are used.

Analysis-level classes are the elements of the problem domain. They help us to understand and document the problem space.

Design-level classes are about how to transform domain structures into technical structures so we work in the solution space instead of the problem space. Design-level classes combine domain motivations with technical aspects. Some of the classes are closer to the domain elements while others are closer to the elements of the solution.

Implementation-level classes show how a solution is given. These classes map directly to the corresponding construct of the implementation language (Java, C# or C++, etc.).

First we need to establish an analysis-level class diagram as this is waht is needed to describe the problem domain itself. To achieve this, an abstraction process is needed: we need to find out what elements (constructs) of the real world are important for our universe of discourse, how can the concepts of the problem domain be revealed.

We choose attributes that support the ideas of likeness we have in mind when abstracting the class. Relationships exist between the things of the domain that are abstracted to associations between classes. The result of this abstraction process is an analysis-leve class diagram that will serve as a good source for further refinements (to evolve it into design-level and probably implementation-level diagrams).

Identification of domain classes

The domain model illustrates conceptual classes or vocabulary in the domain. Informally speaking, a conceptual class is an idea, thing, or object. More formally, a conceptual class may be considered in terms of its symbol, intension, and extension.

  • Symbol: words or images representing a conceptual class.

  • Intension: the definition of a conceptual class.

  • Extension: the set of examples to which the conceptual class applies.

Consider the conceptual class for a product as an example. Its symbol is Product, its intension is that is represents something that can be sold or bought which has a name and a unit price. The Product's extension is the set of all products.

Important

It is better to overspecify a domain model with lots of fine-grained conceptual classes than to underspecify it. Do not think that a domain model is better if it has fewer conceptual classes; quite the opposite tends to be true.

It is common to miss conceptual classes during the initial identification step, and to discover them later during the consideration of attributes or associations, or during design work. That's why this work should be performed in iterations. When a new conceptual class is found, the domain model should be augmented. Relational database design principles are probably not the best to follow since when modeling the domain, even attributeless classes might be important to include as they describe a purely behavioral role in the domain instead of playing an informational role.

A common technique used for class identification is to look for the noun phrases in the overall project description. In our case study, we had nouns like customer, order, payment, category, book, DVD, product, name, address, etc. These nouns will be potential classes and attributes.

In order to decide whether a given noun describes a class or an attibute we can apply the following guideline: if it has an identity in the domain then it is a class, otherwise it is an attribute. In this latter case, of course, we need to find its class, as well. That is the reason why we execute this process in iterations. First, we only concentrate on classes, then in a new iteration we assign attributes to classes. The third phase should be finding additional attributes that did not come up in the textual description.

By following these guidelines, we can find a set of initial classes that belong to the domain.

Figure 3.34. Initial domain classes

Initial domain classes


Name, address and category are such nouns that does not describe a real world entity but instead they provide some descriptive information about real world object.

Note

Of course, the actual domain highly influences such decisions. Would this system be used for the registry of real estates, address of a property might become a first-class citizen of this system and should have been modeled as a class instead of an attribute.

Name can be associated with users, customers, manages, administrators but produts might also have a name. Category is something that allows grouping of various products. Address is belonging to humans (a home address, for example), however, an order can also have associated addresses in multiple roles: a billing address and a shipping address are both addresses. From the domain's perspective these belong to the order not the customer since without an order it would be pointless to talk about a customer's billing or shipping address. That's why it is not considered as a attrribute of the customer but something that describes an order.

After that, we need to identify additional attributes of our domain classes. Even if they were not mentioned in the description, customer's phone number (that can be used to contact the customer), the order's date or the actual price of a product are examples of such descriptive information that can easily be identified when investigating the domain deeper. Even we might think that orders have an attribute called customer which represents the person fro whom this order has been created.

Later, we need to find the relationships among our domain classes. As a first step of this identification, we should look for the possibility of generalization. Are there any classes that describe more general (or more specific) concepts than others? We should take care of the substitutability. We should introduce generalization/specialization relationships only when the instances of the subclass always belong to the superclass, as well. From our domain, we can state that a book is a product, and the same holds also for DVDs. An administrator and a customer are users and a manager is special case of an administrator (based on our system's glossary).

Besides generalization/specialization, containment is also an important relationship type. We need to figure out whether we have concepts in our domain that are members (parts) of othe concept. In our domain, we can say that a shopping cart contains products, or, contrary, a product is a part of a shopping cart. We should decide how strong this containment relationship is, to find out if it is an aggregation or an even stronger composition. The question to ask is: if a shopping cart is deleted, will products (the cart's members) be also deleted? Of course, products remain products, regardless if shopping carts exist or not, therefore it is an (shared) aggregation.

Figure 3.35. Product is part of ShoppingCart

Product is part of ShoppingCart


We now look for whether there are attributes that have types of some other classes. As we stated, orders have an attribute Customer but we also have such a class that describe a customer. Therefore, this attribute will be transformed to an association betweern those classes in out domain model.

If we consider that product categories might be hierarchical then we can conclude that maintaining category as a product attribute is not flexible enough. That is why we create an independent class for product categories: each category might be in a hierarchical relationship with other categories. Of course, this will also result in an association between classes Product and ProductCategory.

A shopping cart might contain the same product multiple times (if the customer wants to purchase multiple instances of the product). In order to model this issue, the simple containment (as identified above) might not be appropriate. Therefore we can convert it into an ordinary association between ShoppingCart and Product. Still it misses the quantity which is a descriptive information about the association itself and not about any of the participating classes. Therefore we can introduce an association class ProductSelection that can capture this information. By analysing the domain, we can also find that (especially when some customers have discounts) the price one buys a product actually might differ from the list price of the product so it is reasonable to include the actual price into ProductSelection, as well. Important to note that if the domain allows discounts then this is still a reflection of a domain concept not a design decision.

Finally, we need to decide on the multiplicities of association, as well. For many cases, it is very straightforward to determine by examining the domain. However, we would like to draw your attention to the fact that multiplicities are very important and they influence subsequent design activities. Let us take a look at the association between ShoppingCart and Order! The multiplicities we selected (and depicted on the following diagram) state that for each shopping cart there might or might not exist an associated order. This is very natural as it is possible to populate a shopping cart and later abandon the whole process (so decide to not to buy the contents of te cart). On the other hand, there is exactly one (1) shopping cart that to each order. What does it mean? An order instance can only be created when there is an associated shopping cart. It is also easy to understand that this model does not allow placing an order in an other ways than using a shopping cart as an order object cannot exist without an associated cart. If the domain would allow orders to created by other means than using a shopping cart then 0..1 will be a more convenient decision.

Important

When modeling an application, you will always have lots of options. Many of those might result in a good design (even if it is very hard to tell what good is). However, you should always be aware of the consequences of your decisions. They will form constraints on subsequent design activities.

Let us consider the association between Product and ShoppingCart! The same product can be selected in multiple (or none) carts, this is very easy to understand. It is hard to think of requirements that would think it differently. From the other direction, however, this model shows that a shopping cart instance contains at least one product. This has a consequence that a shopping cart can only be created when there is a product to be placed in it so an empty cart is not allowed. We should only make such decisions if they are dictated by the domain (or at least if we have good reasons for that). Otherwise it will not allow the architect who performs the detailed design to pick a solution that deals with empty carts.

That said, we can draw our initial domain model.

Figure 3.36. Initial domain model

Initial domain model


In analysis-level class diagrams classes and attributes reflect domain concepts. Attribute names do not need to follow the well-known conventions of some programming languages. They can be capitalized and they can even contain spaces (this also emphasises that we concentrate on the domain, independently of any computer system).

Attribute details are often omitted. Some of them does not even have a type assigned yet but even those attributes whose types have been identified reflect concepts in the domain: PersonalName, Count, Money and Address are examples for it. Not all attributes have domain-specific types: even is this early phase we can decide (based on the domain) whether some attributes are textual (of type String) or numeric.

Refining the model

Even if enough care is taken when designing our domain models, there might be some concepts that were missing. When they are found (regardless which stage of the development cycle we are in) the model should be revised. In many cases, this is not about forgotten concepts but either the deeper understanding results in the need for some claases, attrubutes or relationships or we left out some concepts on purpose for subsequent iterations.

The latter has happened with our initial model. There we omitted details on type of attributes, however, UML can use stereotypes primitive and dataType for defining special classes that represent data types. Primitive types are those for which identity is not used in checking equality. PersonalName, TelephoneNumber and Count are examples of primitive types. Of course, one might think that simply using Strings instead of first two or integer instead of Count would be enough since thi is how we will implement them finally. However, it would be a bad idea to make such a decision now, at analysis level. Of course, not all of the strings would qualify as a name of a person or as a phone number. They must follow some patterns that are known from the domain.Using String in place of TelephoneNumber would mean that we do not want to check the format of phone numbers for sure, just as we do not do any checks on other textual objects (like on product description).

We can also apply analysis patterns. Pattern P of EAA 488 descibes the Money pattern to represent monetary values. This pattern was described by Martin Fowler in page 488 of his excellent book entitled Patterns of Enterprise Application Architecture [FOWLER2002] (a similar pattern, Quantity, has been described earlier in [FOWLER1996]). This pattern advocates the coupling of an amount and a currency type together. For the sake of completeness, the primitive types can be seen as a manifestation of Value object pattern (P of EAA 486).

We can also notice that the class Order did not contain any information on the status of the order (which needs to be traceable according to the reuirements) or the payment type how the order is paid. Most systems offer a set of possible order states and payment methods that are allowed. Therefore we can create few enumerations that list those acceptable values. These are illustrated in Figure 3.37, “Revised domain model with supporting data types”.

Figure 3.37. Revised domain model with supporting data types

Revised domain model with supporting data types


However, even this revised model does not contain information on the concept of bookshelf which is something like a wishlist where customers can save those products that they are interested in. A bookshelf is associated with a customer and contains products. Do you remember the reasons why we switched to represent the relationship between ShoppingCart and Products from aggregation to associaton with an association class? A sloppy reader would think that we face the same problems now. However, this is not true. There is no reason to put the same product more than once onto a bookshelf (contrary to the case of shopping cart) so no additional pieces of information are needed so using aggregation seems to be a good choice. Products put onto the bookshelf are ordered: however, it is up to the customer to reorder itts elements. But since there is an order that exists, we can use the {ordered} constraint to denote it.

Figure 3.38. Domain model after introducing Bookshelf

Domain model after introducing Bookshelf