After reading Eric Evans' DDD, I'm trying to apply it to the project I'm managing. There are some user specific query data and I'm not really sure of how to implement this in a DDD way.
For example, if a user queries notices, the application should tell the user wether each post is read or not. Normally in such situations, I would respond with data that looks like following:
{
"notices": [
{"content": "foo", "is_read": true},
{"content": "bar", "is_read": false}
]
}
Suppose there is Notice entity and Read entity that saves wether a User has read it. Also assume that there are so many users reading the notice that retrieving all users for the is_read is not a efficient way.
Since Read entity is never queried without Notice entity, I could put it inside a Notice aggregate. Then implement query function taking the requesting user as parameter.
Or I could separate NoticeRepository and ReadRepository, query notices and then join them in the application layer with reads queried with notice ids.
The first option seems that it is assuming an user querying the notices and corrupting the domain layer with application logics. On the other hand, the second option gives me a feeling that I'm implementing a simple feature in an unnecessarily complicated way. And I cannot really think of other options right now.. What could be the best practice for such a case?
I cannot really think of other options right now
I can see two possible issues that could be tripping you up.
First, your domain model may be missing an important concept. How do we know if a Bob read a particular notification or not? There may be some entity in the domain, perhaps an Acknowledgement, that captures Bob, and the document that he read, and perhaps other information interesting to this domain (which version of the document did he read? When? What channel? when? and so on).
Thus, the view that would produce would look something like the list of active notifications left joined to the acknowledgements from Bob.
The other thing that could cross you up is that trying to do joins "by hand", using repositories to fetch data, is a real drag. Furthermore, what people have come to realize in the years since the blue book was written, it may not be necessary. Because queries are safe, they don't change the underlying data -- and if the underlying data isn't going to change, we don't really need a domain model to protect a business invariant.
This need to go all in a Query Service,
The book of Eric Evans is good basis and it has evolved to more modern patterns now, for instance CQRS in the book of Vaughn Vernon, Implementing Domain Driven Design (IDDD).
Your query service would be responsible of displaying a list of notices, updating a read column for this user in a separate table.
You might have a look at some example of query services (written in java) here:
https://github.com/VaughnVernon/IDDD_Samples/blob/master/iddd_collaboration/src/main/java/com/saasovation/collaboration/application/forum/ForumQueryService.java
https://github.com/VaughnVernon/IDDD_Samples/blob/master/iddd_collaboration/src/main/java/com/saasovation/collaboration/application/forum/DiscussionQueryService.java
I wouldn't have a Read entity. Just Notice and User. In User you would have a list of Notice ids that the user has read (or viceversa, in Notice you would have a list of the User ids who have read the Notice).
Then , to query the info you need to show in the user interface, you have several alternatives, as Vaughn Vernon says in his book Implementing DDD (page 512):
DTOs
Mediator
Domain Payload Object
State Representations
Use Case optimal repository queries (closed to CQRS)
Data Transformers
Related
I am confused about how to treat strictly UI-related things, that won't be used in the business logic in the domain model: how to properly store them in the database?
If for example I have an aggregate which is an entity and the main purpose of this model is to do something with an important thing, should I include a title in the model even though it does not contribute to the business logic in any way? Does it matter if I want to store the title in the same table I store other data for my entity (e.g. important things)?
#Entity
MyAggregate:
id: ID
title: str
importantThing: ImportantThing
def doSomethingWithImportantThing():
...
And if I don't include a title in the model, then how to properly store it using Repository pattern? If I keep the title within my model my Repository could look like so:
#Repository
MyAggregateRepository:
def create(myAggregate: MyAggregate):
...
What would happen to repository if I remove title from the model? Should it transform like so:
#Repository
MyAggregateRepository:
def create(myAggregate: MyAggregate, title: str):
...
The rule of thumb is to keep only things that are necessary for making decisions and protecting invariants inside the aggregate state. Otherwise, aggregates get polluted by alien concerns and convert to a messy one-to-one representation of an over-growing database table or document.
As any rule, it has exceptions. I don't think it's a good idea going overboard from the start and splitting the entity prematurely.
However, if you feel that things get messy and you can see patterns that a group of fields are used in a group of functions, while another group of fields is solely used in a different set of functions, you might get an idea that your aggregate deserves splitting.
The repository pattern is largely relevant for executing commands. Its main purpose is to handle the aggregate persistence. When implementing queries, consider using CQRS and write queries that you need to write, it doesn't have to be the repository that handles queries. Queries are also idempotent and have no side effect (except the performance), so it is rather safe not to think about the domain model as such when writing queries. It's better to name your queries using the Ubiquitous Language though.
Things that are purely UI-related typically don't belong in the domain unless the domain is related to managing UI-related items, such as in the case of a localisation domain.
Data that belongs in the domain would stay in the domain. For instance, if there is a comment on an AccountTransaction, or some such, then that would be in the language used by the users of the system and not something that one could localize. However, if that transaction has a Type indicator that is either Debit or Credit then you wouldn't want to necessarily use a string representation but rather codify that; even if the "code" is Debit and Credit or Dr/Cr. However, the front-end would use some l10n or i18n mechanism to display the text for the Type in the relevant language.
Hopefully I understood your question correctly.
Keep title within the bounds of your model. There are a few reasons for this.
The utility of title is kept within the bounds of the model itself, since it does not serve any other purpose in the domain layer. It serves as "identity" that is merely local to the model itself, and then gets surfaced in the UI.
The title is not necessary for creating the aggregate, since it has no business logic intent. If it did, it would represent a tighter coupling between the model and the creation of the aggregate, which is typically undesirable.
title seems to be an aggregate invariant that you'd only want the aggregate root to be concerned with, and not a concern from a perspective of external access or creation.
Ultimately, this keeps your design cleaner.
No, it is not a duplication question.
I have red many sources on the subject, but still I feel like I don't fully understand it.
This is the information I have so far (from multiple sources, be it articles, videos, etc...) about what is an Aggregate and Aggregate Root:
Aggregate is a collection of multiple Value Objects\Entity references and rules.
An Aggregate is always a command model (meant to change business state).
An Aggregate represents a single unit of (database - because essentialy the changes will be persisted) work, meaning it has to be consistent.
The Aggregate Root is the interface to the external world.
An Aggregate Root must have a globally unique identifier within the system
DDD suggests to have a Repository per Aggregate Root
A simple object from an aggregate can't be changed without its AR(Aggregate Root) knowing it
So with all that in mind, lets get to the part where I get confused:
in this site it says
The Aggregate Root is the interface to the external world. All interaction with an Aggregate is via the Aggregate Root. As such, an Aggregate Root MUST have a globally unique identifier within the system. Other Entites that are present in the Aggregate but are not Aggregate Roots require only a locally unique identifier, that is, an Id that is unique within the Aggregate.
But then, in this example I can see that an Aggregate Root is implemented by a static class called Transfer that acts as an Aggregate and a static function inside called TransferedRegistered that acts as an AR.
So the questions are:
How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that its a function. what does have a globaly unique identifier is the Domain Event that this function produces.
Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function of the Aggregate class itself?
In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier), then how can we interact with this Aggregate? the first article clearly stated that all interaction with an Aggregate is by the AR, if the AR is an event, then we can do nothing but react on it.
Is it right to say that the aggregate has two main jobs:
Apply the needed changes based on the input it received and rules it knows
Return the needed data to be persisted from AR and/or need to be raised in a Domain Event from the AR
Please correct me on any of the bullet points in the beginning if some/all of them are wrong is some way or another and feel free to add more of them if I have missed any!
Thanks for clarifying things out!
I feel like I don't fully understand it.
That's not your fault. The literature sucks.
As best I can tell, the core ideas of implementing solutions using domain driven design came out of the world of Java circa 2003. So the patterns described by Evans in chapters 5 and six of the blue book were understood to be object oriented (in the Java sense) domain modeling done right.
Chapter 6, which discusses the aggregate pattern, is specifically about life cycle management; how do you create new entities in the domain model, how does the application find the right entity to interact with, and so on.
And so we have Factories, that allow you to create instances of domain entities, and Repositories, that provide an abstraction for retrieving a reference to a domain entity.
But there's a third riddle, which is this: what happens when you have some rule in your domain that requires synchronization between two entities in the domain? If you allow applications to talk to the entities in an uncoordinated fashion, then you may end up with inconsistencies in the data.
So the aggregate pattern is an answer to that; we organize the coordinated entities into graphs. With respect to change (and storage), the graph of entities becomes a single unit that the application is allowed to interact with.
The notion of the aggregate root is that the interface between the application and the graph should be one of the members of the graph. So the application shares information with the root entity, and then the root entity shares that information with the other members of the aggregate.
The aggregate root, being the entry point into the aggregate, plays the role of a coarse grained lock, ensuring that all of the changes to the aggregate members happen together.
It's not entirely wrong to think of this as a form of encapsulation -- to the application, the aggregate looks like a single entity (the root), with the rest of the complexity of the aggregate being hidden from view.
Now, over the past 15 years, there's been some semantic drift; people trying to adapt the pattern in ways that it better fits their problems, or better fits their preferred designs. So you have to exercise some care in designing how to translate the labels that they are using.
In simple terms an aggregate root (AR) is an entity that has a life-cycle of its own. To me this is the most important point. One AR cannot contain another AR but can reference it by Id or some value object (VO) containing at least the Id of the referenced AR. I tend to prefer to have an AR contain only other VOs instead of entities (YMMV). To this end the AR is responsible for consistency and variants w.r.t. the AR. Each VO can have its own invariants such as an EMailAddress requiring a valid e-mail format. Even if one were to call contained classes entities I will call that semantics since one could get the same thing done with a VO. A repository is responsible for AR persistence.
The example implementation you linked to is not something I would do or recommend. I followed some of the comments and I too, as one commenter alluded to, would rather use a domain service to perform something like a Transfer between two accounts. The registration of the transfer is not something that may necessarily be permitted and, as such, the domain service would be required to ensure the validity of the transfer. In fact, the registration of a transfer request would probably be a Journal in an accounting sense as that is my experience. Once the journal is approved it may attempt the actual transfer.
At some point in my DDD journey I thought that there has to be something wrong since it shouldn't be so difficult to understand aggregates. There are many opinions and interpretations w.r.t. to DDD and aggregates which is why it can get confusing. The other aspect is, in IMHO, that there is a fair amount of design involved that requires some creativity and which is based on an understanding of the domain itself. Creativity cannot be taught and design falls into the realm of tacit knowledge. The popular example of tacit knowledge is learning to ride a bike. Now, we can read all we want about how to ride a bike and it may or may not help much. Once we are on the bike and we teach ourselves to balance then we can make progress. Then there are people who end up doing absolutely crazy things on a bike and even if I read how to I don't think that I'll try :)
Keep practicing and modelling until it starts to make sense or until you feel comfortable with the model. If I recall correctly Eric Evans mentions in the Blue Book that it may take a couple of designs to get the model closer to what we need.
Keep in mind that Mike Mogosanu is using a event sourcing approach but in any case (without ES) his approach is very good to avoid unwanted artifacts in mainstream OOP languages.
How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that
its a function. what does have a globaly unique identifier is the
Domain Event that this function produces.
TransferNumber acts as natural unique ID; there is also a GUID to avoid the need a full Value Object in some cases.
There is no unique ID state in the computer memory because it is an argument but think about it; why you want a globaly unique ID? It is just to locate the root element and its (non unique ID) childrens for persistence purposes (find, modify or delete it).
Order A has 2 order lines (1 and 2) while Order B has 4 order lines (1,2,3,4); the unique identifier of order lines is a composition of its ID and the Order ID: A1, B3, etc. It is just like relational schemas in relational databases.
So you need that ID just for persistence and the element that goes to persistence is a domain event expressing the changes; all the changes needed to keep consistency, so if you persist the domain event using the global unique ID to find in persistence what you have to modify the system will be in a consistent state.
You could do
var newTransfer = New Transfer(TransferNumber); //newTransfer is now an AG with a global unique ID
var changes = t.RegisterTransfer(Debit debit, Credit credit)
persistence.applyChanges(changes);
but what is the point of instantiate a object to create state in the computer memory if you are not going to do more than one thing with this object? It is pointless and most of OOP detractors use this kind of bad OOP design to criticize OOP and lean to functional programming.
Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function
of the Aggregate class itself?
It is the function itself. You can read in the post:
AR is a role , and the function is the implementation.
An Aggregate represents a single unit of work, meaning it has to be consistent. You can see how the function honors this. It is a single unit of work that keeps the system in a consistent state.
In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier),
then how can we interact with this Aggregate? the first article
clearly stated that all interaction with an Aggregate is by the AR, if
the AR is an event, then we can do nothing but react on it.
Answered above because the domain event is not the AR.
4 Is it right to say that the aggregate has two main jobs: Apply the
needed changes based on the input it received and rules it knows
Return the needed data to be persisted from AR and/or need to be
raised in a Domain Event from the AR
Yes; again, you can see how the static function honors this.
You could try to contat Mike Mogosanu. I am sure he could explain his approach better than me.
I have a web application with news posts. Those news posts should be searchable. In context of DDD what kind of buililng block are search query and search result?
These are my thoughts
They both don't have identity, therefore they are not Entities. But the absence of identity doesn't imply they are Value Object. As Eric Evans states:
However, if we think of this category of object as just the absence of identity, we haven't added much to our toolbox or vocabulary. In fact, these objects have characteristics of their own and their own significance to the model. These are the objects that describe things.
I would like to say that both are value objects, but I'm not sure. What confuses me are examples that I've found on Internet. Usualy value object are part of other entities, they are not "standalone". Martin Fowler gives for example Money or date range object. Adam Bien event compares them to enums.
If search result would be considered value object, that would be value object that consists of entities. I'm not sure that's completely alright.
I don't think they are DataTransferObject. Because we are not current concerned with transferring data between layers, but we are concerned with their meaning for the model in absence of layer.
I don't think search query is command. Because it's not a request for change.
As stated on CQRS
People request changes to the domain by sending commands.
I'm trying to use and learn DDD, can someone clarify this problem to me? Where did I go wrong with reasoning?
The simple answer is that querying is probably not part of your domain. The domain model is not there to serve queries, it is there to enforce invariants in your domain. Since by nature queries are read-only, there are no invariants to enforce, so why complicate things? I think where people usually go wrong with DDD is that they assume since they are "doing DDD" every aspect of the system must be handled by a domain model. DDD is there to help with the complex business rules and should only be applied when/where you actually have them. Also, you can and probably should have many models to support each bounded context. But that's another discussion.
It's interesting that you mention CQRS because what does that stand for? Command query responsibility segregation. So if commands use the domain model, and query responsibility is segregated from that, what does that tell you to do? The answer is, do whatever is easiest to query and display that data. If select * from news table filled to dataset works, go with that. If you prefer entity framework, go with that. There is no need to get the domain model involved for queries.
One last point I'd like to make is I think a lot of people struggle with DDD by applying it to situations where there aren't many business invariants to enforce and the domain model ends up looking a lot like the database. Be sure you are using the right tool for the job and not over complicating things. Also, you should only apply DDD in the areas of your system where these invariants exist. It's not an all or nothing scenario.
I'm currently designing a backend for a social networking-related application in REST. I'm very intrigued by the DDD principle. Now let's assume I have a User object who has a Collection of Friends. These can be thousands if the app and the user would become very successful. Every Friend would have some properties as well, it is basically a User.
Looking at the DDD Cargo application example, the fully expanded Cargo-object is stored and retrieved from the CargoRepository from time to time. WOW, if there is a list in the aggregate-root, over time this would trigger a OOM eventually. This is why there is pagination, and lazy-loading if you approach the problem from a data-centric point of view. But how could you cope with these large collections in a persistence-unaware DDD?
As #JefClaes mentioned in the comments: You need to determine whether your User AR indeed requires a collection of Friends.
Ownership does not necessarily imply that a collection is necessary.
Take an Order / OrderLine example. An OrderLine has no meaning without being part of an Order. However, the Customer that an Order belongs to does not have a collection of Orders. It may, possibly, have a collection of ActiveOrders if a customer is limited to a maximum number (or amount) iro active orders. Keeping a collection of historical orders would be unnecessary.
I suspect the large collection problem is not limited to DDD. If one were to receive an Order with many thousands of lines there may be design trade-offs but the order may much more likely be simply split into smaller orders.
In your case I would assert that the inclusion / exclusion of a Friend has very little to do with the consistency of the User AR.
Something to keep in mind is that as soon as you start using you domain model for querying your start running into weird sorts of problems. So always try to think in terms of some read/query model with a simple query interface that can access your data directly without using your domain model. This may simplify things.
So perhaps a Relationship AR may assist in this regard.
If some paging or optimization techniques are the part of your domain, it's nothing wrong to design domain classes with this ability.
Some solutions I've thought about
If User is aggregate root, you can populate your UserRepository with method GetUserWithFriends(int userId, int firstFriendNo, int lastFriendNo) encapsulating specific user object construction. In same way you can also populate user model with some counters and etc.
On the other side, it is possible to implement lazy loading for User instance's _friends field. Thus, User instance can itself decide which "part" of friends list to load.
Finally, you can use UserRepository to get all friends of certain user with respect to paging or other filtering conditions. It doesn't violate any DDD principles.
DDD is too big to talk that it's not for CRUD. Programming in a DDD way you should always take into account some technical limitations and adapt your domain to satisfy them.
Do not prematurely optimize. If you are afraid of large stress, then you have to benchmark your application and perform stress tests.
You need to have a table like so:
friends
id, user_id1, user_id2
to handle the n-m relation. Index your fields there.
Also, you need to be aware whether friends if symmetrical. If so, then you need a single row for two people if they are friends. If not, then you might have one row, showing that a user is friends with the other user. If the other person considers the first a friend as well, you need another row.
Lazy-loading can be achieved by hidden (AJAX) requests so users will have the impression that it is faster than it really is. However, I would not worry about such problems for now, as later you can migrate the content of the tables to a new structure which is unkown now due to the infinite possible evolutions of your project.
Your aggregate root can have a collection of different objects that will only contain a small subset of the information, as reference to the actual business objects. Then when needed, items can be used to fetch the entire information from the underlying repository.
Background
Udi Dahan suggests a fetching strategy as a useful pattern to use for data access. I agree.
The concept is to make roles explicit. For example I have an Aggregate Root - Customer. I want customer in several parts of my application - a list of customers to select from, a view of the customer's details, and I want a button to deactivate a customer.
It seems Udi would suggest an interface for each of these roles. So I have ICustomerInList with very basic details, ICustomerDetail which includes the latest 10 products purchased, and IDeactivateCustomer which has a method to deactivate the customer. Each interface exposes just enough of my Customer Aggregate Root to get the job done in each situation. My Customer Aggregate Root implements all these interfaces.
Now I want to implement a fetching strategy for each of these roles. Each strategy can load a different amount of data into my Aggregate Root because it will be behind an interface exposing only the bits of information needed.
The general method to implement this part is to ask a Service Locator or some other style of dependency injection. This code will take the interface you are wanting, for example ICustomerInList, and find a fetching strategy to load it (IStrategyForFetching<ICustomerInList>). This strategy is implemented by a class that knows to only load a Customer with the bits of information needed for the ICustomerInList interface.
So far so good.
Question
What you pass to the Service Locator, or the IStrategyForFetching<ICustomerInList>. All of the examples I see are only selecting one object by a known id. This case is easy, the calling code passes this id through and will get back the specific interface.
What if I want to search? Or I want page 2 of the list of customers? Now I want to pass in more terms that the Fetching Strategy needs.
Possible solutions
Some of the examples I've seen use a predicate - an expression that returns true or false if a particular Aggregate Root should be part of the result set. This works fine for conditions but what about getting back the first n customers and no more? Or getting page 2 of the search results? Or how the results are sorted?
My first reaction is to start adding generic parameters to my IStrategyForFetching<ICustomerInList> It now becomes IStrategyForFetching<TAggregateRoot, TStrategyForSelecting, TStrategyForOrdering>. This quickly becomes complex and ugly. It's further complicated by different repositories. Some repositories only supply data when using a particular strategy for selecting, some only certain types of ordering. I would like to have the flexibility to implement general repositories that can take sorting functions along with specialised repositories that only return Aggregate Roots sorted in a particular fashion.
It sounds like I should apply the same pattern used at the start - How do I make roles explicit? Should I implement a strategy for fetching X (Aggregate Root) using the payload Y (search / ordering parameters)?
Edit (2012-03-05)
This is all still valid if I'm not returning the Aggregate Root each time. If each interface is implemented by a different DTO I can still use IStrategyForFetching. This is why this pattern is powerful - what does the fetching and what is returned doesn't have to map in any way to the aggregate root.
I've ended up using IStrategyForFetching<TEntity, TSpecification>. TEntity is the thing I want to get, TSpecification is how I want to get it.
Have you come across CQRS? Udi is a big proponent of it, and its purpose is to solve this exact issue.
The concept in its most basic form is to separate the domain model from querying. This means that the domain model only comes into play when you want to execute a command / commit a transaction. You don't use data from your aggregates & entities to display information on the screen. Instead, you create a separate data access service (or bunch of them) that contain methods that provide the exact data required for each screen. These methods can accept criteria objects as parameters and therefore do searching with whatever criteria you desire.
A quick sequence of how this works:
A screen shows a list of customers that have made orders in the last week.
The UI calls the CustomerQueryService passing a date as criteria.
The CustomerQueryService executes a query that returns only the fields required for this screen, including the aggregate id of each customer.
The user chooses a customer in the list, and chooses perform the 'Make Important Customer' action /command.
The UI sends a MakeImportantCommand to the Command Service (or Application Service in DDD terms) containing the ID of the customer.
The command service fetches the Customer aggregate from the repository using the ID passed in the command, calls the necessary methods and updates the database.
Building your app using the CQRS architecture opens you up to lot of possibilities regarding performance and scalability. You can take this simple example further by creating separate query databases that contain denormalised tables for every view, eventual consistency & event sourcing. There is a lot of videos/examples/blogs about CQRS that I think would really interest you.
I know your question was regarding 'fetching strategy' but I notice that he wrote this article in 2007, and it's likely that he considers CQRS its sucessor.
To summarise my answer:
Don't try and project cut down DTO's from your domain aggregates. Instead, just create separate query services that give you a tailored query for your needs.
Read up on CQRS (if you haven't already).
To add to the response by David Masters, I think all the fetching strategy interfaces are adding needless complexity. Having the Customer AR implement the various interfaces which are modeled after a UI is a needless constraint on the AR class and you will spend far to much effort trying to enforce it. Moreover, it is a brittle solution. What if a view requires data that while related to Customer, does not belong on the customer class? Does one then coerce the customer class and the corresponding ORM mappings to contain that data? Why not just have a separate set of classes for query purposes and be done with it? This allows you to deal with fetching strategies at the place where they belong - in the repository. Furthermore, what value does the fetching strategy interface abstraction really add? It may be an appropriate model of what is happening in the application, it doesn't help in implementing it.