Building Block View
Building Block View
A bounded domain is the key building block for a modular monolith architecture approach. The ERP application is consisting of multiple bounded domains.
The same approach should be used for a distributed microservice architecture.
Each bounded domain is a self-contained module that encapsulates the business logic and data for a specific domain. Persistence shall be handled per bounded domain. Ideally, the domain model should be designed to be independent of the persistence technology.
We assume the reader is familiar with the concepts of domain-driven design.
The key abstractions are described in the following diagram. The CRM
bounded domain is used as an example.
See also the JavaDoc Domain Model.
Facets of a Bounded Domain
A bounded domain must provide the following abstractions:
-
A bounded domain class as entry point to the domain. Each bounded domain has a unique name.
-
A realm of the domain model and provides the factory and persistence functionality as described in DDD. All aggregates of the domain are created and persisted using the realm.
-
A port describing the services provided by the domain. An adapter class and other helper classes are used to implement the port contract.
-
An optional business logic implementing the business rules of the domain.
The following abstractions are optional:
-
A user interface to interact with the domain.
-
A REST service to expose the domain functionality to other modules or external clients.
-
Domain events published by the domain.
-
Domain commands to interact with the domain.
-
Domain queries to retrieve information from the domain.
Domain Model
The classes are declared in the package net.erp.DOMAIN.domain
.
Internal Representation
The entities and aggregates of the domain are modeled as Java plain old objects (POJOs). Value objects are port of aggregates. They are immutable and are used to represent data in a graph of objects. Ideally, they should be implemented as Java records to reflect their immutability.
An entity shall have an identifier that uniquely identifies the entity within the domain. Optionally, it can have an internal object identifier used to identify the entity within the domain model.
An entity implements the HasId
interface and optionally the HasOid
interface.
An entity can also have a human-readable name used to display the entity in the user interface.
Such entities implement the HasName
interface.
External Representation
Our domains provide an external representation of the domain model instances. This representation is used to transfer the domain model instances between the domain and the external world. The mechanism provides import, export and archiving functionality.
The preferred export format is TSV. Most entities map logically to a row in a TSV file.
For complex structures, we use JSON. An example is the export of a complete invoice.
Instances edited outside the domain are often encoded in YAML. An example is the documentation for the monthly activities of a consultant in a services company.
The |
Domain Services
The classes are declared in the package net.erp.DOMAIN.service
.
The implementation of the service is located in the services and port packages.
The Port
interface requires the import, export and clear functionality.
Domain Interfaces
-
REST Services are defined in the package
net.erp.DOMAIN.rest
. -
Events are defined in the package
net.erp.DOMAIN.events
. -
Commands are defined in the package
net.erp.DOMAIN.commands
. -
Queries are defined in the package
net.erp.DOMAIN.queries
.
The number of commands and queries is an indicator of the coupling between the bounded domains. Try to minimize the number of commands and queries.
REST services are an alternative path to realize a user interface for a bounded domain instead of a more traditional {ref-vaadin} user interface. Events are the preferred way to communicate between bounded domains. They are part of the domain-driven design approach.
User Interface
The classes are declared in the package 'net.erp.DOMAIN.ui'.
Bounded Domain Application Services
-
User Interface for Bounded Domain Micro Frontends
-
Authentication and Authorization
-
Audit Log
-
Event Publishing and Subscribing
-
Tenancy
A bounded domain can provide a REST interface to expose its functionality to other modules or external clients. The definition and documentation of the REST services are part of the bounded domain and should be packaged with the domain artifacts.
THe REST services are documented using the OpenAPI specification, and the documentation is displayed using Swagger UI.
We have one REST services specification per bounded domain. The Swagger UI shall be used to publish the REST services for all bounded domains part of the modular monolith application. The application uses the Javalin framework to implement the REST services. OpenAPI and Swagger plugins are used to document and publish the documentation of the REST services. |
References
-
E. Evans, Domain-driven design. Addison-Wesley, 2004 [Online]. Available: https://www.amazon.com/dp/0321125215
-
V. Vernon, Domain-Driven Design Distilled. Addison-Wesley Professional, 2016 [Online]. Available: https://www.amazon.com/dp/B01JJSGE5S/
-
V. Vernon, Implementing Domain driven Design. Addison-Wesley Professional, 2012 [Online]. Available: https://www.amazon.com/dp/B00BCLEBN8
-
M. C. Feathers, Working Effectively with Legacy Code. Prentice Hall, 2004 [Online]. Available: https://www.amazon.com/dp/0131177052
-
J. Kerievsky, Refactoring to Patterns. Addison-Wesley Professional, 2004 [Online]. Available: https://www.amazon.com/dp/0321213351
-
E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns. Addison-Wesley Professional, 1995 [Online]. Available: https://www.amazon.com/dp/B000SEIBB8
-
S. Newman, Building Microservices. O’Reilly Media, Incorporated, 2020 [Online]. Available: https://www.amazon.com/dp/B09B5L4NVT
-
N. Ford, Software architecture, First edition. Cambridge, Massachusetts: The MIT Press, 2021 [Online]. Available: https://www.amazon.com//dp/1492086894