distributed usage of aggregateidentifier - domain-driven-design

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.

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.)

Service Class representation in UML

I have three classes one is called
WorkCoordinator and it calls different service classes depending on an event passed to it, so if the event is trackIssue there is a TrackService class that handles some operations specifically for tracking and there is also a Track object. So you could have the following
WorkCoordinator -- (track issue) --> TrackService (has a list of Track objects)
How would you correctly represent these three in a UML diagram ? where everything starts with the workcoordinator which uses a TrackService and TrackService may have a function like add(Track track), where you would pass it a Track object to add to an array list within it say:
private ArrayList<Track> tracks;
and as add gets called, then a track is added to tracks.
Appreciate any insights, I was thinking something like this but may be totally wrong.
I have three classes one is called
Contrarily to an operation a class cannot be called, but it can be used.
WorkCoordinator -- (track issue) --> TrackService
when the event string is trackIssue the class WorkCoordinator uses the class TrackingService, but how ? Because in your diagram the class TrackingService only has the operation add that means that operation is called, even I have some doubt about that, more the fact we don't know from where the instance of Track given in argument comes from. If an other operation is called add it in the diagram.
About your diagram :
the role of the line between WorkCoordinator and TrackingService is unknown as it is, and then invalid. Because of the attribute trackingService probably you wanted to also show it as a relation, in that case the relation must completed.
TrackingService has two lists of Track, one though the attribute trackItems and an other one through the relation tracks. This is probably not what you wanted, and trackItems must be renamed tracks or the reverse.
to show the same thing through an attribute and a relation is legal in UML, but quite heavy because the reader must check they are the same thing, I encourage you to use only one of them, and to favor the relation when both classes are drawn.
your aggregation says TrackingService is composed of Track, are you sure this is the case and an aggregation must be used ?
How would you correctly represent these three in a UML diagram ?
The class diagram does not indicate at all that when the processed event is trackIssue the operation add (or an other) is applied on trackingService (with the right argument). Of course you can add a note to say that, but that note is a free text and only human can understand it.
To show that in a diagram you can use a sequence diagram or an activity diagram, depending on what you want to show.
The sequence diagram showing what happens during the execution of process can be (supposing a new instance of Track is created to be given in argument to add) :
event is supposed to be the argument of process, to name the instance of TrackingService I used trackingService being the name of the attribute, and item represents the created instance of Track to use it in the message add.
All of that seems vague, but this is normal because an interaction is not a behavior, and a sequence diagram focuses on message interchange between lifelines.
If you want to fully model the behavior of the operation process without ambiguity you can use an activity, and the diagram can be :
Additional remarks :
An event is generally much more than a name like trackIssue, so the parameter of process is not a string or that string is a complex form.
Track has getter/setter for the id but not for the name, seems strange. Are you sure the id is not only set (with name) when an instance is created ?

Can a repository access another by DDD?

I am practicing DDD, and I have a very simple example, which looks like this currently:
Polling
getEventBus() -> Bus
getEventStorage() -> Storage
getMemberRepository() -> MemberRepository
getCategoryRepository() -> CategoryRepository
getBrandRepository() -> BrandRepository
getModelRepository() -> ModelRepository
getVoteRepository() -> VoteRepository
MemberRepository
MemberRepository(eventBus, eventStorage)
registerMember(id, uri)
-> MemberRegistered(id, uri, date)
-> MemberRegistrationFailed //when id or uri is not unique
isMemberWithIdRegistered(id)
isMemberWithUriRegistered(uri)
CategoryRepository
CategoryRepository(eventBus, eventStorage) {
addCategory(id, name)
-> CategoryAdded(id, name, date)
-> CategoryAdditionFailed //when id or name is not unique
isCategoryWithIdAdded(id)
isCategoryWithNameAdded(name)
};
BrandRepository
CategoryRepository(eventBus, eventStorage) {
addBrand(id, name)
-> BrandAdded(id, name, date)
-> BrandAdditionFailed //when id or name is not unique
isBrandWithIdAdded(id)
isBrandWithNameAdded(name)
};
ModelRepository
ModelRepository(eventBus, eventStorage)
addModel(id, name, categoryId, brandId)
-> ModelAdded(id, name, categoryId, brandId, date)
-> ModelAdditionFailed //when id or name is not unique and when category or brand is not recognized
isModelWithIdAdded(id)
isModelWithNameAdded(name)
VoteRepository
VoteRepository(eventBus, eventStorage)
addVote(memberId, modelId, vote, uri)
-> MemberVoted(memberId, modelId, vote, uri, date)
-> VoteFailed //when the member already voted on the actual model and when memberId or modelId is not recognized
I'd like to develop here a polling system, so I think we could call this the polling domain. We have members, categories, brands, models and votes. Each member can vote on a model only once and each model have a brand and a category. For example inf3rno can vote on the Shoe: Mizuno - Wave Rider 19 with 10, because he really likes it.
My problem is with the
addModel(id, name, categoryId, brandId)
-> ModelAdded(id, name, categoryId, brandId, date)
-> ModelAdditionFailed //when id or name is not unique and when category or brand is not recognized
and the
addVote(memberId, modelId, vote, uri)
-> MemberVoted(memberId, modelId, vote, uri, date)
-> VoteFailed //when the member already voted on the actual model and when memberId or modelId is not recognized
parts. Let's stick with the ModelAddtion.
If I want to check whether the categoryId and brandId are valid, I have to call the CategoryRepository.isCategoryWithIdAdded(categoryId) and the BrandRepository.isBrandWithIdAdded(brandId) methods. Is it allowed to access these methods from the ModelRepository? Should I inject the container and use the getCategoryRepository() -> CategoryRepository and getBrandRepository() -> BrandRepository methods? How to solve this properly by DDD?
update:
How would you solve this validation in the domain if you'd really need the foreign key constraint and your db engine would not have this feature?
There are 2 hard problems in computer science: cache invalidation, naming things, off by one errors, and attributing quotes.... I'll come in again.
Repository, as used in the ubiquitous language of DDD itself, doesn't normally mean what you are trying to express here.
Eric Evans wrote (the Blue Book, chapter 6).
Another transition that exposes technical complexity that can swamp the domain design is the transition to and from storage. This transition is the responsibility of another domain design construct, the REPOSITORY
The idea is to hide all the inner workings from the client, so that client code will be the same whether the data is stored in an object database, stored in a relational database, or simply held in memory.
In other words, the interface of a repository defines a contract to be implemented by the persistence component.
MemberRepository
MemberRepository(eventBus, eventStorage)
registerMember(id, uri)
-> MemberRegistered(id, uri, date)
-> MemberRegistrationFailed //when id or uri is not unique
This, on the other hand, looks like a modification to your domain model. "registerUser" has the semantics of a command, MemberRegistered, MemberRegistrationFailed look like domain events, which strongly implies that this thing is an aggregate, which is to say an entity that protects specific invariants within the domain.
Naming one of your aggregates "Repository" is going to confuse everybody. The names of aggregates should really be taken from the ubiquitous language of the bounded context, not from the pattern language we use to describe the implementation.
If I want to check whether the categoryId and brandId are valid, I have to call the CategoryRepository.isCategoryWithIdAdded(categoryId) and the BrandRepository.isBrandWithIdAdded(brandId) methods. Is it allowed to access these methods from the ModelRepository?
Assuming, as above, that CategoryRepository, BrandRepository and ModelRepository are all aggregates, the answer is no, no, and no.
No: If your have modeled your domain correctly, then all of the state needed to ensure that a change is consistent with the business invariant should be included within the boundary of the aggregate that is changing. Consider, for example, what it would mean to be adding a model in this thread, while the brand that the model needs is being removed in that thread. These are separate transactions, which means that the model can't maintain the consistency invariant.
No: if the motivation for the check it to reduce the incidence of errors by sanitizing the inputs, that logic really belongs within the application component, not the domain model. It's the responsibility of the domain model to ensure that the parameters of the command induce a valid change to the state of the model; it's the responsibility of the application to ensure that the correct parameters are being passed. The sanity check belongs outside the domain model
That said
No: aggregates in the domain model shouldn't access each other directly; instead of passing in an aggregate, pass in a domain service that represents the query that the domain model needs to run.
Model.addModel(brandId, brandLookupService) {
if (brandLookupService.isValid(brandId)) {
// ...
}
}
This extra bit of indirection removes any ambiguity about which aggregate is being changed within a given transaction. The BrandLookupService itself, under the covers, could well be loading a read only representation of a Brand from the BrandRepository.
Of course, it still doesn't address the concern that the brands could be changing even as the model is referencing the brand. In other words, there's a potential data race in this design because of where the transactions boundaries are drawn.
How would you solve this validation in the domain if you'd really need the foreign key constraint and your db engine would not have this feature?
Two options:
1) Redraw the aggregate boundaries.
If you need the foreign key constraint enforced by the domain model, then its not a "foreign" key; its a local key for an aggregate that contains both bits of state.
2) Change the requirements
Udi Dahan, I think in this talk, pointed out that sometimes the way that the business (currently) runs simply doesn't scale properly, and the business itself may need to change to get the results that they want.
I am not sure what the aggregates are here.
Let's try this a different way - how do we implement this?
For example inf3rno can vote on the Shoe: Mizuno - Wave Rider 19 with 10, because he really likes it.
In your design above, you used a VoteRepository to do this. We don't want to use "repository", because that noun isn't taken from the ubiquitous language. You called this the polling domain earlier, so let's try Poll as the entity. The Poll entity is going to be responsible for enforcing the "one man, one vote" invariant.
So it's going to look something like
class Poll {
private PollId id;
private Map<MemberId,Vote> recordedVotes;
public void recordVote(MemberId memberId, Vote vote) {
if (recordedVotes.containsKey(memberId)) {
throw VoteFailed("This member already voted. No backsies!");
}
recordedVotes.put(memberId, vote);
}
}
And the code to record the vote is going to look something like
// Vote is just a value type, we can create one whenever we need to
Vote vote = Vote.create(10);
// entity ids are also value types that we can create whenever
// we want. In a real program, we've probably done both of these
// lookups already; Poll and Member are entities, which implies that
// their identity is immutable - we don't need to worry that
// MemberId 3a7fdc5e-36d4-45e2-b21c-942a4f68e35d has been assigned
// to a different member.
PollId pollId = PollId.for("Mizuno - WaveRider 19")
MemberId memberId = MemberId.for("inf3rno");
Poll thePoll = pollRepository.get(pollId);
thePoll.recordVote(memberId, vote);
pollRepository.save(thePoll);
From a puristic view, you shouldn't need to access 2 repositories. I say puristic because it might take a while to understand what missing bits of the domain would simplify this.
From the top of my head, I would question myself the following:
Do you need to ensure that those entities exist? (isCategoryWithIdAdded and isBrandWithIdAdded). Depending on your storage engine, can you enforce this (e.g. required foreign key). I think this would be my approach, as it's also faster from a performance point of view.
Can you ensure those entities exist somewhere else? Some DDD implementations assume that data is correct once an Application Service is called.
And last (this might be a bit questionable) can this feature link 2 things even if they don't exist? (what would be the 'damage').
And just a comment... having something in your domain called Model is so confusing, as it's part of the vocabulary of DDD. =D

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.

Object Oriented Programming - Best Practice?

Which of the following would you go with?
And based on object oriented programming which one is the best practice?
A
Class Note
{
//Some properties, etc
public static Note getNoteFromServer();
public void UpdateNoteOnServer();
}
B
Class Note
{
//Some properties, etc
}
Class NoteManager
{
public static Note getNoteFromServer();
public static UpdateNoteOnServer(Note);
}
I would say option B. In that way you separate concerns: you have a Note that can be reused anywhere (and not necessarily on a networked application), and you have a manager class that only cares with server communication.
You may also think on implement logic for multiple servers. For example, you may want to comunicate with data formats like JSON or XML. You may implement an interface (example, interface INoteManager) and then implement two classes with servers for each of the data types I mentioned (example, NoteManagerXml and NoteManagerJson).
The main point on this question is sepration of concerns. Hope I've helped! :)
To take a different viewpoint from my other answer, I'd suggest that your division into Note/NoteManager is the wrong one - not because Note has anything wrong with it, but because the term Manager is a bit of a code smell because it's very generic, inviting the use of the class as a general dumping ground.
If the class is responsible for note persistence, call it NoteRepository.
If it's responsible for validating the content of a single note, move the logic onto the Note.
If it's responsible for creating notes, providing a number of convenience methods for easily creating notes, call it NoteFactory.
And if it's responsible for all of the above, split it into separate pieces because it's doing too much.
That's a pretty opinion based question you're asking there.
You're essentially asking (if I understand correctly) whether it is better to have a Class which contains only properties and another class to manage that object (Example B) or to have a class which does everything (Example A).
It really depends. If we're planning on using a MVC kind of framework, Example B would fit better, with Note being your Model, and NoteManager being the controller.
Personally, I would go with a hybrid of A and B, where NoteManager is handling controller actions, but the Model still has methods of its own to do things like managing a singleton instance. So maybe something like this?
Class Note
{
//Some properties, etc
public static Note getInstance(noteIdentifier);
public void saveNote();
}
Class NoteManager
{
// This handles view validation and calls Note.saveNote();
public static UpdateNoteOnServer(Note);
}
I think A is better, for 1 reason:
It implements the Object Oriented
paradigm to the letter.
The problem i see with B is that a static method that receives an instance of the same class sounds redundant to me because, why would you use a static method to apply behaviour to an instance of the same class? The whole idea behind classes and instances is that Classes are the frame and instances cookies, if you need different cookies, modify your frame and get new ones.
It seems to depend on how its going to be used in your program. If Note is the only class or is the parent class for derived classes then there is no point and having a "Manager", Keep It Simple Stupid (KISS). However if the Manager has to deal with other classes via Interfaces then I can see having a seperate class.
As per my experience best practice is , as long as things are separated DRY is best practice. you can extends note to notemanager
Class Note
{
//Some properties, etc
}
Class NoteManager
{
public static Note getNoteFromServer();
public static UpdateNoteOnServer(Note);
}
I'd choose B, unless you want to end up like poor ol' PHP:
get_note_from_server_and_print_the_response($note, 'PHP, why must you be so disorganized?')
But seriously, it may seem intuitive to do A at the moment, but you'll eventually split A up, as those server operations will require more and more related functions, until you have a mammoth Note class which contains every function in your program...
"It Depends"
One of the things it depends upon is the language of implementation.
If you are working in C# or Java, then you'll likely want to go with the Note/NoteManager approach as this gives you the most flexiblity of implementation - because static members in those languages a kind of second class citizens.
To illustrate, in Delphi's original Object Pascal lanaguage, methods and properties that could be accessed without an instance were known as class members, not static members, and they could be virtual, and therefore overridden in descendent classes.
If you're working with a language that provides features like "virtual class (static) members" and a few others, then you might want to merge Note/NoteManager together.
I would go with "B"
Reason why is that you may require "Note" to be used with another type of Controller class, like what you have done for NoteManager.
Also gives you the ability to dissociate your Data Objects or DTO's or Model away from your actual controller classes.
C
Class Note
{
//Some properties, etc
public static Note LoadFrom(Whatever);
public void SaveTo(Whatever);
}

Resources