Notes from Vaughn Vernon book Implementing Domain-Driven Design
Note that I have read the "Blue Book" (Eric Evans' Domain-Driven Design) previously, so mainly I haven't repeated things from that book.
Foreword and Preface
Foreword by Eric Evans
- Nine years after my book (...) was published, there's actually a lot to say about DDD that is new, and there are new ways to talk about the fundamentals.
Preface
- Sometimes DDD is first embraced as a technical tool set (referred to as DDD-Lite by some).
- If there is a single invention Evans delivers to the software development community, it is the Ubiquitous language.
Chapter 1: Getting Started with DDD
- DDD isn't first and foremost about technologies. In its most central principles, it's about discussion, listening, understanding, discovery and business value, all in an effort to centralize knowledge.
- If you're capable of understanding the business ..., you can at a minimum participate on discovery process for a Ubiquitous Language.
- How DDD helps?
- 1: DDD brings domain experts and software developers together in order to develop software that reflects the mental model of the business experts
- Instead of "most realistic", thrive to deliver a model that is most useful for the business.
- 2: DDD addresses the strategic initiatives of the business
- 3: DDD has tactical design modeling tools to analyze and develop software
- 1: DDD brings domain experts and software developers together in order to develop software that reflects the mental model of the business experts
- Use DDD to simplify, not to complicate!
- Business value for DDD
- The organizations gains a useful model of its domain
- A refined, precise definition and understanding of the business is developed
- ...
Chapter 2: Domains, Subdomains, and Bounded Contexts
These things are "Strategic design".
- In broad sense, a domain is what an organization does and the world it does it in.
- Bounded Context is chiefly a linguistic boundary.
- Some projects fall into the trap of attempting to create an all-inclusive model. (Which is a pitfall)
- Same term might have very different meaning in different bounded contexts.
- Bounded Context often marks off a system, an application or a business service.
- With persistence, a database schema will live inside the boundary.
- How big should it be? A bounded context should be as big as it needs to be in order to fully express it's complete Ubiquitous Language.
- Often a single team for a single bounded context works pretty well
Division between different parts of the business domain:
- Core Domain is a part that is of primary importance to the success of the organization.
- Supporting Subdomain: Bounded Context that models some aspect of the business that is essential, yet not Core.
- Generic Subdomain: Subdomain that captures nothing special to the business, yet is required for the overall business solution.
Problem space vs solution space. (This chapter deals mainly on problem space assessment)
Chapter 3: Context Maps
This chapter focuses on the solution space assessment.
- Context map shows the mappings between Bounded Contexts.
- By drawing a Context Map, you will be forced to think about your relationships with all other projects / Contexts you depend on.
- A Context Map should capture the existing terrain, not the imagined future. First focus on the current situation and where you are. After that determine where to go next.
- (Going through the patterns in Evans' "Strategic Design" part)
- We might have state dependent from another system.
- Instead of caching whole dependent objects, we create local domain objects translated from the foreign model.
Chapter 4: Architecture
- The goal is to use just the right choices and combinations of architecture and architecture patterns.
Layers
- Domain layer is a separate layer.
- As a detail, separate Application Services from Domain Services.
- Potential way: Dependency Inversion Principle (DIP) (See The Dependency Inversion Principle article, linked from Clean Coder / Articles)
Hexagonal / Ports and Adapters
- See Alistair Cockburn's Hexagonal Architecture article.
- Ports and Adapters name also used.
- Instead of "Front end" and "Back end" Hexagonal looks are "Inside" and "Outside"
- Domain Model furthest inside.
- Normally we don't implement the ports ourselves. (Most of that comes from a framework, container etc.)
- For remainder of the chapter, assume that Ports and Adapters approach is used.
Service-Oriented
REST
- Two alternatives for combining DDD and RESTful HTTP
- 1: Create a separate Bounded Context for the system's interface layer
- 2: Reflect domain objects in resources
- As a problem, any changes to objects structure are immediately reflected in remote interfaces.
CQRS
From Wikipedia:
... every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer. More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.
Examining Areas of CQRS (see overview image)
- Query Processor takes queries from client.
- Query Model (aka Read Model)
- Command Processors
- Command Model (aka Write Model)
- Event Subscriber updates the Query Model
- Synchronous or asynchronous? Depends on the normal load of the system, where the query model DB is stored, data consistency constraints and performance requirements.
- If Query model is Eventually Consistent, it needs to be considered in the UI. Different approaches:
- As a trick, show the data UI in the UI as the command would already be successfully executed.
- Show date and time from the query model that the user is currently viewing.
Summa summarum, CQRS introduces a number of competing forces
Event-Driven Architecture
- Pipes and Filters
- Long-Running processes (aka Sagas)
- Problem of knowing which process was ending etc?
- One way is to assign a unique Process identity.
- Store an aggregate-like state object tracking process state & completion.
- Problem of knowing which process was ending etc?
Event Sourcing
- Sometimes the business cares about tracking changes that occur to the objects in the domain model.
- -> Store history of everything that's happened.
- To avoid playback of many events, we can apply optimization with (Aggregate) state snapshots.
Data Fabric and Grid-Based Distributed Computing
Chapter 5: Entities
- Developers have tendency to focus on data rather than the domain.
- One reason being many approaches placing importance on the database.
- Instead of designing domain concepts with rich behavior, we might think primarily about the attributes
- Domain concept is designed as an Entity when we care about its individuality.
- Distinguishing it from all other objects in a system is a mandatory constraint.
- Some strategies for identity creation:
- User provides one or more unique values as input to the application.
- Application internally generates an identity using some algorithm that ensures uniqueness
- The application relies on a persistence store, e.g. database.
- Unique identity is already determined by another Bounded Context.
- Identity generation timing can be done either
- Early (identity is generated before the Entity is persisted. As part of object's construction.
- Late (identity is generated when the Entity is persisted). As part of object's persistence.
- Surrogate identity
- Some tools (e.g. ORMs) want to deal with Object identity on their own terms.
- -> Two identities:
- One designed for the domain model
- One for the tool, known as a surrogate identity
- It's best to hide the surrogate attribute from the outside world.
- Entity validation - can be done at three levels
- Validating single attributes/properties (not null, certain values, certain format, ...)
- Referred to as defensive programming.
- Validating Whole Objects
- Validations that need to have access to the state of the entire object.
- Specification/Strategy pattern might be used.
- Validating Object Compositions
- Often at Aggregate level.
- Validating single attributes/properties (not null, certain values, certain format, ...)
Chapter 6: Value Objects
- Evans: When you care only about the attributes of an element of the model, classify it as a Value Object.
- Treat the Value Object is immutable.
- Don't give it any identity.
- We should thrive to model using Value Objects instead of Entities whenever possible.
- Make sure you address the Ubiquitous Language.
- Value objects usually possess most of these characteristics:
- It measures, quantifies or describes a thing in the domain.
- It can be maintained as immutable.
- It models a conceptual whole.
- Parent reference to a Value Object is not just an attribute. Rather, it is a property of the containing parent object/thing...
- It is completely replaceable.
- It can be compared with others using Value equality.
- It supplies its collaborators with Side-Effect-Free Behavior.
- Standard Types Expressed as Values.
- E.g. Java enums can be used as State object
- Vernon prefers naming
valuePercentage()
overgetValuePercentage()
getValuePercentage()
is a technical statementvaluePercentage()
is a fluent human-readable language expression.
- If at all possible, design your data model for the sake of your domain model, not vice versa.
ORM things discussed:
- ORM and Single Value Objects
- Often Value Object is denormalized into its parent Entity's DB row.
- ORM and Many values serialized into a single column
- e.g. List/Set
- Potential drawbacks to consider
- Column width
- Querying - Individual value elements not queryable.
- Requires custom user type
- ORM and Many values backed by a database entity
- We can use a Layer Supertype
- ORM and Many values backed by a join table
- Downsides
- join needed
- nulls not supported
- value type mapped may itself not contain a collection
- Generally to be avoided
- Downsides
- ORM and Enum-as-State Objects
- Requires custom user type.
Chapter 7: Services
- A Service in the domain is a stateless operation that fulfills a domain-specific task.
- Often the best indication for service being needed is when the operation you need to perform doesn't fit either to an Aggregate of a Value Object.
- Don't confuse a Domain Service with an Application Service.
- We don't want to house business logic in an Application Service.
- Application Service would normally be a client of a Domain Service.
- Transactions and security should be addressed as application concerns in Application Services, not in Domain services.
- When would an operation not belong on an Entity of Value Object? You can use a Domain Service to
- Perform a significant business process.
- Transform a domain object from one composition to another.
- Calculate a Value requiring input from more than one domain object.
- Make sure you need a service.
- Avoid Anemic Domain Model
- Is Separated Interface necessary?
- May be a more a matter of style in cases where the service is always domain specific and will not have technical implementation or multiple implementations.
Chapter 8: Domain Events
- Contemporary definition for Domain Events: Something happened that domain experts care about.
- Although domain experts might not initially be aware of the need for every kind of Event, they should understand the reasons for them, as they are included in discussions.
- When Events are delivered to interesting parties (either local of foreign systems), they are generally used to facilitate eventual consistency
- This is purposeful and by design.
- Can eliminate the need for two-phase commits & support of the rules of Aggregates.
- Does every Aggregate command result in an Event?
- It is important also to know when to disregard happenings in the domain that experts or the business, as a whole don't care about.
- Because of technical implementation aspects it is possible that Event will be more prolific than domain experts care about.
- Modeling Events
- Name Events and their properties according to the Ubiquitous Language.
- Typical naming
- Command operation:
BacklogItem#commitTo(Sprint sprint)
- Event outcome:
BacklogItemCommitted
- Command operation:
- At times Events are created by direct request from clients and don't fit a single Aggregate.
- When that happens, the Event can be modeled as an Aggregate and retained in its own Repository.
- Identity
- At times it may be necessary to distinguish Events on from another, but the need may be rare.
- Unique identity may be necessary when Events are published outside the local Bounded Context, forwarded by messaging infrastructure.
- Publishing Events
- Publisher
- Typical use of Domain Events is when an Aggregate creates an Event and publishes it.
- The publisher resides in a Module of the model, but it doesn't model an aspect of the domain.
- Subscribers
- Generally Application Services subscribe to Domain Events. Sometimes Domain Services.
- One thing the subscriber should not do is get another Aggregate instance and execute modifying command on it.
- This would violate the modify-single-aggregate-instance-in-single-transaction rule of thumb.
- Events are domain-wide concept, not just a concept in a single Bounded Context
- Events are published to any number of Bounded Contexts of other Subdomains.
- Publisher
- Spreading the News to Remote Bounded Contexts
- Some form of messaging takes place.
- Commitment to Eventual consistency is needed
- The changes in one model that influence one or more other models will not be fully consistent for some period of time.
- (At least) two mechanisms must be consistent with each other:
- Persistence store for the domain model
- Persistence store backing the messaging infrastructure
- Autonomous Services and Systems
- A high degree of independency from other systems is achieved by avoiding in-band RPCs.
- Use asynchronous messaging to achieve a greater degree of independence between systems - autonomy.
- Latency Tolerances
- It may surprise developers to learn that most times, several seconds, minutes, hours or even days between consistent states might be completely tolerable.
- Not true for all cases.
- We must not assume that near-consistent time frames would be always imperative for any given domain.
- Event Store
- Consider what you could to if you were to store a discrete event for every model command:
- Use the Event Store as a queue for publishing all Domain Events through a messaging infrastructure.
- Use the same Event Store to feed REST-based Event notifications to polling clients
- Logically the same as point 1, but different in actual us.
- Examine a historical record of the result of every command ever executed on the model.
- Use the data in business analytics (trending, forecasting etc.)
- Use the Events to reconstitute each Aggregate instance when it is retrieved from its Repository.
- Undo blocks of changes to an Aggregate
- Consider what you could to if you were to store a discrete event for every model command:
- Architectural Styles for Forwarding Stored Events
- Publishing Notifications as RESTful Resources
- (+) If potentially many clients can go to a single well-known URI for the same set of notifications, the RESTful approach works well.
- (-) If one or few consumers are required to pull from multiple producers for resources in order to get a single set of tasks to performed in a specific sequence, the RESTful approach won't probably work too well.
- Publishing Notifications through Messaging Middleware
- Publishing Notifications as RESTful Resources
- Event De-Duplication
- One way to deal with the possibility of duplicate message delivery is for subscriber model operation to be idempotent.
- When idempotency is not a viable option, you can instead design the subscriber/receiver itself to be idempotent.
- Messaging product might support this off-the-shelf.
Chapter 9: Modules
- In a DDD context, Modules in your model serve as named containers for domain classes that are highly cohesive with one another.
- Simple Do/Don't Rules for Module Design
- Do design Modules to fit modeling concepts.
- Do name Modules per the Ubiquitous Language.
- Don't create Modules mechanically according to a general component type or pattern being used.
- Do design loosely coupled Modules.
- Do strive for acyclic dependencies on peer Modules when coupling is necessary.
- Do relax the rules a bit between child and parent Modules.
- Don't make Modules as a static concept of the model, but allow them to be molded along with the objects that they organize.
- Module naming conventions
- One approach is to divide model and services, e.g.
com.foobar.identityaccess.domain.model
com.foobar.identityaccess.domain.service
com.foobar.collabaration.domain.model
com.foobar.collabaration.domain.service
- Fits well with that we're designing and implementing a model of a domain, not domain.
- Another approach is to drop
model
/service
divisioncom.foobar.collabaration.domain.conceptname
- One approach is to divide model and services, e.g.
- Modules in other layers
- Same structure can be followed at other layers
- RESTful resources e.g.
com.foobar.collabaration.resources
,com.foobar.collabaration.resources.view
- Application layer modules, e.g.
com.foobar.agilepm.application.team
- RESTful resources e.g.
- Same structure can be followed at other layers
Chapter 10: Aggregates
- As a start: What is an Aggregate? ... What is this concept of invariants and a consistency boundary all about?
- The last question is an especially relevant one.
- Rule: Model True Invariants in Consistency Boundaries
- An invariant is a business rule that must always be consistent.
- Different kinds of consistency: Transactional consistency and eventual consistency.
- When discussing invariants, we're referring to transactional consistency.
- Consistency boundary logically asserts that everything inside adheres to a specific set of business invariant rules.
- With a typical persistence solution, we use a single transaction to manage consistency.
- A properly designed Aggregate is one that can be modified in any way required by the business with its invariants completely consistent within a single transaction.
- A properly designed Bounded Context modifies only one Aggregate instance per transaction in all cases.
- -> We can't correctly reason on Aggregate design without applying transactional analysis.
- Aggregates are chiefly about consistency boundaries and not driven by a desire to design object graphs.
- Note that these rules are rules of thumb.
- Rule: Design Small Aggregates
- With big aggregates, multiple large collections etc. might be loaded during many simple operations.
- What does "small" mean? The correct minimum is however many are necessary, and no more. :)
- Often target for just the Root Entity and a minimal number of attributes and/or Value-typed properties.
- Don't Trust Every Use Case
- A new use case may lead to insights that push us to remodel the Aggregate.
- Be skeptical here, too.
- A large-cluster Aggregate might be problematic
- Often, in such cases, the business goal can be achieved with eventual consistency between Aggregates.
- Rule: Reference Other Aggregates by Identity
- If you don't hold any reference, you can't modify another Aggregate.
- Prefer references to external Aggregates only by their globally unique identity, not by holding a direct object reference.
- See Pat Helland's paper Life beyond Distributed Transactions: an Apostate’s Opinion
- Rule: Use Eventual Consistency Outside the Boundary
- If executing a command on one Aggregate instance requires that additional business rules execute on one or more other Aggregates, use eventual consistency.
- "Ask Whose Job It Is" principle:
- When examining the use case, ask whether it's the job of the user executing the use case to make the data consistent.
- If it is, try to make it transactionally consistent.
- If it is another user's job, or the job of the system, allow it to be eventually consistent.
- When examining the use case, ask whether it's the job of the user executing the use case to make the data consistent.
- Reasons to break the rules
- 1: User Interface Convenience
- 2: Lack of Technical Mechanisms
- user-aggregate affinity: Are the business workflows such that only one user would be focused on one set of Aggregate instances at any given time?
- 3: Global transaction
- 4: Query performance
- Implementation
- Root Entity with Unique Identity
- Law of Demeter: Any given method on any object may invoke methods only on the following:
- Itself
- Any parameters passed to it
- Any object it instantiates
- Self-contained part objects that it can directly access
Chapter 11: Factories
- A Factory may or may not have additional responsibilities in the domain model other than object creation.
- Two main options:
- Factory on Aggregates
- Factory Methods on Aggregates allow you to express the Ubiquitous Language in ways not possible through constructors alone.
- Factory on Service
- Factory on Aggregates
Chapter 12: Repositories
Evans:
For each type of object that requires global access, create an object that can provide an illusion of an in-memory collection of all objects of that type. ... Provide methods to add and remove objects, which will encapsulate the actual insertion or removal of data in the data store. ... Provide Repositories only for Aggregate roots
- Repositories are all about persistency.
- Generally, each persistent Aggregate type will have a Repository
- There is also option of using persistence mechanism's Session or Unit of Work as such. Generally to be avoided.
- Two kinds of Repository design: collection-oriented design and persistence-oriented design
- Collection-Oriented Repositories
- Mimic a collection.
- A repository interface that does not hint that there is an underlying persistence mechanism, avoiding any notion of saving/persisting data to a store.
- For a Java in-memory collection, there is no need to do anything special to get the collection to recognize the changes to the objects it contains.
- Take-aways:
- A repository should mimic a Set interface.
- You must not allow instances of the same object to be added twice.
- When retrieving objects from a Repository and modifying them, you don't need to "re-save" them to the Repository.
- The persistence mechanism must in some way support tracking changes. Can be done in various ways, including the following:
- Implicit Copy-on-Read - Each persistent object is copied when it is loaded from the data store.
- Implicit Copy-on-Write - Proxy objects that make a copy of the managed object when required.
- Note that in general it is possible that instances of some Aggregate types must never be removed through normal application use cases.
- Instances might be needed after they are no longer usable in the application. For e.g. referential and/or historical purposes.
- In this kind of cases Aggregate instances can be marked e.g. as disabled, unusable, or in some other way logically removed.
- Repository interface is often in domain.
- Implementation can be placed in infrastructure layer.
- Another approach is to put implementation in a submodule under Aggregate and Repository module
- Exceptions: Since we're going to abstract away the implementation details in general, we want to isolate clients from those also with exceptions.
- TopLInk has both Session and Unit of Work.
- With Unit of Work, objects to be changed are explicitly registered to the Unit of Work. -> More efficient use of memory & processing power, not so transparent abstraction
- Persistence-Oriented Repositories
- "Save-based" approach.
- The case when the persistence mechanism doesn't implicitly or explicitly detect and track changes.
- Every time you create a new Aggregate instance or change a pre-existing one, you have to put it explicitly into the data store by using e.g. save.
- Repository operation both when aggregates are created and when they are modified. (In comparison with collection-oriented repository no explicit operation when existing aggregate is updated)
- Take-aways:
- We must explicitly
put()
both new and changed objects into the store, replacing value previously associated with the given key. - These data stores are sometimes called Aggregate Stores or Aggregate-Oriented Databases.
- We must explicitly
- Additional behavior
- Sometimes it is beneficial to provide additional behavior on a Repository interface.
- E.g. calculations that must be performed in the data store in order to meet some non-functional requirement.
- At times it may be advantageous to query Aggregate parts out of the Repository without directly accessing the Root itself.
- This should be used primarily to address performance concerns.
- Use with caution
- Special finder methods
- use case optimal query (often resulting as a Value object)
- If there's need for many finder methods supporting use case optional queries on multiple Repositories, it's probably a code smell
- Code smell named Repository masks Aggregate mis-design
- Transactions
- Domain layer is never the correct place to manage transactions. Usually transactions should be managed in the Application Layer.
- Repository implementations should have access to the same Session / Unit of Work for the transaction the Application Layers started.
- Be careful not to overuse the ability to commit modifications to multiple Aggregates in a single transaction. (If need be, revisit Aggregates)
- Repository vs Data Access Object (DAO)
- DAO is expressed in terms of database tables, providing CRUD operations
- Testing repositories: Two ways to look at testing Repositories
- Repositories themselves have to be tested.
- Code using Repositories has to be tested.
Chapter 13: Integrating Bounded Contexts
- There are always multiple Bounded Contexts in any project of significance, and there will be need to integrate.
- A few reasonably straightforward ways to integrate Bounded Contexts
- Expose an API in another Bounded Context and use that API via RPCs from another.
- Use of messaging mechanism
- RESTful HTTP
- Distributed systems are fundamentally different. Author's Principles of Distributed Computing
- The network is not reliable.
- There is always some latency, and maybe a lot.
- Bandwidth is not infinite.
- Do not assume that the network is secure.
- Network topology changes.
- Knowledge and policies are spread across multiple administrators.
- Network transport has cost.
- The network is heterogeneous.
- Experience with
- Open Host Service: Enhance and expand the protocol to handle new integration requirements
- -> Provide only what integrators need at present, based on a range of use case scenarios.
- If at all possible, it is best to minimize or even completely eliminate information duplication across Bounded Contexts.
- It may not be possible to do that entirely.
- E.g. SLAs may make it impractical to retrieve remote data every time it is needed.
- Having the goal to reduce the amount of foreign information will make our jobs much easier.
Chapter 14: Application
A domain model often lives at the heart of an /application/.
Here we're using the term /application/ somewhat interchangeably with /system/ and /business service/.
- System is usually a solution with many applications.
UI
- How do we render domain objects onto the glass?
- There's controversy and disagreement on how best to render objects of the domain model onto the user interface.
- The UI often benefits from views of data richer than is required to accomplish the direct task.
- UI often needs to render properties of multiple Aggregate instances.
- In most use cases, the user performs a state-mutating task that is applied to just one Aggregate instance.
- DTO approach
- Design a DTO to hold the entire number of attributes that are needed to display the view.
- DTO pattern was originally designed to deal with a remote presentation tier that consumes the DTO instances.
- Mediator to publish aggregate internal state
- To reduce coupling between the model and it's (UI) clients
- e.g.
BacklogItem.provideBacklogItemInterest(BacklogItemInterest interest)
that would callinterest.informTenantId(...)
etc.
- Domain Payload Object (DPO)
- A variant of DTO within a single virtual machine.
- Contains a reference to whole Aggregate instances.
- State Representations of Aggregate instances
- REST-based resources
- It's good to think a set of RESTful resources as a separate model (View Model / Presentational Model) to avoid coupling clients straight to the domain model.
- Use Case Optimal Repository Queries
- Creating a DTO/PTO straight with Repository.
- This approach has similar motivations than CQRS. (Might be worth going all the CQRS route)
- Dealing with Multiple Disparate Clients
- You may design your Application Services to accept Data Transformer
- Rendition Adapters and Handling User Edits
- In whatever way your domain data is provided from Application Services - through DTOs, DPOs, or state representations - and whatever presentation framework you use, you may be able to benefit from Presentational Model.
- How do we render domain objects onto the glass?
Application Services
- Application Services are direct clients of the domain model. (Options on the logical location were introduced earlier in Architecture chapter)
- When using an ACID database, the Application Services also control transactions.
- Security is also commonly cared for by Application Services.
- Example
- Some types from the domain model are used in Application Service method signatures.
- -> UI needs to be aware of these types and depend on them.
- Alternatively, signature with only primitive types, DTOs and/or Command objects could be used.
- Spring
@Transactional
used - Potentially also security concerns.
Infrastructure
- To provide technical capabilities for other parts of the application.
Appendix: Aggregates and Event Sourcing: A+ES
Note:
- Related articles can be found from https://abdullin.com/tags/domain-event/
- Sample code can be found from https://github.com/abdullin/iddd-sample
Actual content:
- Basics
- Event Sourcing can be used to represent the entire state of an Aggregate as a sequence of Events that have occurred since it was created.
- State of the Aggregate can be rebuilt from the events.
- Example flow of operations:
- Client calls Application Service
- Loads Aggregate state from Event Stream
- Call Aggregate method passing parameters got, along with Domain Services as needed
- Commit published Events as a Unit of Work to the Event Store to persist the state of the aggregate
- New Events are published from Event Store to all subscribers
- Command Handlers
- Control the task management of our application.
- Command Handler effectively replaces the Application Service method.
- Decoupling the client from the Service can /enhance load balancing, enable competing consumers, and support system partitioning./
- This approach creates /temporal decoupling/ between clients and the Application Service.
- Performance
- Some patterns to apply:
- Cache Event Streams in server memory (as Events are immutable once written to the Event Stream)
- Use /snapshots/ of Aggregate instances to avoid loading and replaying big amounts of an Event Stream.
- With A+ES Aggregates, Aggregates can be partitioned among multiple processes or machines by Aggregate Identity.
- Some patterns to apply:
- A+ES aggregates tend to be smaller (following Aggregate Rules of Thumb)
- Because creating new Aggregates tends to be easier with A+ES than traditional aggregate persistence.
- Read Model Projections
- One of the common concerts of A+ES: How to query the Aggregates by their properties?
- Here Read Model Projections can help
- Domain Event subscribers that project Events to a persistent Read Model.
- See sample lokad-cqrs
- Event enrichers
- One of A+ES problems comes from event's dual purpose.
- i) Aggregate persistence
- ii) Communicate domain-level happenings around the enterprise.
- Subscribers (ii) often need additional information.
- We can simplify this by enriching the domain events with additional data.
- Not essential for reconstructing the aggregate but simplifies Event subscribers
- One of A+ES problems comes from event's dual purpose.
No comments:
Post a Comment