I have a simple use case where the user can discard a profile. It is really easy to understand but raise some modeling questions.
1/ Is it okay to have a flag in my profile entity to indicate that he is in the trash ?
I don't think. So I would like to have two ProfileRepository and TrashRepository.
2/ So given those two repositories, in my application service I just have to remove the profile from his repository and add it to the trash. Seems natural but can cause troubles if I cannot have a transaction. (but it is not the case in my app).
However, I'm using a relational database and a first idea would be to use a column to indicate if the row is in the trash or not and having the two repositories working on the same table. I'm not sure that it is a good idea.
I can also add a discard method to the ProfileRepository so that I don't need the two.
Which is the best solution ?
Can I set a flag to determinate the status (discarded) in my entity or is it better to have two different entities with different repositories ?
Discard really is a business command and a command will always mutate the state of the domain. I believe that it's perfectly valid to have a status indicating that the profile has been discarded. What would be wrong is to introduce a property such as deleted or active when what you really mean is discarded.
However, some thinks that it's sometime useful to model states explicitely: have an entirely different class to represent a discarded profile.
Here's a few links related to explicit state modeling:
http://codebetter.com/gregyoung/2010/03/09/state-pattern-misuse/
http://p2p.wrox.com/book-patterns-principles-practices-domain-driven-design/94718-ch16-explicit-state-modeling-identity-map.html
https://medium.com/#martinezdelariva/explicit-state-modeling-f6e534c33508
Related
After reading the book Domain-Driven Design and some characters in the book Implementing Domain-Driven Design, I finally try to use DDD in a small service of a microservice system. And I have some questions here.
Here we have the entities Namespace, Group, and Resource. They are also aggregate roots:
As the picture pointed out, we have many Namespaces for users. And in every Namespace, we have Groups as well. And in every Group, we have Resources.
But I have a business logic:
The Group should have a unique name in its Namespace. (It is useful that the user can find the Group by its name)
To make it come true, I need to do those steps in the application layer to add a group with time complexity O(n):
Get the Namespace by its ID from the Repository of Namespace. It has a field Groups, and its type is []GroupID.
Get []Group value by []GroupID value from the Repository of Group.
Check if the name of the new group is unique in the existing Groups we get.
If it does be unique, then use the Repository of Group to save it.
But I think if I just use a sample transaction script, I can finish those in O(lg n). Because I know that I can let the field of Group name be unique in the database. How can I do it in DDD?
My thinking is:
I should add a comment in method save of the Repository interface for Group to let the user know that the save will check the name if is unique in the same Namespace.
Or we should use CQRS to check if the name of Group is unique? Another question is that maybe a Namespace may have a lot of Group. Even though we only put the ID of Group in the entity Namespace, it does cost a lot of space size. How to paginate the data?······ If we only want to get the name of Namespace by its ID, why we need get those IDs for Groups?
I do not want the DDD to limit me. But I still want to know what is the best practices. Before I know what happens, I try to avoid breaking rules.
My solution:
Thanks for the answer by #voiceofunreason. I find that it is hard to write code for set validation in the domain layer still.
#voiceofunreason tells me that I need consider the real world. I do consider and I am still confused that how to implement it to avoid breaking DDD rules. (Sorry but my question is not do we need the condition or not. My question is HOW to make the condition(or domain logic) come true without higher time complexity)
To be honest, I only have a MongoDB serving for storing all data. If I am using Transaction Script, everything is easy:
Create an index for the name of Group to make sure the names are unique.
Just insert a new Group. If the database raises any error, just refuse the request from the user.
But if I want to follow the DDD, and put the logic into the domain layer, I even do not know where to put the logic (it is easy in Transaction Script, right?). It really makes me feel blue. So my solution is:
Use DDD to split the total project into many bounded contexts.
And we do not care if we use the DDD or others in the bounded context. So tired I am.
In this bounded context, we just use Transaction Script.
Is the DDD not well to hold the condition for the set of entities, right? Because DDD always wants to get all data from the database rather than just deal in the database. Sometimes it makes the time complexity higher and I still do not know how to avoid it. Maybe I am wrong. If I am, please comment or post a new answer, thanks a lot.
The Group should have a unique name in its Namespace.
The general term for this problem is set validation. We have some collection of items, and we want to ensure that some condition holds over the entire set....
What is the business impact of having a failure
This is the key question we need to ask and it will drive our solution
in how to handle this issue as we have many choices of varying degrees
of difficulty. -- Greg Young, 2010
Some questions to consider include: is this a real constraint of the domain, or just an attempt at proofreading? Are we the authority for this data, or are we just storing a local copy of data that belongs to someone else? When we have conflicting information, can the computer determine whether the older or newer entry is in error? Does the business currently have a remediation process to use when the set condition doesn't hold? Can the business tolerate a conflict for some period of time (until end of day? minutes? nanoseconds?)
(In thinking about this last question, you may want to review Race Conditions Don't Exist, by Udi Dahan).
If the business requirement really is "we must never write conflicting entries into the collection", then any change you make must lock the collection against any potential conflicts. And this in turn has implications about, for example, how you can store the collection (trying to enforce a condition on a distributed collection is an expensive problem to have).
For the case where you can say: it makes sense to throw all of this data into a single relational database, then you might consider that the domain model is just going to make a "best effort" to avoid conflicts, and then re-enforce that with a "real" constraint in the data model.
You don't get bonus points for doing it the hard way.
I am modeling a course app, trying to play with DDD and Clean Architecture. So I have Course, which has one or more modules, and each of them has one or more lessons
I created a ModuleLessons aggregate root which is a list of lessons that belongs to a module.
I have the use case where user can access the whole list of lessons within a module, so he access an url like myapp/lessons/{module-id} and this it will endup calling something like moduleLessonsRepository.getById({module-id}) and will render to user a list of lessons which compose that module
As I understand, repository should only deal with the whole aggregate root, not child entities directly. In other words, if Lesson is not an AR, I must not have a LessonRepository.getById()
But I have another use case where user can access something like myapp/lesson/{lesson-id}
But how could I implement if I cant have a repository which returns a lesson by it's id?
I could load the ModuleLessons aggregate and then find lesson within it, but I don't have it's id to query.
I could put module id and lesson id (or maybe just a 'lesson position within it's module) on the url and use that to find the ModuleLessons AR, but I'm puting extra data on the url just to fulfill architectural constraints, is that right?
Finaly, the lesson position within it's module does mater, but this piece of data dont belong to the lesson nor to the module, that's why I created the list itself as the AR, maybe it wasn't the right decision?
Your model sounds very structural, e.g. a course consists of modules, modules consist of one or more lessons being taught as part of it, etc. It's not really solving a problem (or at least you've not described one). Could be booking a course, could be attending the lessons of a course, etc ... The other observation is that you seem to be describing what are essentially queries. You will find that most models have a conflict of interest when it comes to reading and writing, one of the main reasons CQRS came about in the first place (not suggesting you adopt that, merely pointing out the obvious). Writing happens to align with use cases and rules that must be upheld at all times (or else). Reading, on the other hand, seems to happen far more liberally, without much consideration for the past use cases that brought the queryable data about. One easy step could be to undo yourself of the shackles that say you can't return lessons by id - simply add whatever code you need to make that happen and don't feel compelled to put that in a box like a repository. Consistency is to be considered, but if the writing imposes the proper transactional boundaries, the reading won't inadvertently observe something it shouldn't. Secondary indexes can help too - they're the sort of thing that can help you find the module id based on the lesson id if you choose to continue to go down the current path.
If it is just about reading data (e.g. showing data to a user), you can always bypass the whole aggregate repository and use whatever whatever appropriate read queries you need. Only, if your use case needs to manipulate data go through the aggregate repository to retrieve a full aggregate in order to make sure transactional consistency inside this aggregate as well as business rules are applied when changing said aggregate.
Also, it should be considered that if you do you have valid use cases where you would directly change (not read) an entity inside an aggregate without the need of considering business logic that needs to be owned by the parent aggregate root, you might have missed to discover this entity being modeled as an aggregate on it's own. See also, https://stackoverflow.com/a/67250062/7730554
We're building a microservices system with Axon Framework 4.1. In our domain, we have a label concept where we can attach labels to other entities. While labels are normally created and managed by the user, some of these labels are "special" and need to be hard-coded, but they need to be present in the event stream as well.
We have a bunch of aggregates that represent entities that can be labeled with these labels. Some of these aggregates will be used frequently, while others might be used infrequently or are even abandoned by the user.
Sometimes we come up with new special labels. We add them to the code, and then we also need to add them to the event stream. What is a good way to do that?
We can create a special command that we need to send when the updated service is started for the first time. It goes through all the labels and adds the ones that aren't in the event stream yet. This has two disadvantages. First, we need to actually send that command, which either requires us to not forget it, or to add some infrastructure for it outside of the code (e.g., in our build pipeline). Also, other services could have booted up faster with the new labels and started sending commands before we fired our special command. The other disadvantage is that this command will target all aggregates, including the abandoned ones, which could be wasteful of resources and be confusing to end users who might see activity in a document they thought was abandoned.
Ideally, we would like to be able to send the command when Axon has just loaded the aggregate. That way we would be certain that the labels are only introduced in aggregates that are actually used. Also, we could wire this up in code and it wouldn't require us to add infrastructure outside of the application and/or remember to do it manually.
Unfortunately, this feature doesn't seem to exist in Axon (yet) 😉.
Are there other (better) ways to achieve this?
I've got an idea which might help you out on this.
If I understand the use case correctly, the "Label" in your system, which user can introduce themselves but for which also a couple of hard-coded versions exist, is an Aggregate.
Based on that assumption, I suggest to be smart with the Aggregate Identifier you are using.
The sole thing that Axon expects from you, is that the Aggregate Identifier is (or can be made in to) a String. Typically a UUID is used for the Aggregate Identifiers, which is a reasonable first start.
You can however wrap this UUID in a typed-id object. Taking your "Label" Aggregate, that would opt for a LabelId.
That said, let's first go back to verifying whether a given "Label" Aggregate exists within the Event Stream.
The concern you have is rather valid I think; reading the entire Event Stream to figure out whether a given Aggregate instance exists is to big of a hassle.
However, the EventStore can be queried through two mechanism:
The Event Stream from a given point in time (e.g. what the TrackingToken mechanism does).
The Event Stream for a given Aggregate instance, based on the Aggregate Identifier.
It's the second option which is far more ideal in your scenario.
Just query the EventStore for a given "Label" Aggregate's Identifier. If you receive a non-empty Event Stream, you know it already exists.
Vice versa, if no Events are found, you are certain it's a new "Label" that needs to be introduced.
The crux here is in knowing the "Label's" Aggregate Identifier up front, which circles back to the String storage approach for the Aggregate Identifiers using a typed LabelId. What you could do, is deviate in the LabelId object between a custom "Label" (I'd opt for a UUID here) and a hard-coded "Label".
For the latter, you could for example have the label-name, plus a UUID/counter if desired.
Doing so will ensure that all the Events published from a hard-coded "Label" will have an Aggregate Identifier you can anticipate on during start-up.
Hope this is clear and all, if not, please comment on my response below.
Let's say we have a class Order (related to user) and it has property state. I want to prevent having more than one confirmed order in the same time so before I confirm any order I have to check if there is already some confirmed in it's time period.
I can make 2 approaches (I know of):
OrderRepository has a function changeState which search for conflicting confirmed orders before changing it and allows it only when nothing is found - the problem here is repository knows about logic of changing state.
OrderRespository is injected into Order and Order has function changeState which will use that repository to check for conflicts - here problem is the domain object know about persistence.
What is a right way to do?
Repositories are not in charge of domain invariants. Aggregates are. If no Aggregate has the needed info inside itself to check the invariant, try to question your aggregate design and maybe come up with a new one.
You can use a Domain Service, alternatively. As a weaker option, you could also degrade the domain invariant down to a simple use case precondition and have it checked by the Application Service/Command Handler. Note that the latter 2 options don't provide as strong a guarantee that domain entities will be in a consistent state at all times regarding that rule.
Another way to think about this would be from the point of view of a repository's responsibility. At the end of the day, a Repository is an abstraction to represent how to deal with a collection of objects, in your case, Orders.
Hence, it makes sense to keep rules around consistency and right state for the collection to be represented at the repository layer. Injecting repositories into entities is probably a code smell that something is not being modelled correctly. I'd go for your first version, but maybe you don't need to be specific about your state change, but simply embed those rules into the save() method. You can save the changes to an order iif there's no other confirmed at the same time.
As a matter of fact, Entities and even Value Objects may contain references to Aggregate Roots.
Additionally as per definition, Aggregate Roots stand on their own, the have intrinsically a Repository where I not at last could delete that Aggregate Root.
As a requirement of my GUI / Workflow, the customer wants to see where a particular Aggregate Root is referenced, not least because he wants / should be able to check whether he can delete that AR "safely".
My current design only has the navigation from the Entity in question towards the other AggregateRoot, so there's, at the moment, no simple way to find the opposite direction.
As this is surely not a single case, I wonder how this is done usually?
Addendum:
Consider the following example; we have an Address as Entity, and a Value Object HomeVisit containing date and Address address (just for the simplicity).
Until now, there is no modelling need to be able to navigate from Address to HomeVisit, even more since bidirectional associations are discouraged in general.
But you should see the use case now: For any reason I might need to be able to find out where an Address is currently used prior to delete or even modify it (maybe a service technician is currently on its way to that address and I need to be aware of that).
You can argue that for these cases there must be a Service or similar to find that out, but imagine there's a third party module which brings the HomeVisit VO and makes use of the Address somehow anonymously; at least that's the way I would like it to implement.
It seems like the answer is: via Domain or Application Services, involving respective Repositories whereas necessary.
So, the check for references has to be kinda hard-coded with an AddressService, having a method like deleteAddressByIdentifier. This method then needs to check or invoke a method isTechnicianOnWayToAddress() which again queries Repositories accordingly; or whatever is needed to fulfil the goal.