13.6. Guideline: Design with Layers
The essential ideas of using layers [BMRSS96] are simple:
- Organize the large-scale logical structure of a system into discrete layers of distinct, related responsibilities, with a clean, cohesive separation of concerns such that the "lower" layers are low-level and general services, and the higher layers are more application specific.
- Collaboration and coupling is from higher to lower layers; lower-to-higher layer coupling is avoided.
Some more design issues are covered later, starting on p. 559. The idea is described as the Layers pattern in [BMRSS96] and produces a layered architecture . It has been applied and written about so often as a pattern that the Pattern Almanac 2000 [Rising00] lists over 100 patterns that are variants of or related to the Layers pattern.Using layers helps address several problems:
- Source code changes are rippling throughout the systemmany parts of the systems are highly coupled.
- Application logic is intertwined with the user interface, so it cannot be reused with a different interface or distributed to another processing node.
- Potentially general technical services or business logic is intertwined with more application-specific logic, so it cannot be reused, distributed to another node, or easily replaced with a different implementation.
- There is high coupling across different areas of concern. It is thus difficult to divide the work along clear boundaries for different developers.
The purpose and number of layers varies across applications and application domains (information systems, operating systems, and so forth). Applied to information systems, typical layers are illustrated and explained in Figure 13.4.
Figure 13.4. Common layers in an information system logical architecture.[1]
[View full size image]
[1] The width of the package is used to communicate range of applicability in this diagram, but this is not a general UML practice. AKA means Also known As.
The Application layer in 567.
Benefits of Using Layers
- In general, there is a separation of concerns, a separation of high from low-level services, and of application-specific from general services. This reduces coupling and dependencies, improves cohesion, increases reuse potential, and increases clarity.
- Related complexity is encapsulated and decomposable.
- Some layers can be replaced with new implementations. This is generally not possible for lower-level Technical Service or Foundation layers (e.g., java.util ), but may be possible for UI, Application, and Domain layers.
- Lower layers contain reusable functions.
- Some layers (primarily the Domain and Technical Services) can be distributed.
- Development by teams is aided because of the logical segmentation.
Guideline: Cohesive Responsibilities; Maintain a Separation of Concerns
The responsibilities of the objects in a layer should be strongly related to each other and should not be mixed with responsibilities of other layers. For example, objects in the UI layer should focus on UI work, such as creating windows and widgets, capturing mouse and keyboard events, and so forth. Objects in the application logic or "domain" layer should focus on application logic, such as calculating a sales total or taxes, or moving a piece on a game board.UI objects should not do application logic. For example, a Java Swing JFrame (window) object should not contain logic to calculate taxes or move a game piece. And on the other hand, application logic classes should not trap UI mouse or keyboard events. That would violate a clear separation of concerns and maintaining high cohesion basic architectural principles.high cohesion p. 314 Later chapters will explore these important principles, plus the Model-View Separation Principle , in greater detail.Model-View p. 209
Code: Mapping Code Organization to Layers and UML Packages
Most popular OO languages (Java, C#, C++, Python, …) provide support for packages (called namespaces in C# and C++).Here's an example, using Java, for mapping UML packages to code. The layers and packages illustrated in Figure 13.2 can map to Java package names as follows. Notice that the layer name is used as a section of the Java package name:
Notice that, to support cross-project reuse, we avoided using a specific application qualifier ("nextgen") in the package names unless necessary. The UI packages are related to the NextGen POS application, so they are qualified with the application name com.mycompany.nextgen.ui.* . But the utilities we write could be shared across many projects, hence the package name com.mycompany.utils , not com.mycompany.nextgen.utils .
// --- UI Layer
com.mycompany.nextgen.ui.swing
com.mycompany.nextgen.ui.web
// --- DOMAIN Layer
// packages specific to the NextGen project
com.mycompany.nextgen.domain.sales
com.mycompany.nextgen.domain.payments
// --- TECHNICAL SERVICES Layer
// our home-grown persistence (database) access layer
com.mycompany.service.persistence
// third party
org.apache.log4j
org.apache.soap.rpc
// --- FOUNDATION Layer
// foundation packages that our team creates
com.mycompany.util
UML Tools: Reverse-engineer Package Diagrams from Code
As mentioned earlier, a great use for a UML CASE tool is to reverse-engineer the source code and generate a package diagram automatically. This practice is enhanced if you use the recommended naming conventions in code. For example, if you include the partial name ".ui." in all packages for the UI layer, then the UML CASE tool will automatically group and nest sub-packages under a "ui" package, and you can see the layered architecture in both code and package diagram.
Definition: Domain Layer vs. Application Logic Layer; Domain Objects
This section describes a simple but key concept in OO design! |
How do we design the application logic with objects?
We could create one class called XYZ and put all the methods, for all the required logic, in that one class. It could technically work (though be a nightmare to understand and maintain), but it isn't the recommended approach in the spirit of OO thinking.So, what is the recommended approach? Answer: To create software objects with names and information similar to the real-world domain, and assign application logic responsibilities to them. For example, in the real world of POS, there are sales and payments. So, in software, we create a Sale and Payment class, and give them application logic responsibilities. This kind of software object is called a domain object . It represents a thing in the problem domain space, and has related application or business logic, for example, a Sale object being able to calculate its total.Designing objects this way leads to the application logic layer being more accurately called the domain layer of the architecturethe layer that contains domain objects to handle application logic work.
What's the Relationship Between the Domain Layer and Domain Model?
This is another key point: There's a relationship between the domain model and the domain layer. We look to the domain model (which is a visualization of noteworthy domain concepts) for inspiration for the names of classes in the domain layer. See Figure 13.5.
Figure 13.5. Domain layer and domain model relationship.
[View full size image]
Definition: Tiers, Layers, and Partitions
The original notion of a tier in architecture was a logical layer, not a physical node, but the word has become widely used to mean a physical processing node (or cluster of nodes), such as the "client tier" (the client computer). This book will avoid the term for clarity, but bear this in mind when reading architecture literature.The layers of an architecture are said to represent the vertical slices, while partitions represent a horizontal division of relatively parallel subsystems of a layer. For example, the Technical Services layer may be divided into partitions such as Security and Reporting (Figure 13.6).
Figure 13.6. Layers and partitions.
Guideline: Don't Show External Resources as the Bottom Layer
Most systems rely on external resources or services, such as a MySQL inventory database and a Novell LDAP naming and directory service. These are physical implementation components, not a layer in the logical architecture.Showing external resources such as a particular database in a layer "below" the Foundation layer (for example) mixes up the logical view and the deployment views of the architecture.Rather, in terms of the logical architecture and its layers, access to a particular set of persistent data (such as inventory data) can be viewed as a sub-domain of the Domain Layerthe Inventory sub-domain. And the general services that provide access to databases may be viewed as a Technical Service partitionthe Persistence service. See Figure 13.7.
Figure 13.7. Mixing views of the architecture.
[View full size image]