When looking at the post "Should Entities in Domain Driven Design and Entity Framework be the same?" the accepted answer states that domain entities and EF Entities can only be the same when using code first. This so that the entities can remain "pure".
However, because of this inpediment: "Discussion on many-to-Many relationships (without CLR class for join table)" it is not possible to create an order entity with a collection of product entities without specifying a special entity for the association table (orderline entity).
I now see colleagues taking these association tables into their domain entities and i feel that is wrong because it hints towards coping with persistence and not towards being true to the domain. They are not "pure" anymore in my opinion.
Would you say that it is impossible to have the same Domain entities in EF Core because of the association table entities? How can i cope with this in EF Core?
But in a regular/classic Ordering domain there is a need for an orderline (or order-line-item or whatever you want to call it) because you need to store the quantity and the item price along the product ID.
In most DDD examples this item is a Value object from the DDD point of view and an Entity from the Persistence point of view. If you are wondering how a Value object could be an ORM Entity you should read Persisting Value Objects from the book Implementing Domain Driven Design by Vaughn Vernon.
There are, however cases when the Domain model does not fit 100% percent with the Persistence model. In such cases one needs to attach some meta information to the Domain models in order to match the Persistence models. In general you have two options:
you can add the metadata to some external files, like XML-files;
it has the advantage that it keeps the Domain model agnostic in regard to the persistence but
it has the disadvantage that one must remember to change the external files when the Domain model changes
you can annotate the Domain models
it has the advantage that it is easy to change at the same time the Domain model and the Persistence model by having the information in the same file; it follows the principle: "things that change together stay together" (Common Closure Principle)
it has the disadvantage that it pollutes the Domain model with Infrastructure concerns
If I have to choose, I tend to choose to annotate the Domain models, but you should make that decision by yourself.
Related
I thinking about modeling aggregates, invariants, data etc. There is common advice to design aggregates to be small. I have problem a with correct splitting domain and simple CRUD.
Let's assume that we have application where we are able to create project and join to it collaborators. There are a lot of informations related with project at the stage of creating (name, description, project_aims, notes, creation date, modified date, collaborators). How to correct design aggregate where there is a rule which check that we can only add 5 collaborators. Taking into consideration that fields name, description, project_aims, notes doesn't really take part in any business rule and there is only requirements that this fields should'nt be empty (those are really invariants?) should those fields really be a part of aggregate?
Is'nt that our real Domain (aggregates, entities, value objects, policies) should hold only data which take part with protecting invariants or help making business decisions?
If so, how to (create) project described above? Should class with all that nonsignificant (from a business point of view) fields be implemented as anemic model outside the Domain and Aggregate root should just have method addCollaborator which protect quantity of collaborators? Is it good idea to save anemic class object using Dao (operates on db table) and for Domain implementation of aggregate, create Repository?
How to add first collaborator during creating project as at the beggining we create anemic class object outside Domain?
Thank you for any help and advice
Papub
"How to correct design aggregate where there is a rule which check that we can only add 5 collaborators"
Project AR most likely maintains a set of collaborators and throws whenever it's size would exceed 5.
"there is only requirements that this fields should'nt be empty (those are really invariants?)"
Yes, these may be simple rules, but are still are invariants.
"should hold only data which take part with protecting invariants or help making business decisions"
This can be done when modeling ARs with EventSourcing, where you'd only materialize the properties needed to check invariants on the AR, while having all data in the full set of events.
"implemented as anemic model outside the Domain and Aggregate root should just have method addCollaborator which protect quantity of collaborators".
You could always attempt to mix CRUD-driven anemia with rich always-valid models, but the anemic/rich model decision is usually consistent for a given Bounded Context (BC), meaning you may have CRUDDy BCs and rich domain model BCs, but rarely both strategies in the same BC.
For instance, perhaps "Project Definition" is a CRUD-driven BC while "Collaboration" isin't. Those BCs may not make any sense, but it's just to give an example.
Furthermore, don't forget DDD tactical patterns are there to allow manage the complexity, they aren't hard rules. If handling a part of your AR through services and another (where there's more meat) with rich behaviors then perhaps that's acceptable. Still, I'd probably prefer CRUDDy behaviors on the ARs themselves like an update method rather than giving up in the anemic direction.
While i am practicing DDD in my software projects, i have always faced the question of "Why should i implement my business rules in the entities? aren't they supposed to be pure data models?"
Note that, from my understanding of DDD, domain models could be consist of persistent models as well as value objects.
I have come up with a solution in which i separate my persistent models from my domain models. On the other hand we have data transfer objects (DTO), so we have 3 layers of data mapping. Database to persistence model, persistence model to domain models and domain models to DTOs. In my opinion, my solution is not an efficient one as too much hard effort must be put into it.
Therefore is there any better practice to achieve this goal?
Disclaimer: this answer is a little larger that the question but it is needed to understand the problem; also is 100% based on my experience.
What you are feeling is normal, I had the same feeling some time ago. This is because of a combination of architecture, programming language and used framework. You should try to choose the above tools as such that they give the code that is easiest to change. If you have to change 3 classes for each field added to an entity then this would be nightmare in a large project (i.e. 50+ entity types).
The problem is that you have multiple DTOs per entity/concept.
The heaviest architecture that I used was the Classic layered architecture; the strict version was the hardest (in the strict version a layer may access only the layer that is just before it; i.e. the User interface may access only the Application). It involved a lot of DTOs and translations as the data moved from the Infrastructure to the UI. The testing was also hard as I had to use a lot of mocking.
Then I inverted the dependency, the Domain will not depend on the Infrastructure. For this I defined interfaces in the Domain layer that were implemented in the Infrastructure. But I still needed to use mocking for them. Also, the Aggregates were not pure and they had side effects (because they called the Infrastructure, even it was abstracted by interfaces).
Then I moved the Domain to the very bottom. This made my Aggregates pure. I no longer needed to use mocking. But I still needed DTOs (returned by the Application layer to the UI and those used by the ORM).
Then I made the first leap: CQRS. This splits the models in two: the write model and the read model. The important thing is that you don't need to use DTOs for models anymore. The Aggregate (the write model) can be serialized as it is or converted to JSON and stored in almost any database. Vaughn Vernon has a blog post about this.
But the nicest are the Read models. You can create a read model for each use case. Being a model used only for read/query, it can be as simple/dump as possible. The read entities contain only query related behavior. With the right persistence they can be persisted as they are. For example, if you use MongoDB (or any document database), with a simple reflection based serializer you can have a very thin architecture. Thanks to the domain events, you won't need to use JOINS, you can have full data denormalization (the read entities include all the data they need).
The second leap is Event sourcing. With this you don't need a flat persistence for the Aggregates. They are rehydrated from the Event store each time they handle a command.
You still have DTOs (commands, events, read models) but there is only one DTO per entity/concept.
Regarding the elimination of DTOs used by the Presentation: you can use something like GraphSQL.
All the above can be made worse by the programming language and framework. Strong typed programming languages force you to create a type for each custom returned value. Some frameworks force you to return a custom serializable type in order to return them to REST over HTTP requests (in this way you could have self-described REST endpoints using reflection). In PHP you can simply use arrays with string keys as value to be returned by a REST controller.
P.S.
By DTO I mean a class with data and no behavior.
I'm not saying that we all should use CQRS, just that you should know that it exists.
Why should i implement my business rules in the entities? aren't they supposed to be pure data models?
Your persistence entities should be pure data models. Your domain entities describe behaviors. They aren't the same thing; it is a common pattern to have a bit of logic with in the repository to change one to the other.
The cleanest way I know of to manage things is to treat the persistent entity as a value object to be managed by the domain entity, and to use something like a data mapper for transitions between domain and persistence.
On the other hand we have data transfer objects (DTO), so we have 3 layers of data mapping. Database to persistence model, persistence model to domain models and domain models to DTOs. In my opinion, my solution is not an efficient one as too much hard effort must be put into it.
cqrs offers some simplification here, based on the idea that if you are implementing a query, you don't really need the "domain model" because you aren't actually going to change the supporting data. In which case, you can take the "domain model" out of the loop altogether.
DDD and data are very different things. The aggregate's data (an outcome) will be persisted somehow depending on what you're using. Personally I think in domain events so the resulting Domain Event is the DTO (technically it is) that can be stored directly in an Event Store (if you're using Event Sourcing) or act as a data source for your persistence model.
A domain model represents relevant domain behaviour with the domain state being the 'result'. An entity is concept which has an id, compared to a Value Object which represents a business semantic value only. An entity usually groups related value objects and consistency rules. Not all business rules are here , some of them make sense as a service.
Now, there is the case of a CRUD domain or CRUD modelling where basically all you have is some data structures plus some validation rules. No need to complicate your life here if the modeling is correct. Implement things as simple as possible.
Always think of DDD as a methodology to gather requirements and to structure information. Implementation as in code (design) is something different.
Is it ok for my aggregate root to act as a factory for entities that he manages?
E.G: is it ok for my aggregate root "Question" to instantiate a entity "Answer"?
Is it ok for my aggregate root to act as a factory for entities that he manages?
Almost.
The aggregate root isn't an entity as such, but a role played by an entity. Think interface - it gives the application a restricted access to the domain model, encapsulating the actual implementation.
It's natural to have the aggregate be responsible for its own state; after all, all of the components of the aggregate are going to be drawn from the same data model (they are persisted together).
Within your entity (which is acting as the aggregate root), you want your code to align as closely as possible with the language of the domain. That will usually mean that you don't have a "factory", as in the design pattern, but instead have some entity in the model that produces the managed entities.
Udi Dahan touched on this, somewhat obliquely, when he wrote Don't Create Aggregate Roots.
Customers don’t just appear out of thin air.
The entities in your model all come from other entities in your model. Turtles all the way down.
So introducing the factory design pattern into the domain language is a bit sketch.
Because the domain model lives in memory... because its unusual for the domain model to have side effects... a lot of the usual motivations for abstracting connection points don't apply. If you find yourself, for example, wanting to inject a mock into your domain model for unit testing, then something has gone badly wrong (into domain services, yes, but not into entities).
Yes, it is, if the code is a simple new Answer (someArguments, ...).
If it is a more complicated process then you should extract this code into a AnswerFactory class.
EDIT:
The desire to create a clean code dictates this and not DDD. A rule from DDD that is relevant to your question is that Domain (so all classes from the Domain layer) should not depend on any other layers (like Infrastructure or Application).
I have some big Entity. Entity has propertis "Id", "Status" and others.
I have Repository for this Entity.
I want to change status in one entity.
Should I get whole Entity, change property Status and use save method in Repository or should I use method ChangeStatus(id, newStatus) in Repository?
Probably you don't need a domain model. You could try a transaction script that directly use SQL to update the database.
You need a domain model if and only if you need to hire an expert to understand the business.
Otherwise, it's just expensive buzzwords driven development.
And btw, if you have big entity classes containing data that you don't need during most of operations, then you know that you haven't properly defined context boundaries.
The best definition of bounded context is the one of Evans:
The delimited applicability of a particular model. BOUNDING CONTEXTS gives team members a clear and shared understanding of what has to be consistent and what can develop independently.
That is: you have to split the domain expert knowledge in contexts where each term has an unambiguous meaning and a restricted set of responsibility. If you do so, you'll obtain small types and modules with high cohesion an
What is the difference between a domain model and a data model?
A datamodel is a design model that only describes data and it's relations. The model contains entities, but they are described in terms of what data they own not how they act on this data or what their responsibilities are.
An domain model on the other hand, is a conceptual model used in analysis of a problem domain. It describes the domain in terms of entities that have relations, data and behaviour. It describes the responsibilities of those entities as relevant for understanding the problem domain.
BTW an excelent and very short introduction to UML is:
UML Distilled: A Brief Guide to the Standard Object Modeling Language
A data model is focused on the DB schema definition, including tables, columns, and relationships.
A domain model is focused on the business domain, including concepts (classes of objects), behavior (methods/logic), and relationships.
In both cases, the cardinality is used for relationships (e.g. 1:1, 1:Many, 0:Many, ...).
That said, you would ideally like the data model and domain model to be closely related, i.e. a Person with name, ... and a MailingAddress, ... relates to a PERSON table with a NAME column and a FK to a MAILING_ADDR table entry. You have to decide where logic is hosted - in the objects in the software system vs. in the DB via procedures, triggers, and such.
I think it's important to provide some clarity here for posterity.
A data model is a design for how to structure and represent information. By structure, I mean concerns like "fifth normal form". By representation, I mean choosing a computer serialization, such as integer, floating point, or string.
The term domain model actually has two conflated meanings.
A model of essential characteristics of real or imaginary things in the world. In this kind of model, classes represent human conceptualizations and instances are things in the world. For example, a "Person" class would have instances including you and me, and an essential characteristic might be that every Person has a mother. This kind of model is often called an conceptual ontology or concept model and is intended to provide meaning.
A model of required information about things in the world, usually with some system in mind. In this kind of model, classes represent information that must be stored about things in the world. For example, a "Person" class would have instances representing required information about you and me, such as first name, last name, date of birth, current height, and current weight. This information often does not include all essential characteristics, such as our mothers, because, for the purposes of a particular system, that information is not required. This kind of model is often called an information model, conceptual data model, or operational ontology.
Both the UML and OWL languages can be used to represent either kind of domain model. Both can be considered analysis models, as they are used to analyze a domain. One is used to understand things in a domain, the other is used to gather requirements to build a particular software or database system for things in a domain. Both are necessary, and, unfortunately, they are usually conflated such that people building an analysis model are themselves confused about what they are modeling!
I think that domain model and data model are now pretty much the same with new top down modelling technologies. I mean that you can model in a class diagram and only add database stereotypes in your diagram. If you use the tool that I use then your ejb3 annotation would be immediately synchronized with your code. The next step is only to use a mapper to create your database. This technology only works with Java