Mitigating the "Ball of mud" in your products/services with Domain Driven Design.
Follow the talk from with your smartphone:
Example repository:
I can't teach anything. I can only make you think.- Socrates
Can't see the forest for the trees- John Heywood
Production is the happiest place in the world.- Josh Long
it’s not the domain expert's knowledge that goes into production, it’s the developer's assumption of that knowledge.- Alberto Brandolini
Note: DDD is not the unique way to develop software for production.
Engineering in Industrial Organization (M.S.) @ ICAI Technical Architect & Innovation Estratego @ VASS Associate Professor @ ICAI STEAM Teacher @ Space Math @juanantoniobm | Github |
Bachelor degree in Management Information Systems @ HE VINCI Freelance Senior Software Engineer @LeXavTwit | Github |
The talk will try explain some ideas from:
The talk doesn´t cover the following topics ATM:
What is a Software architecture?
Architecture is about the important stuff. Whatever that is.
Timeline
Or maybe your design suffer with: Anemic Domain Model
Microservices with Spring Cloud Kubernetes
Microservices running in a multi cloud environments
Have that designs an enough detail to create a backlog to start the implementation phase?
Did you read a book about DDD previously?
Domain-driven design (DDD) is a software design that focuses on understanding domain experts and building the software as a model of its domain.
One concept is that the structure and language of software code (class names, class methods, class variables) should match the business domain.
Source: https://en.wikipedia.org/wiki/Domain-driven_designIn any moment :)
Depends of the DDD Skills 🤷
You could use DDD:
Strategic Design is a set of principles and patterns for maintaining model integrity, distilling the Business Domain Model, and working with multiple models. Strategic design is very useful to divide a large and complex business problem into multiple chunks with clear boundaries and specific responsibilities and build a high-level software design topology.
Tactical Design is a set of design patterns and building blocks that you can use to abstract low and mid-level components of the software. Tactical patterns are very hands-on addressing programming code and deal with classes and modules. The purpose of tactical design is to refine the result of Strategic patterns applied to a stage where it can be converted into a working code.
DDD Vocabulary
Define the Ubiquitous Language, the Bounded contexts and the Context maps
Concepts:
A language structured around the domain model and used by all team members within a bounded context to connect all the activities of the team with the software.
What happened with meters & miles?
Source: https://www.simscale.com/blog/2017/12/nasa-mars-climate-orbiter-metric/A description of a boundary (typically a subsystem, or the work of a particular team) within which a particular model is defined and applicable.
Domains & Subdomains
Domains & Subdomains
Domains & Subdomains
Domains & Subdomains
Context Maps describe the contact between bounded contexts and teams with a collection of patterns. There are nine context map patterns and three different team relationships.
Technical integration patterns between Bounded Contexts:
Organizational patterns and integration that describe the types of relationship between Bonded Contexts:
This pattern addresses the case where the power is skewed toward the consumers. The supplier is interested in protecting its consumers and providing the best service possible.
To protect the consumers from changes in its implementation, the upstream supplier decouples its implementation model from the public interface.
Common language for the translation between the models that are going to interact. For example JSON or XML. Usually associated with OHS. The advantage of using REST services is that in each request the PL can be specified by configuring the desired content type.
A well documented language shared between bounded contexts
This is another upstream/downstream relationship at a lower level, where the downstream bounded context implements a layer between itself and the upstream.
This layer is responsible for translating the objects given by the upstream into its own models. This approach will guarantee the integrity of the downstream bounded context and keeps it completely ignorant of any foreign concepts.
This approach is generally useful for integrating new features to some existing legacy software, where you can treat the existing legacy software as a black box bounded context and create an ACL for the new feature.
The Anticorruption Layer translate one model to another one
2 or more bounded contexts can share a common model. In design terms, the Ubiquitous Language of this shared part is common both all relevent teams. In code terms, you may have a shared library, or a service. This is generally a small codebase but difficult to maintain as its related bounded contexts develop, as the teams will tend to go on separate ways as their own bounded contexts evolve.
Shared kernel is a subset of a domain model that two or more teams share:
This relationship describes the relationship of 2 bounded context, where the upstream has no interest in supporting the downstream for whatever reason. Instead, the downstream must conform to whatever the upstream provides. This can happen when integrating a new feature with a large, existing solution that is well established; or using a set of APIs, where the downstream is not the sole customer.
The conformist slavishly adhreres to the upstream model:
This approach puts 2 bounded contexts into an upstream and downstream, where the upstream is the supplier, and has to try and meet the expectations of the customer (downstream). But the final decision of what the customer gets comes from the supplier. This typically works in an autonomous environment within the same organisation, or if the customer is the sole client of the supplier.
A customer-supplier development gives the downstream team some influence:
Partnership is about cooperative relationships between teams:
Structural Refactorings:
AR-2: Split Bounded Context by Features
Description | Input | Output |
Splits a bounded context by grouping those aggregates together into one bounded context which are used by the same use case(s) and/or user stories (features). | 1 BC | n BC |
AR-3: Split Bounded Context by Owner
Description | Input | Output |
Splits a bounded context by grouping those aggregates together into one bounded context which belong to the same team. | 1 BC | n BC |
AR-7: Merge Bounded Contexts
Description | Input | Output |
Merges two bounded contexts together. The result is one bounded context containing all the aggregates of the two input bounded contexts. | 2 BC | 1 BC |
AR-8: Extract Shared Kernel
Description | Input | Output |
Extracts a new bounded context for the common model parts of the Shared Kernel and establishes two upstream-downstream relationship between the new and the existing Bounded Contexts. | 1 Shared Kernel relationship | 1 New Bounded Context and 2 new upstream-downstream relationships |
AR-9: Suspend Partnership
Description | Input | Output |
Suspends a Partnership relationship and replaces it with another structure how the two Bounded Context can depend on each other. The AR provides three strategies to suspend the partnership. | 1 Partnership relationship | Depends on the selected mode |
Relationship Refactorings:
AR-10: Change Shared Kernel to Partnership
Description | Input | Output |
Changes the type of a Shared Kernel relationship to a Partnership relationship. | Shared Kernel relationship | Partnership relationship |
AR-11: Change Partnership to Shared Kernel
Description | Input | Output |
Changes the type of a Partnership relationship to a Shared Kernel relationship. | Partnership relationship | Shared Kernel relationship |
Techniques:
Tool:
Process:
Event-Storming
Event-Storming
Event storming is a workshop-based method to quickly find out what is happening in the domain. The result is expressed in sticky notes on a wide wall. The business process is "stormed out" as a series of domain events which are denoted as orange stickies.
Event-Storming
Event storming can be used as a means for business process modeling and requirements engineering. The basic idea is to bring together software developers and domain experts and learn from each other.
Example: Discovering Domain Events
Example: Discovering Commands & Queries
Example: Discovering Invariants
Example: Discovering the bounded contexts
Bounded Context Canvas
The Bounded Context Canvas is a collaborative tool for designing and documenting the design of a single bounded context.
A bounded context is a sub-system in a software architecture aligned to a part of your domain.
Source: https://github.com/ddd-crew/bounded-context-canvasBounded Context Canvas
Context mapper
Context Mapper is a modular and extensible modeling framework for Domain-driven Design (DDD) and its strategic patterns. The core component provides a DSL to create context maps featuring these DDD patterns.
Context mapper
Context mapper
Context mapper
Context mapper
Context mapper
Domain-Driven Design Starter Modelling Process
Tactical DDD is when you define your domain models with more precision.
Concepts:
Value Object
A value object is a small object that represents a simple entity whose equality is not based on identity: i.e. two value objects are equal when they have the same value, not necessarily being the same object.
Examples: Objects representing an amount of money or a date range
Entity
In a data model context, describes the structure of data regardless of the stored form.
Agreggate Root
An Agreggate is a cluster of associated objects that we treat as a unit.
Source: Domain-Driven Design, Eric EvansAgreggate Root
Aggregates are the basic element of transfer of data storage - you request to load or save whole aggregates.
Source: https://martinfowler.com/bliki/DDD_Aggregate.htmlAgreggate Root
An aggregate will have one of its component objects be the aggregate root. Any references from outside the aggregate should only go to the aggregate root. The root can thus ensure the integrity of the aggregate as a whole.
Source: https://martinfowler.com/bliki/DDD_Aggregate.htmlRepositories
Query access to aggregates expressed in the ubiquitous language
For each type of aggregate that needs global access, create a service that can provide the collection of all objects of that aggregate’s root type. Provide methods to add and remove objects, which will encapsulate the actual insertion or removal of data in the data store. Provide methods that select objects based on criteria meaningful to domain experts.
Example:
Source: https://khalilstemmler.com/articles/typescript-domain-driven-design/aggregate-design-persistence/Example:
Source: https://kalele.io/modeling-aggregates-with-ddd-and-entity-framework/A domain event is a full-fledged part of the domain model, a representation of something that happened in the domain. Ignore irrelevant domain activity while making explicit the events that the domain experts want to track or be notified of, or which are associated with state change in the other model objects.
Patterns:
Libraries:
The Hexagonal-like Architectures:
The Onion Architecture is an Architectural Pattern that enables maintainable and evolutionary enterprise systems.
Source: https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/Domain layer:
Application layer:
Infrastructure layer:
jmolecules-onion-architecture: Layers:
Source: https://speakerdeck.com/kiyotakeshi69/spring-fest-2020-express-ddd-using-jpa-x-jmoleculesAdvantages:
Advantages:
How to ensure that your team apply Onion architecture in an effective way?
ArchUnit is a free, simple and extensible library for checking the architecture of your Java code using any plain Java unit test framework.
Website: https://www.archunit.org/
< dependency>
< groupId>com.tngtech.archunit< /groupId>
< artifactId>archunit< /artifactId>
< version>${archunit.version}< /version>
< scope>test< /scope>
< /dependency>
< dependency>
< groupId>com.tngtech.archunit< /groupId>
< artifactId>archunit-junit5-engine< /artifactId>
< version>${archunit.version}< /version>
< /dependency>
< dependency>
< groupId>com.tngtech.archunit< /groupId>
< artifactId>archunit-junit5< /artifactId>
< version>${archunit.version}< /version>
< /dependency>
Maven:
https://mvnrepository.com/artifact/com.tngtech.archunit
Example:
@AnalyzeClasses(
packages = "com.ddd.balance",
importOptions = {ImportOption.DoNotIncludeTests.class})
public class BalanceArchitectureOnionTest {
@ArchTest
static final ArchRule follow_onion_architecture_structure =
onionArchitecture()
.domainModels("..domain.model..")
.domainServices("..domain.service..")
.applicationServices("..application..")
.adapter("rest", "..infrastructure.rest..");
}
You can apply TDD at architectural level with ArchUnit
Spring Data JDBC, part of the larger Spring Data family, makes it easy to implement JDBC based repositories.
Library: https://spring.io/projects/spring-data-jdbcSpring Data repositories are inspired by the repository as described in the book Domain Driven Design by Eric Evans. One consequence of this is that you should have a repository per Aggregate Root. Aggregate Root is another concept from the same book and describes an entity which controls the lifecycle of other entities which together are an Aggregate. An Aggregate is a subset of your model which is consistent between method calls to your Aggregate Root.
Architectural abstractions for Java.
Maven dependencies:
< dependency>
< groupId>org.jmolecules< /groupId>
< artifactId>jmolecules-ddd< /artifactId>
< version>${jmolecules.version}< /version>
< /dependency>
< dependency>
< groupId>org.jmolecules< /groupId>
< artifactId>jmolecules-onion-architecture< /artifactId>
< version>${jmolecules.version}< /version>
< /dependency>
Maven: https://mvnrepository.com/artifact/org.jmolecules
Goals:
The library is organized in the following modules:
jmolecules-ddd:
Github: https://github.com/xmolecules/jmolecules/tree/main/jmolecules-dddjmolecules-ddd: Annotations to define Domain-Driven Design building blocks.
Github: https://github.com/xmolecules/jmolecules/tree/main/jmolecules-dddjmolecules-ddd:
jmolecules-architecture:
Github: https://github.com/xmolecules/jmolecules/tree/main/jmolecules-architecture
jmolecules-onion-architecture:
jmolecules-onion-architecture:
jmolecules-onion-architecture:
Source: https://speakerdeck.com/kiyotakeshi69/spring-fest-2020-express-ddd-using-jpa-x-jmoleculesjmolecules-onion-architecture: Layers:
Source: https://speakerdeck.com/kiyotakeshi69/spring-fest-2020-express-ddd-using-jpa-x-jmoleculesThanks