CSC/ECE 517 Fall 2010/ch6 6h mf

From Expertiza_Wiki
Jump to navigation Jump to search

Domain Models

Introduction

The domain model is an object model that encapsulates the rules, logic, and data associated with the problem domain. The principle advantage of domain modelling is that it separates the concern of domain-specific problem solving from other concerns like the user interface and persistent storage.

A number of different terms are used to refer to the domain model and related concepts. These include Domain Object Model (DOM), domain layer, business layer, business logic, business logic layer (BLL), business tier, and logic tier. Many of these terms are used when describing multi-tier architectures. The canonical example is the three-tier architecture composed of the a presentation tier, logic tier, and data tier. The presentation tier is responsible for the user interface. The logic tier (domain model) is responsible for solving problems in the specific domain of the application (often a business domain, hence the term business logic). The data tier is responsible for storing and retrieving information, typically to and from a database.

The three-tier architecture illustrates how domain modelling helps achieve separation of concerns. The presentation tier could be implemented in a number of different ways. For example, it could be a command-line interface (CLI), a graphical user interface (GUI), or a web-based interface. It might be desirable to support several different types of user interfaces. However, the type of interface and its implementation is largely independent from the problem domain. Separating the behaviour and data of the user interface from the behaviour and data of domain model enables developers to reuse domain-specific code while implementing various user interfaces. In addition, weak coupling between the user interface and domain model allows the domain-specific code to vary with negligible effect on the user interface code.

Understanding the problem domain is critical to developing a good domain model. Well-designed software should exist to solve a problem. The problem domain encompasses all the entities, relationships, data, rules, and logic that are necessary to solve the problem. Conversely, entities, relationships, data, rules, and logic which are not necessary to solve the problem are outside the problem domain.

Domain objects represent real world entities, both tangible and intangible, encountered in the problem domain. For example, consider the Spring framework PetClinic sample application, which is a simple example of a three-tier architecture. The essential elements of the domain model are represented in UML in the figure below. The domain objects include Person, Vet, Owner, Pet, and Visit. Visit is an example of an intangible entity, in other words an abstract concept, that is part of the problem domain. Contrast these domain objects with GUI objects like buttons and text fields which are not relevant to the problem domain (in this case, operating a veterinary clinic).

In addition to representing real world entities (domain objects), domain models also represent the relationships between these entities. For example, an Owner has an is-a relationship with a Person and a has-a relationship with a Pet. These relationships are of little relevance to the user interface. In the database, some relationships, particularly has-a relationships, must be represented. However, others, like is-a relationships, typically do not. For example, the base class Person, an important abstraction in the domain model, does not even appear in the PetClinic database. This is because the database is primarily concerned with storing and retrieving application data. Abstractions are relevant to the domain model, but the database only needs to represent concrete data.

An example of business logic

The PetClinic example is useful for understanding domain objects and the relationships between them, but another important aspect of the domain model is that it represents rules and logic that are specific to the problem domain. The following example of some business logic that could be represented in a domain model appears in "The mythical business layer."

When a Sale is Cleared, only Managers with Void Approval and Executives may issue a Cancellation Request. If the Propagation Status for the Transferable Receivable is not Pending and the Expense Allocation Type is Reversible, the Cancellation Request is issued for Processing; otherwise, it is issued for Approval.

This example dictates the circumstances of the cancellation of an item (a TransferableReceivable) from a sale. An example of a rule contained in the statement is that "only Managers with Void Approval... may issue a Cancellation Request." Potential domain objects are Sale, Manager, Executive, CancellationRequest, and TransferableReceivable. An example of a behaviour that a Manager may exhibit is issueACancellationRequest(). An example of domain-specific data is hasVoidApproval which is an attribute of a Manager.

Possible class diagrams for the domain objects are presented in UML below. Has-a relationships are represented through attributes. Is-a relationships are not explored. It would stand to reason that Manager and Executive both inherit from an Employee class, but this is not modelled below.

Sale
items : TransferableReceivable[]
clear()


Manager
hasVoidApproval : Boolean
issueACancellationRequest(item : TransferableReceivable) : CancellationRequest


Executive

issueACancellationRequest(item : TransferableReceivable) : CancellationRequest


CancellationRequest
item : TransferableReceivable
issueForProcessing()
issueForApproval()


TransferableReceivable
propagationStatus : Enum
expenseAllocationType : Enum

Notice how these class diagrams encapsulate entities (domain objects), data (attributes), and behaviour (methods) which are relevant and specific to the business problem that the application solves, namely cancelling items from a sale which has been cleared. This domain model does not address how information is presented to the user or how information is made persistent. These are issues which are not specific to the problem domain and are therefore addressed outside the domain model. Understanding which issues are specific and relevant to the problem domain and which are not is essential to developing a good domain model.

Anemic domain models

When domain models fail to encapsulate behavior as well as entities and data, the anemic domain model anti-pattern results. One symptom is the presence of a service layer which provides methods which operate on the objects in the domain model. Adding a service layer can reduce code duplication, especially if there are many different domain objects with similar behaviours. However, the domain model becomes anemic when the service layer unnecessarily subsumes behaviours from the domain model.

For example, consider the business logic example given above. One could create a service object CancellationRequestIssuer like the one diagrammed below.

CancellationRequestIssuer

issue(employee : Manager, item : TransferableReceivable) : CancellationRequest
issue(employee : Executive, item : TransferableReceivable) : CancellationRequest

This may seem like a reasonable way to avoid code duplication, since presumably a CancellationRequest issued by a Manager will be more or less identical to one issued by an Executive. However, there is an additional bit of logic in the domain model for a Manager which this design pushes into the service layer. Namely, before allowing a Manager to issue a Cancellation request, the application must check that the Manager attribute hasVoidApproval equals true.

Putting this logic in CancellationRequestIssuer violates the encapsulation of hasVoidApproval within Manager. In addition, stripping this logic out of Manager reduces cohesion. Furthermore, with this design, CancellationRequestIssuer is responsible for assuring that all domain objects which may issue a CancellationRequest are authorized to do so. This means that CancellationRequestIssuer is tightly-coupled with these domain objects (in the sense that it needs information encapsulated within them to authorize requests).

A better design keeps the domain object-specific logic in the domain model. One way to accomplish this and still use the service object above is to add a mayIssueCancellationRequests() method to domain objects which may be passed to a CancellationRequestIssuer which returns true if they are authorized to issue a CancellationRequest and false if they are not. This allows domain objects to encapsulate their own specific logic, while allowing CancellationRequestIssuer to generalize the actual issuance of a CancellationRequest.

Conclusion

Domain modelling is a useful technique for separating problem domain-specific concerns from concerns which are unrelated to the problem domain, like user interfaces and databases. Developing a good domain model requires a thorough understanding of what is and what is not part of the problem domain. Good candidates for inclusion in a domain model are real-world entities related to the problem the software solves, the relationships between those entities, and the behaviours and data associated with those entities.

A good domain model is only weakly-coupled with other parts of an application. This allows domain-specific logic and entities to vary without affecting other system components and vice versa. However, a good domain model is still cohesive. Separating responsibilities from domain objects unnecessarily produces the anemic domain model anti-pattern in which service objects are tightly-coupled with domain objects and domain objects lack cohesion.

References