I am building an application that will expose part of its features through RESTful services and my application packages is organized as below
Application --> This package contains the RESTfull services
Model --> Contains the domain model the aggregates, Value Objects,...
Infrastructure --> Contains the set of classes required to access the database
Mongo DB --> My DB
The application package exposes the endpoint
CastReview(UUID reviewedEntityId, string review)
The review the retrieved from the body of the request and it is mandatory.
Now my question is where the validation should occur
Should I keep the validation logic inside the aggregate and inside the application I just construct instance of the aggregate and check if the aggregate is valid
Or Should I have the validation inside the application package as well as inside the aggregate
For Aggregates, I wouldn't call it validation but invariant enforcement, since they are supposed to be always valid. You don't just modify an aggregate and then have it checked by an external validator, aggregates enforce their own invariants.
Some rules are clearly domain invariants since you have to have deep knowledge of aggregate data to enforce them, and some are definitely applicative rules (e.g. email confirmation == email). But sometimes the lines are blurred. I would definitely check at a client-side and applicative level that the review is not null or empty, and at the same time I wouldn't consider a Review Aggregate OK if it has a null review, so I would do both. But this might be domain-dependent and YMMV.
Integrity constraints (or "invariants", if you prefer that term) should be defined in the (domain/design/data) Model. Then they should be checked multiple times:
In the front-end User Interface (on input/change and on submit) for getting responsive validation.
In the back-end Application or Infrastructure before save.
And in the DBMS (before commit), if your DB is shared with other applications.
See also my article Integrity Constraints and Data Validation.
Related
I've been reading a book Domain-Driven Design Quickly.
Now I've reached the Repository Pattern.
I am not sure what are they referring by mentioning the "Client"?
What does "Client" mean here?
Databases are part of the infrastructure. A poor solution is for
the client to be aware of the details needed to access a database.
For example, the client has to create SQL queries to retrieve the
desired data. The database query may return a set of records,
exposing even more of its internal details. When many clients
have to create objects directly from the database, it turns out that such code is scattered throughout the entire domain.
Client of a repository is a piece of code (another class), usually application layer in context of DDD/Onion Architecture. The rule of a thumb says: 1 repository per Aggregate Root. If your Aggregate Root is Order, which has a collection of OrderItem inside, you create only OrderRepository and return back the whole Order with ALL OrderItems, no Lazy Loading. Now, your client, (application layer code) should have no idea what is inside repository, (is it file based, sql based, http based) you treat it as inmemory collection: repository.GetById(orderId) where repository is IOrderRepository. That would mean you can easily change your repo from in Memory to sql and back anytime and your client code (application layer) or whatever class which uses repository will not be affected hence Liskov Substitution principle is preserved.
I have two questions related to CQRS and Domain Driven Design (DDD).
As far as I understand the segregation idea behind CQRS, one would have two separate models, a read model and a write model. Only the write model would have access to and use the business domain model by means of commands. The read model, however, directly translates database content to DTOs by means of queries and has no access to the business domain at all.
For context: I am writing a web application back-end that provides calculation services for particle physics. Now my questions:
1.) My business domain logic contains some functions that calculate mathematical values as output from given measurement system configurations as input. So, technically, these are read-only queries that calculate the values on-the-fly and do not change any state in any model. Thus, they should be part of the read model. However, because the functions are heavily domain related, they have to be part of the domain model which again is part of the write model.
How should I make these calculation functions available for the front-end via my API when the read model, that should contain all the queries, does not have any access to the domain model?
Do I really have to trigger a command to save all the calculations to the database such that the read model can access the calculation results? These "throw-away" calculations will only be used short-term by the front-end and nobody will ever have to access the persistent calculation results later on.
It's the measurement configuration that has to be persistent, not the calculation results. Those will be re-calculated many times, whenever the user hits the "calculate" button on the front-end.
2.) I also feel like I duplicate quite a bit of data validation code, because both read model and write model have to deserialize and validate the same or very similar request parameters in the process chain http request body -> json -> unvalidated DTO -> validated value -> command/query.
How should I deal with that? Can I share validation code between read model and write model? This seems to dissolve the segregation.
Thanks in advance for all your help and ideas.
I think that what do you have is a set of domain services that with a given input they return an output.
As you said, this services are located in the domain. But, nothing denies you to use them in the read model. As long as you don't change the domain inside the functions, you can use them in any layer above the domain.
If, for any reason, this solution is not viable, because for example the services require domain objects that you cannot/don't want to build in the query side, you can always wrap the domain services inside application services. There you take in input a base object, you do all the transformations to the domain one, you call the domain service and you return the resulting value.
For the second question, you can build a validation service in the domain layer, as a set of services or simple functions. Again, nothing denies you to use them in the validation steps.
I've done the same in my last web app: the validation step of the form data calls a set of domain services, that are used also when I build the domain objects during the handling of a command. Changing the validation in the domain has as effect that also the Web related validation changes. You validate two times (before building the command and during the building of the domain object), but it's ok.
Take a look at the ports/adapters or the onion architecture: it helps a lot understanding what should stay inside a layer and what can be used by an overlapping layer.
Just to add my two pence worth.
We have microservices that use mongo as a backend. We use NET Core using mediatr (https://github.com/jbogard/MediatR) to implement a CQRS pattern in the MSs. We have .Query and .Command features.
Now in our world we never went to Event Sourcing. So, at the mongo level, our read and write models (entities) are the same. So what worked best for us was to have a single entity model which could be transformed into different models (if needed ) via each command/query handler(s).
If you are doing pure CQRS via event sourcing (so different read and write models) or something else then please ignore me! But this worked best for us.
Colleague of mine told me - we don't have a Business logic, we only have CRUD like GetById, GetBySearchTerm, GetByParentID....so I started to wondering about these words.
After reading about DDD, those methods are CRUD, they have a mechanism to fetch data (also store, update, delete...) based on some specific code (usually SQL).
If Business analyst say me: "We need to show data about specific customer".
In my opinion this IS (GetById) a Business process, GetById should be placed inside Business logic part of the application and it contacts repository to fetch a data. Repository with CRUD methods is responsible to persist data based on some criteria.
I Know this question can lead to debate to have repository with atomic methods (GetById, GetBySearchTerm, GetByParentiId...) but my question is only simple - are those methods are CRUD or Business logic methods.
The short answer is that you should not be querying your domain model for any reason other than domain operations that are part of the write / transactional side of things. This side of things is more interested in commands issued at your domain in order to do / perform operations.
Anything related to displaying data should come from as simple a query / read model as is possible.
If you find that your queries require domain interaction you probably have a scenario where you may need to tell your domain to do something and, once completed, you can request the data through the query side.
Not every application is a DDD application. Some applications are just simple CRUD
The business logic would be the part of the application where you validate inputs (like get by id and id is a number between 1 and 99999). This then is passed on to the repository for the actual query.
But if your application is really a crud application then trying to apply DDD isn't going to help you.
Those methods can't be the business methods at all. As a CQRS practitioner i would suggest you to have different models for command and query side. May be you create a different bounded context that serves the whole reading (Query) process (You can create anemic /DTOs here) and another domain model that serves pure business logic purpose.
You can take a look at my blog for command and query separation.
https://aspxsushil.wordpress.com/2015/10/18/command-and-query-object-pattern/
In DDD, the Application layer is supposed to just perform coordination tasks, whereas the Domain layer is responsible of validating the business rules.
My question is about validating the domain object properties. For example, I need to validate that a required property has some value in it before persisting it to the database through repositories.
In terms of DDD, is it acceptable to perform this sort of property validation in the Application layer?
Kinds of validation
In the situation you describe, there are two different validation steps that you need to consider separately:
Input validation. This is the responsibility of an app service. The goal is to ensure that no garbage or harmful data enters the system.
Protecting model invariants. This is your domain logic. Whenever something in the domain changes, you need to make sure that the changes are valid within your domain, i.e. all invariants still hold.
Validating domain invariants as part of an app service
Note that sometimes you also want to validate domain invariants in an app service. This could be necessary if you need to communicate invariant violations back to the client. Doing this in the domain would make your domain logic client-specific, which is not what you want.
In this situation, you need to take care that the domain logic does not leak into the app service. One way to overcome this problem and at the same time make a business rule accessible to both the domain and the app service is the Specification Pattern.
Here is an answer of mine to another question that shows an example implementation for the specification pattern.
You can validate incoming data in your ui layer.
For example you can you symfony forms validation or just check for necessary data inside your layer with Rest.
What about Domain Layer, it depends.
You didn't precise what kind of domain object it is.
Mostly you do such kind of validation by creating Value Object, with creation logic inside. For example Email Value Object, you can't create wrong one, otherwise it will throw exception.
Aggregates can perform validation before executing method and it's called invariants. For example, user has method becomeVIP, inside a method there is constraint, that only user with name 'Andrew', can become a VIP.
So you don't do validation after the action, but before the action. You don't let your aggregate go into wrong state.
If you have logic, which is not correlated with aggregate you put it in domain service, for example email uniqueness check.
Rather than "validating hat a required property has some value in it" at the periphery of the Domain, I prefer to make sure that it can never become null in the Domain the first place.
You can do that by forcing consumers of the constructors, factories and methods of that entity to always pass a value for the property.
That being said, you can also enforce it at the Application level and in the Presentation layer (most web application frameworks provide convenient ways of checking it these days). Better 2 or 3 verifications than one. But the domain should be the primary source of consistency.
Consider a typical Breeze controller that limits the results of a query to entities that the logged in user has access to. When the browser calls SaveChanges, does Breeze verify on the server that the entities reported as modified are from the original set?
To put it another way, does the EFContextProvider (in the case Entity Framework) keep track of entities that have been handed out, so it can check against malicious data passed to SaveChanges? Or does BeforeSaveEntity need to validate that the user has access to the changed entities?
You must guard against malicious data in your BeforeSaveEntity or BeforeSaveEntities methods.
The idea that the EFContextProvider would keep track of entities that have already been handed out is probably something that we would NOT want to do because
The EFContextProvider would no longer be stateless, which was a design goal to facilitate scaling.
You would still need to guard against malicious data for "Added" entities in the BeforeXXX methods.
It is actually a valid use case for some of our users to "modify" entities without having first queried them.