We're refactoring our solution to a Domain Driven Design structure. Our consultants which implement the software, should be able to customize some behavior of the application (for specific customers needs). For example they want to add custom defined properties to the presentation (user input forms) and save the custom data together with the entities defined in our DDD projects.
However, the domain objects should preferably not contain a customData property. I don't want to mix those and let the domain object know that there's something like custom data. I'm saving en fetching the entities by Repositories.
How do I make this scenario possible? One possible solution would be:
Query the entity by using his Repository
And query separately the CustomPropertiesRepository by entity ID.
Combine the two queries objects.
When saving the forms. It will be splitted again using two repositories
The disadvantage of this, is that I have to query twice though it should be one document.
Any advice on this problem?
in general dynamic properties are better suited for data-centric design and in my opinion this practice is not suitable for DDD.
in DDD the code must reflect the knowledge of the domain, it must be simple and explicit.
before thinking of the best way to persist a dynamic property, you must solve the problem at the design level:
1-There are three possible artifacts for a property: aggregate root, entity or object value.
2-usually a dynamic property brings with it a functional need (calculation, validation ... etc), where you will implement this functionality? whether in the aggregate root or in a domain service you will be compelled to compile your code and here the dynamic propriety loses its meaning, unless you think use a Business rules engine, and there you introduce another new paradigm with its whole complication, and some of your business logic would be outside aggregates and domain services.
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.
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
I'm working a pretty standard e-commerce web site where there are Products and Categories. Each product has an associated category, which is a simple name-value pair object used to categorise a product (e.g. item 1234 may have a category "ballon").
I modelled the product as a root aggregate, which owns and knows how to modify it's category, which is an entity.
However, I ran into a problem where a user needs to be able to search a category. How am I supposed to implement this in DDD? I'm new to DDD but I believe that only root aggregates should be given it's own repository. So that leaves me with 2 options:
Add "SearchCategory" method to the ProductRepository
Implement the search logic as service (i.e. CategoryFinderService)
I personally think option 2 is more logical but it feels weird to have a service that touches database. Somehow I feel that only repository should be allowed to interact with database.
Can someone please tell me what's the best way to implement this?
IMHO, in your Domain Model, Category should not be child of the Product Aggregation. The Product has a Category, but it does not know how to create or edit a Category.
Take this another example. Imagine the ShoppingCart class, it's an aggregate root and contains a list of Items. The ShoppingCart is responsible for adding/editing/removing the Items, in this case you won't need a Repository for the Item class.
Not sure by the way, I'm new to this just like you.
Placing something You don't know where to put into artificial services usually leads to anemic domain model.
I would go with first option. But need for entities without context of root is a sign that You might lack another root.
Don't try to implement everything with your domain model. The domain model is powerful for changing the state of the system, but unnecessary complex for querying. So separate the two. It's called Command Query Responsibility Segregation, or CQRS. And no, it has nothing to do with Event Sourcing, even though they do work nicely together.
I implement scenarios such as this so that I have a domain logic side with the domain objects and repositories (if needed), which do the state changing when something happens, i.e. new order is placed or order is shipped. But when I just need to show something in the UI, for instance the list of the products filtered by the category, it is a simple query and does not involve the domain objects at all. It simply returns Data Transfer Objects (DTO) that do not contain any domain logic at all.
I'm facing several problems trying to apply DDD with EF4 (in ASP MVC2 context). Your advaice would be greatly appreciated.
First of all, I started to use POCO because the dependacy on ObjectContext was not very comfortable in many situations.
Going to POCO solved some problems but the experience is not what I was used to with NHibernate.
I would like to know if it's possible to use designer and to generate not only entities but also a Value Objects (ComplexType?). If I mean Value Object is a class with one ctor without any set properties (T4 modification needed ?).
The only way I found to add behavior to anemic entities is to create partial classes that extends those generated by edmx. I'm not satisfied with this approach.
I don't know how to create several repositories with one edmx. For now I'm using a partial classes to group methods for each aggregate. Each group is a repository in fact.
The last question is about IQueryable. Should it be exposed outside the repository ? If I refer to the ble book, the repository should be a unit of execution and shouldn't expose something like IQueryable. What do you think ?
Thanks for your help.
Thomas
It's fine to use POCOs, but note that EntityObject doesn't require an ObjectContext.
Yes, Complex Types are value objects and yes, you can generate them in the designer. Select several properties of an entity, right click, and choose refactor into complex type.
I strongly recommend putting business methods in their own types, not on entities. "Anemic" types can be a problem if you must maintain them, but when they're codegened they're hardly a maintenance problem. Making business logic separate from entity types allows your business rules and your data model to evolve independently. Yes, you must use partial classes if you must mix these concerns, but I don't believe that separating your model and your rules is a bad thing.
I think that repositories should expose IQueryable, but you can make a good case that domain services should not. People often try to build their repositories into domain services, but remember that the repository exists only to abstract away persistence. Concerns like security should be in domain services, and you can make the case that having IQueryable there gives too much power to the consumer.
I think it's OK to expose IQueryable outside of the repository, only because not doing so could be unnecessarily restrictive. If you only expose data via methods like GetPeopleByBirthday and GetPeopleByLastName, what happens when somebody goes to search for a person by last name and birthday? Do you pull in all the people with the last name "Smith" and do a linear search for the birthday you want, or do you create a new method GetPeopleByBirthdayAndLastName? What about the poor hapless fellow who has to implement a QBE form?
Back when the only way to make ad hoc queries against the domain was to generate SQL, the only way to keep yourself safe was to offer just specific methods to retrieve and change data. Now that we have LINQ, though, there's no reason to keep the handcuffs on. Anybody can submit a query and you can execute it safely without concern.
Of course, you could be concerned that a user might be able to view another's data, but that's easy to mitigate because you can restrict what data you give out. For example:
public IQueryable<Content> Content
{
get { return Content.Where(c => c.UserId == this.UserId); }
}
This will make sure that the only Content rows that the user can get are those that have his UserId.
If your concern is the load on the database, you could do things like examine query expressions for table scans (accessing tables without Where clauses or with no indexed columns in the Where clause). Granted, that's non-trivial, and I wouldn't recommend it.
It's been some time since I asked that question and had a chance to do it on my own.
I don't think it's a good practice to expose IQueryable at all outside the DAL layer. It brings more problems that it solves. I'm talking about large MVC applications. First of all the refactorings is harder, many developers user IQueryable instances from the views and after struggle with the fact that when resolving IQueryable the connection was already disposed. Performance problems because all the database is often queried for a given set of resultats and so on.
I rather expose Ienumerable from my repositories and believe me, it saves me many troubles.