I intend to break this out into more concrete and describable sections.
As a general guideline
– Bounded Context(Subdomains) Microservice
Anti-Pattern = multiple bounded contexts in 1 service. Monolith.
– Each Subdomain has its own ubiquitous language and model.
– The domain model should describe the software. Not the other way around.
Bounded context (subdomain)
– The meaning of the same word may vary between bounded contexts
– Combination of the model and the ubiquitous language.
– Each subdomain has its own ubiquitous language
– Don’t use the same class across all different bounded contexts.
For example, Customer may point to the same person but different bounded
contexts won’t care to know the same details about a given customer. For example, the shipping department could not care less about the age/birthdate of “Sally” but the payment department will care about Sally’s age/birthdate. Each bounded context, Payment and Shipping, will keep track of its own attributes for Sally. Payment and Shipping would be their own microservices with a Customer entity that contains different information about Sally with respect to the bounded context/subdomain. The details of Sally will change depending on what part of the business is referring to Sally.
When determining the bounded contexts
– Different areas of the domains are handled by different groups of people. This should be an indicator.
– Job classifications within organizational subgroupings could be an indicator.
= A clear grouping of business processes and workflows
– Uniquitous language alterations. If the meaning of certain terms change, that should be an indicator of a different context.
– Identifying events and interactions that make up a specific workflow in a bounded context.
– We identify activities and then group those to find the system boundaries.
– See https://en.wikipedia.org/wiki/Event_storming
– Translate domain concepts that are unique from one context and not compatible to another context.
– They will prevent bounded contexts from penetrating and imposing on one another. Some say “prevent leaking to each other”.
– By using a anti-corruption layer, the bounded context of the domain is protected and unchanged
– Think of it as an adapter or “decorator” around the bounded context that’s there to protect it and ensure that it remains “safe” and “unchanged”.
– Prevents a bounded context from being “co-dependent” on other bounded contexts (“I’ll take the hit and change myself (even if it’s not for the better) so that others can do as they please. So my bounded context will have terms/meanings from other bounded context that will impact me in a negative way”
– A concept is called one thing in context A but another thing in context B.
– A set of units from context A will need to be converted a set of units in context B.
– It could translate an entity representation (ie, an Account) from one bounded context to another.
Account is protected with an adapter.
– Best to represent it as an abstract interface that is implemented
Anti-Corruption Layer(s) for Legacy Systems
– The legacy system may be sloppy/messy or confusing
– The ACL will protect you from that by preventing your domain from dealing with that.
– If it makes it easier, you can introduce an ACL for both the legacy and domain context
– Recommendations – Anytime a microservice/bounded context has to communicate to another external service, it should always do so thru an anti-corruption layer to keep the details of that external service out of the microservice/bounded context.
– for the legacy system, you can create/expose an API that will hide the mess of how it communicates to the legacy system. You call the api.
– A way to visualize the relationships between the bounded contexts in your system.
Activities in a Domain leading into CQRS
– Commands (has not happened yet)
* Request to do something (has not happened yet and can be voided)
* Causes the state of the domain to change.
* (Place order, etc..)
* Can be rejected
– Events (has already happened, always worded as past tense)
* Type of activity that occurs in the domain
* Can never be rejected because it happened
* Records a change to the state of the domain
* An order was placed, the customers last name was changed, etc..
– Domain Events should be raised by the aggregate in which it happened.
– Query (another type of activity in a domain)
* Request for info about the domain
* A response is always expected
* The request to query happens usually to a specific destination (ie, Microservice) that will make the query on your behalf
* Does not change the state of the domain
* Get Customer Payment history, check if order was placed, etc..
– Command and Query data should be placed into seperate data stores for seperation of concerns and performance. And for performance, you can create read-replicas for your Query stores. Think of your Query stores like you would a materialied view.
– Commands, Events and Queries are the messages in a Reactive system which basically form the API for a bounded context or microservice. Done asynchronously.
– A bounded context API is composed of Commands, Events and Queries.
– Events are always fact (happened in the past).. Commands are requests that ultimately turn into fact.
Commands/Queries and Events Best Practices
– It’s best to define Commands that are intent revealing meaning that you can tell from the command what we’re wanting to do.
– Events are often the result of a command. Commands request to change the state of a domain but events actually record that state change.
– Queries can be done to obtain information about the state of the domain. A query is issued in the form of a request for information, but it never changes the state of the domain. Queries are idempotent.
– Defined by the attributes
– objects are = if their attributes are the same.
– Immutable because changing the value of any field results in a different object.
– They have no unique identity otherwise.
– they CAN contain business logic (rich)
– Messages are usually implemented as Value objects
– Defined by an id or key which is unique
– Attributes can change but not the identity
– Persisted via repository
– Can contain business logic
– Specific type of entity and is source of truth
– Collection of domain objects bound to a root entity
– All objects are treated as a single unit
Name Position Experience
– Baseball Player is the aggregate root
– Access to Name/Position and Experience must go thru “Baseball Player”
– Transactions should NOT span multiple aggregate roots
– Aggregates can access other aggregates but only thru the aggregate roots of the other aggregates.
Determining Aggregate roots
– Aggregate root is an entity in a bounded context that aggregates other objects.
– It is never a part of another aggregate.
– Always entities. Can never be a value object.
– Can be different from one context to the next
– Some contexts can have many aggregate roots
Is the entity involved in that bounded context?
If you delete the entity, does it require you to delete the entities?
Will a single transaction span multiple aggregate roots? A transaction should NOT span multiple aggregate roots.
Services (no, not the Kubernetes services 🙂 )
– Houses business logic that does not fit within an entity or value object.
– You can abstract away an anti-corruption layer
– Should be thin layer over a piece of business logic
– Examples, a passing hashword service, en email service, a string utility service, a currency conversion service, etc..
– Needs to be stateless
If we need to put state in a Service we should probably find/create an entity or value object to contain the state.
– Abstract away the logic of creating a domain object.
– In CRUD based apps, they are the “C” part.
– The “RUD” in CRUD. Read/Update/Delete
– Abstraction layer over persistence mechanisms (DB, files, API’s, etc..). Does not always mean a database.
– Alternative to n-tiered architecture where DDD is involved
– Isolates your domain from your infrastructure
– The domain should NOT know about any of the following:
Infrastructure, Adapters, API, Databases/persistance, Ports
Your domain can then be portable.
– Domain is at the center.
– Ports are an API for infrastructure components to interface with the domain
– API is the “ports layer”
– The infrastructure layer wraps the API layer and adapts outgoing/inbound calls to the API layer.
A good course to take