Question about aggregate examples from red book - domain-driven-design

In the red book (Implementing Domain-Driven Design) Vernon Vaughn shows an aggregate example for a Scrum Core Domain. Unfortunately the code samples are just fragments.
For the second attempt the model is split in multiple aggregates instead of using a single large aggregate. As a result the method contract for the planBacklogItem method changes from
public class Product ... {
...
public void planBacklogItem(
String aSummary, String aCategory,
BacklogItemType aType, StoryPoints aStoryPoints) {
...
}
...
}
to
public class Product ... {
...
public BacklogItem planBacklogItem(
String aSummary, String aCategory,
BacklogItemType aType, StoryPoints aStoryPoints) {
...
}
}
The application service looks then like this:
public class ProductBacklogItemService ... {
...
#Transactional
public void planProductBacklogItem(
String aTenantId, String aProductId,
String aSummary, String aCategory,
String aBacklogItemType, String aStoryPoints) {
Product product =
productRepository.productOfId(
new TenantId(aTenantId),
new ProductId(aProductId));
BacklogItem plannedBacklogItem =
product.planBacklogItem(
aSummary,
aCategory,
BacklogItemType.valueOf(aBacklogItemType),
StoryPoints.valueOf(aStoryPoints));
backlogItemRepository.add(plannedBacklogItem);
}
...
}
I understand the idea of aggregates and the sample code, but I wonder why planBacklogItem is not declared as static in the multiple aggregate version. The method does not access any instance data. Separate aggregates were used to achieve better concurrent access. Therefore I don't understand why the application service first pulls a full product from the repository, while none of its data is needed.
Since the BacklogItem uses Ids it can be created without reading the product from the repository. In case the product aggregate has lots of data and child aggregates are accessed frequently, the implementation can cause performance issues.
The only explanation I could come up with is that it should ensure the existence of the product. But why would you not use a method like productRepository.existsProduct(productId) instead?
I'm working with C# and don't understand all the magic of #Transactional. Vaughn did not say anything about the isolation level. Race conditions between reading the product and writing the BacklogItem could occur. Does #Transactional create a serializable transaction? I doubt it since not all storages support it. If the isolation level of the transaction is not serialized or the product is not locked during read it could be deleted before the BackLogItem was written. (It might not be a business case for the scrum examples, but it is a general concern).
I'm afraid that I miss something major. Thanks for any help.

The method does not access any instance data.
Not sure if the book examples are incorrect, but it does use instance data on GitHub samples.
public BacklogItem planBacklogItem(
BacklogItemId aNewBacklogItemId,
String aSummary,
String aCategory,
BacklogItemType aType,
StoryPoints aStoryPoints) {
BacklogItem backlogItem =
new BacklogItem(
this.tenantId(), // <--
this.productId(), // <--
aNewBacklogItemId,
If the isolation level of the transaction is not serialized or the product is not locked during read it could be deleted before the BackLogItem was written.
Indeed, there could be a race condition (assuming we can remove products). TBH I don't know LevelDB enough and didint' dug into the actual implementation details, but a traditionnal foreing key constraint could prevent orphans in a relationnal DB.
However, that wouldn't really work for logical deletes (e.g. archiving) so in these cases I guess there's those choices:
Ignore the problem. Perhaps it doesn't actually matter that a backlog item gets planned a millisecond after a product has been archived? Race Conditions Don't exist?
Lock the Product AR. That could be done in numerous ways, such as forcing an optimistic locking version bump.
Apply an eventually consistent compensating action, such as unplanning a planned backlog item.

Related

What is the intuition behind using value objects in DDD when storing the references (ids) to other Aggregates

Let me preface this by apologising if this was asked before (I could not find a similar question when doing a quick search).
The DDD pattern is centered around defining and isolating aggregates to split the business complexity into a more manageable chunks, and it is strictly forbidden for an aggregate to hold any kind of relation to other aggregates. The references to the other aggregates are instead to be stored as ids that can then be used to fetch the other aggregates on demand. Therefore a single aggregate would only contain its properties, value objects and references to other aggregates.
To use a common example (User, Order) it would look as such:
public class User {
private Long id;
private List<Long> orders;
}
and
public class Order {
private Long id;
private Long userId;
}
However I have seen multiple sources use another layer of encapsulation for the aggregate references, turning them from the property types (as defined in the example above) into value objects like shown below:
public class User {
private Long id;
private List<OrderId> orders;
}
and
public class Order {
private Long id;
private UserId userId;
}
I am rather new to DDD so I want to understand the benefit of doing so when working with non-composite ids.
On the first glance I see a lot of pretty obvious drawbacks (or such they seem to me!), like explosion in quantity of common base types, serialization issues, extra complexity when working with the code and accessing the values stored within these holders, however I am sure that it would not be done so without a very good reason that I am overlooking somewhere.
Any comments, thoughts or feedback would be very welcome!
This is a domain abstraction
private UserId userId;
This is a data structure
private Long userId;
Your domain logic (probably) doesn't care, or need to care, about the underlying data structure that supports representations of UserId, or how they are stored in the database, or any of that nonsense.
The broad term is "information hiding" -- creating firewalls around decisions such that the decision can be changed without that change cascading into the rest of the system. See Parnas 1971.
There are some mistake detection benefits as well. Consider
todays_order.userId + yesterdays_order.userId
That's utter nonsense code; adding two identifiers together doesn't do anything useful. But adding to Long values together is a perfectly normal thing to do in other contexts, and the compiler isn't going to catch this mistake.
recindOrder(orderId, userId)
Did you catch the bug? I've got the arguments in the wrong order! When the method signature is
recindOrder(Long userId, Long orderId)
The machine can't help me catch the problem, because I haven't given it the hints that it needs to look beyond the data structures.
There is also a theory that by providing an explicit representation of the domain value, that code attracts other related functions that otherwise might not find a home -- in effect, it improves the coherence of your design.
(In my experience, that's less true of semantically opaque types like identifiers than it is for numerical abstractions like money. However, if you have some identifiers that are reserved, then the identifier type becomes a convenient place to document the reservation.)

distributed usage of aggregateidentifier

I was wondering whether it would be considered bad practice to use an aggregate identifier across a service in another (extensipn) aggregate which shares that they are both revolving about the same identifiable entity.
The problem I am currently having is that we want to split some logic (bounded context if you so will) into a different service as the one originally creating the aggregate.
In general, this seems to work, as when I send a Command within the second service, it is picked up and updates its state. As I can use EventSourcingHandler to also use Events created in the other service to manipulate its state, I get state information from a source applied by the first services aggregate.
I was worried that the snapshot mechanism would work against me, but apparently it is smart enough to store snapshots separately as long as I make sure the aggregate "type" name is not the same.
So far, so good, the only thing that's a smell for me is that the second aggregate does not have (needs) an initial constructor CommandHandler, as the creation is done in the first aggregate.
So, am I going against the way axon framework intends aggregates to be used, or is this a viable use case?
#Aggregate
#Getter
#NoArgsConstructor
public class Foo {
#AggregateIdentifier
private String fooIdentifier;
#CommandHandler
public Foo(CreateFooCommand command) {
apply(FooCreatedEvent.builder()
.fooIdentifier(command.getFooIdentifier())
.build());
}
#EventSourcingHandler
public void on(FooCreatedEvent event) {
this.fooIdentifier = event.getFooIdentifier();
}
}
#Aggregate
#Getter
#NoArgsConstructor
public class Bar {
#AggregateIdentifier
private String fooIdentifier;
private String barProperty;
#CommandHandler
public void on(UpdateBarCommand command) {
apply(BarUpdatedEvent.builder()
.fooIdentifier(this.fooIdentifier)
.barProperty(command.getBarProperty())
.build());
}
#EventSourcingHandler
public void on(FooCreatedEvent event) {
this.fooIdentifier = event.getFooIdentifier();
}
#EventSourcingHandler
public void on(BarUpdatedEvent event) {
this.barProperty = event.getBarProperty();
}
}
The case for why I tried to split is that we wanted to separate the base logic (creation of the aggregate, in this case a vehicle) from the logic that happens and is handled in a different bounded context and separate microservice (transfers from and to a construction site). Since I cannot publish a creation event (CommandHandler in the constructor, sequence 0) for the same aggregate identifier but different aggregate type twice, I could not separate the two states completely.
So my only options right now would be what I presented above, or use the creation of the second aggregate to set a different aggregateId, but also add internally the aggregateId of the first aggregate to allow for events to be published with the aggregateId information of the first as a reference Id. To make this work I would have to keep a projection to map back and forth between the two identifiers, which also does not look too good.
Thanks in advance,
Lars Karschen
Very interesting solution you've come up with Lars. Cannot say I have ever split the Aggregate logic in such a manor that one service creates it and another loads the same events to recreate that state in it's own form.
So, am I going against the way axon framework intends aggregates to be used, or is this a viable use case?
To be honest, I don't think this would be the intended usage. Not so much because of Axon, but more because of the term Bounded Context you are using. Between contexts, you should share very consciously, as terms (the ubiquitous language) differs per context. Your events are essentially part of that languages, so sharing the entirety of an aggregate's stream with another service would not be something I'd suggest normally.
Whether these services you are talking about truly belong to distinct Bounded Contexts is not something I can deduce right now, as I am not your domain expert. If they do belong to the same context, sharing the events is perfectly fine. Then still I wouldn't recreate a different aggregate based on the same events. So, let me add another concept which might help.
What I take from your description, is that you have something called a Vehicle aggregate which transitions different states. Wouldn't a Polymorphic Aggregate be the solution you are looking for? That way you can have a parent Vehicle aggregate with all the basics, and more specific implementations when necessary? Still, this might not fit your solution completely, something I am uncertain about given your description.
So, I am going to add a third pointer which I think is valuable to highlight:
Since I cannot publish a creation event (CommandHandler in the constructor, sequence 0) for the same aggregate identifier but different aggregate type twice, I could not separate the two states completely.
This line suggests you want to reuse the Aggregate Identifier between different Aggregates, something which comes back in the question's title too. As you've noted, [aggregate identifier , sequence number] pairs need to be unique. Hence, reusing an aggregate identifier for a different type of aggregate is not an option. Know however that Axon will use the toString method of your aggregate identifier class to fill in the aggregate identifier field. If you would thus adjust the toString() method to include the aggregate type, you'd be able to keep the uniqueness requirement and still reuse your aggregate identifier.
For example, the toString method of a VehicleId class containing a UUID would normally output this:
684ec9f4-b9f8-11ea-b3de-0242ac130004
But if you change the toString to include the aggregate type, you would get this:
VehichleId[684ec9f4-b9f8-11ea-b3de-0242ac130004]
Concluding, I think there are three main points I'd like to share:
Axon Framework did not intent to reuse Aggregate Streams to recreate distinct Aggregate types.
Polymoprhic Aggregates might be a means to resolve the scenario you have.
The [aggregateId, seqNo] uniqueness requirement can reuse an aggregateId as long is the toString method would append/prepend the aggregate type to the result.
I hope this helps you on your journey Lars. Please let me know of you feel something is missing or if I didn't grasp your question correctly.

Domain-Driven Design: how to model nested product category hierarchy? Even worse, what if the product category is an Aggregate Root?

I am practicing Domain-Driven Design so why not build a demo product catalog project? Apparently Product is the Core Domain here, but since I like to make the project more interesting, I would love to support nested Category hierarchy. In other words, a Category could have many child Category.
Moreover, I would want to separate Category from Product domain and make it its own Supporting Domain.
Question: Marking Category as AggregateRoot doesn't sound right to me. A Category could have many child Category, which are also AggregateRoots?!! How can I go about modeling this? Nested product category is pretty common in E-Commerce real life situation.
namespace DL.Demo.Domain.Shared
public abstract class ValueObjectBase<T> : IEquatable<T>
where T : ValueObjectBase<T>
{
public abstract bool Equals(T other);
public abstract override bool Equals(object obj);
public abstract override int GetHashCode();
}
public abstract class EntityBase : IEquatable<EntityBase>
{
public Guid Id { get; private set; }
protected EntityBase()
{
this.Id = Guid.NewGuid();
}
// Some Object overrides
}
And I actually have AggregateRoot inherents from Entity because I guess only an Entity could be an AggregateRoot?
public abstract class AggregateRoot : EntityBase
{
}
namespace DL.Demo.Domain.Catalog
public class Category : AggregateRoot
{
public string Name { get; private set; }
public Guid? ParentCategoryId { get; private set; }
public CategoryStatus CategoryStatus { get; private set; }
}
Having a nested list of AggregateRoot just doesn't sound right to me. If you don't mark the Category as the AggregateRoot, how would you go about modeling this?
I am new to DDD and all other related cool stuff like Domain Events, Event Sourcing, etc. I will be appreciated if somebody who had experience can tell me if I am going to the right way.
I am new to DDD and all other related cool stuff like Domain Events, Event Sourcing, etc. I will be appreciated if somebody who had experience can tell me if I am going to the right way.
You are on the right way.
Category should be an Aggregate root, with a reference to parent category by it's ID and this is very good.
Nested categories are a good candidate for event-sourcing, even if there are no special invariants to protect because of the different modes that this hierarchy could be projected in the Read models. You are not limited in any way on that representation, although the Aggregate is straight-forward. In every used Read model you could implement them differently as:
Model Tree Structures with Parent References
Model Tree Structures with Child References
Model Tree Structures with an Array of Ancestors
Model Tree Structures with Materialized Paths
Model Tree Structures with Nested Sets
See more here about implementing tree structures (this link points to MongoDB but that is not relevant).
The Category Aggregate just emits simple events as ACategoryWasCreated, ACategoryHasMovedToOtherParent and so on and the Read models just adapt to reflect those events.
I've implemented a tree structure like this and the queries on the read-side (the query side) are very very fast. You could select the products in a category and all child categories with no joins. Or you could build a category path, again, with no joins.
The key to defining an aggregate is to define first a transactional boundary. Outside of an aggregate boundary consistency is eventual - achieved by reacting to the domain events emitted by an aggregate.
Aggregate can hold another aggregate ID (Value Object) as a reference, however, is not responsible to be transactionally consistent with another aggregate.
So, the main question - Is your tree transactionally consistent? If yes, linked list won't scale well. You have to model it differently.
Modeling is context specific and is not cookie-cutter exercise. Maybe your category is just a value object that could be modeled as a path. Hard to say without broader context.
If you want to have a category tree, then the tree itself should probably be your aggregate root (I see you were coming to this conclusion on your own in the comments already). And this would have functions to add or remove children and so on.
And yes, with very large trees you could probably gain a lot of performance in having a read-only projection of your tree in for instance json format (stored in MongoDb, cache, file or whatever). Especially considering how such a category tree is typically updated only a tiny fraction of how often it is read, you could also easily get away with always just maintaining that json and foregoing a normalised database table tree altogether.

DDD - Problems in constructor and methods in entities design

I have a problem with regards to entity design. As I've read, when you design a DDD entity, the constructor should contain the values needed for an entity to "exist". For example, in the domain I am working on, a Class entity cannot exist without a Section and a Level:
public class Class
{
public Class(short id, string section, Level level)
{
ID = id;
Section = section;
Level = level;
}
//
// Properties
//
public short ID { get; private set; }
public string Section { get; private set; }
public Level Level { get; private set; }
//
// Methods
//
public static IList<Class> GetClassesByTeacher(short teacherID)
{
List<Class> classes = new List<Class>();
classes.Add(new Class(1, "a", null));
classes.Add(new Class(2, "b", null));
classes.Add(new Class(3, "c", null));
return classes;
}
}
Here Level is also an entity. As I am not yet finished in the design, Level's contructor might also contain an entity SchoolYear. What bothers me is for me to call GetClassesByTeacher method, I need to instantiate a Class along with other entities (Level, and also SchoolYear, needed in Level's constructor).
Is this the correct? I think it's bothersome when I just want to call the method. Are there other ways? I considered making it static but others said testability would suffer. I'm not sure if CQRS is one of the solution for what I want to do as I haven't yet read too much about it, but if it is, are there any other techniques aside from CQRS I can employ, or is it when going DDD, this is how it really is? Or is my entity design incorrect?
You should reconsider you domain model, as you actually say it seems there something wrong.
I may refer to Single Responsibility Principle (SRP) in which any class should have one one reason to change. In your example, what happens if we added a new field to 'Class', we will modify 'Class' it self and is right, but what happens if we decide that the listing should be on reversal order, or if you need a new type of list taking into account only interim teachers... you should change 'Class' but 'Class' has nothing to do with listings.
To answer you question, you might take a look at Repository pattern. Repositories are where you could ask for these type of listings.
I might split Class into two:
one for 'Class' model
other for 'Class' repositories
In summary:
public class Class
{
public Class(short id, string section, Level level)
{
ID = id;
Section = section;
Level = level;
}
//
// Properties
//
public short ID { get; private set; }
public string Section { get; private set; }
public Level Level { get; private set; }
}
public class ClassRepository
{
private IList<Class> contents;
//
// Methods
//
public IList<Class> GetClassesByTeacher(short teacherID)
{
List<Class> classes = new List<Class>();
for (Class elem: contents) {
if (elem.getTeacher().equals(teacherID) {
classes.Add(elem);
}
}
return classes;
}
}
repository = new ClassRepository;
level1 = new Level();
repository.Save(new Class(1, "a", level1));
repository.Save(new Class(2, "b", level1));
repository.Save(new Class(3, "c", level1));
result = repository.GetClassesByTeacher(1);
There are other details like using a ClassRepositoryInterface and implement with an InMemoryClassRepository, you will miss also Teacher information in class, as long as one one teacher drives the class, if not you might change how to filter by teacher, etc, etc.
I'm not a Java developer and the code will not compile but I expect you get the idea.
The GetClassesByTeacher method does indeed belong in some kind of repository or service class. Your Class entity is meant to represent an instance of that thing in the real world. An entity is not meant to provide instances (say, from some underlying persistence) - they are only meant to represent them. A ClassRepository would be a way to provide instances of the Class entity into your domain.
You also mentioned that Class cannot exist without a Level. You are speaking about aggregates here. There is a lot of DDD material online with regards to designing aggregates. Here are a couple:
DDD: Aggregates and Aggregate Roots
DDD: The Aggregate And Aggregate Root Explained
EDIT:
When an entity needs another entity to exist, should it always be an
aggregate?
No, just because entity A depends on entity B's existence, it doesn't mean that entity A needs to belong to entity B's aggregate.
As now I have a model in which many entities (like Class, Level,
Subject, Adviser, Teacher, etc.) exists only in a certain SchoolYear
(an entity). Is it OK for an aggregate to get that large?
An aggregate this large could result in performance and consistency issues.
Why performance? You could be loading a huge graph of data in memory for some aggregate root. You most likely only need to work on a fraction of that aggregate for whatever unit of work is occurring and not all the entities involved.
What consistency issues? The larger the aggregate, the more likely data can be changed in another part of the system while it has been retrieved into memory. When saving, data loss can occur.
Vaughn Vernon covers exactly these problems in his three-part Effective Aggregate Design series. It's a bit daunting if you aren't familiar with DDD lingo, but I highly recommend this read!
Also, by what you said, the Entity should not use the repository. If
some business logic in the Entity needs database access for it to be
processed, should it directly use DAL?
Entities should not know anything about repositories or services (or anything else, for that matter). They should not have any dependency on any other 'layer' in the system. Everything can know about your entities, but your entities shouldn't know about anything else. Provide me with an example of why you would want an entity to call on a repository and maybe I can provide a better answer.

DDD and Factories

Hi I have a few questions regarding Domain Driven Design and using Factories / Factory Methods.
Per the Domain Driven Design Blue Book (Eric EVan's Book) it states that complex constructors should be encapsulated inside Factories / Factory Methods / Builders so there is a consistent place where you check all the invariants, so my question is regarding this:
Let's say I am developing a magic organizer application where you can make CRUD like operations on magic effects (like a post on a blog + several attributes like effect duration, materials used (list of strings), patter associated with the magic effect) and some of the invariants are that a magic effect must always have a title, a content of the magic effect, a duration and an optional patter and must be published by a user registered in the application.
So since I have quite a few invariants I have a EffectBuilder that builds MagicEffect objects and checks all the invariants.
Is it ok to do something like this in the user class?
public class User {
// Several attributes and business methods
public MagicEffect publishEffect(final String title, final String content, final Long duration, final Collection<String> elements) [
EffectBuilder builder = new EffectBuilder();
builder.withAuthor(this);
builder.withTitle(title);
builder.withContent(content);
builder.withDuration(duration);
builder.withElements(elements);
return builder.build();
}
};
Or should I do something like:
public class User {
// Several attributes and business methods
public EffectBuilder publishEffect() [
EffectBuilder builder = new EffectBuilder();
builder.withAuthor(this);
return builder;
}
};
And somewhere else
User user = userRepository.findById(userId);
MagicEffect effect = user.publishEffect().withTitle(title).withContent(content).withDuration(duration).withElements(elements).build();
userRepository.save(user);
I mean the first example I have a huge method with huge amount of parameters but I make sure all the invariants are set in the effect when it's built, in the other scenario I programatically improve the code readability by having a fluent interface but I canot make sure the invariants are met 100% of the time.
Which is the better approach? Is there a more balanced approach of doing it?
Thanks
Pablo
I think that your second approach is better. The whole point of Builder is to avoid large list of parameters like you have in your first example. Builder is not responsible for enforcing invariants in the object that it builds. Object itself enforces them. I think it is perfectly fine to have an instance of EffectBuilder without Title or with a default title. As long as the MagicEffect itself enforces 'Every effect should have a title' invariant.

Resources