Suppose I have a service StateService which has a method ChangeState.
ChangeState(State toState, DomainObject object)
I have business rules that checks whether the destination state is valid or not in the domain objects current "state", how can I technically check those rules without first setting the toState on the domain object? It feels wrong to first set the new state, run validation and if one or more rule breaks unset the state.
One solution I came up with is to create some context object that drives the validation eg.
ChangeStateContext that contains the DomainObject along with the State that is to be set.
Another related question is how to report back from the ChageState call how it went?
I can collect all validation rules that broke and throw an exception with those rules that the caller can catch and handle accordingly or I can add a return type on the ChangeState-method like ValidationSummary that contains information about broken rules and such. What is best practices in these cases?
Can't you throw an exception from the ChangeState method when the state transformation is invalid? You can throw specific exceptions such as StateTransformationException or ValidationException that you can catch higher on the call stack. You can optionally include extra properties to these exception types so that you can communicate very precisely what went wrong to the user.
When you want to call multiple ChangeStates after a single user action, you will need a way to revert or rollback. What I usually do is using the unit of work pattern (supplied to me by LINQ to SQL and Entity Framework) and change all state within this unit of work. When an exception is thrown I throw away the complete unit of work with all its changes.
The DomainObject class could have a public bool CanChangeState(State toState) instance method, returning True if toState is a valid transition from the current state of the subject DomainObject. Such method can be called prior to the StateService.ChangeState call.
Of course, if the StateService is responsible for the state change validation, then a CanChangeState(State toState, DomainObject obj) method should be added to the StateService.
To report back the validation error messages, change the return Type of the CanChangeState to a custom Type responsible for reporting validation errors.
Related
I was wondering where exactly we should put input validations(imagine an API call send input to apply free times of a user). Is it right to inject validation class in service Layer and call validate method inside service? or it's better to put it in the infrastructure layer or even in Domain model? I just wanted to see a sample code that's implement validation of input for an API in Domain-driven design approach? what if I use CQRS architecture?
I use in my DDD/CQRS project following approach, structure of a project is API layer, Domain layer, Data Access layer, all input data from UI or from User are validated before, command are created and dispatched, to update the state of Domain, and we validate input data two times one is on the UI, (Angular app), and second one in Web API layer, if the data are valid the CQRS command are created and dispatched after that you can have Business logic validation. For validation you can use FastValidator or FluentValidation
UPDATE: Here is the simple example we have API for Create Batch Entity.
[HttpPost]
[Route("create")]
public IHttpActionResult Create([FromBody] BatchEditModel model)
{
var createCommand = model.Map<BatchEditModel, CreateBatchCommand>();
var result = (OperationResult<int>) _commandDispatcher.Dispatch(createCommand);
return Result(result);
}
As you can see as user input data will be BatchEditModel.
so we have BatchEditModelValidator which contains input data validation:
public class BatchEditModelValidator : AbstractValidator<BatchEditModel>
{
public BatchEditModelValidator()
{
RuleFor(x => x.Number).NotEmpty()
.WithMessage(ValidatorMessages.MustBeSpecified);
RuleFor(x => x.ClientId).GreaterThan(0)
.WithMessage(ValidatorMessages.MustBeSpecified);
RuleFor(x => x.EntryAssigneeId).GreaterThan(0)
.WithMessage(ValidatorMessages.MustBeSpecified);
RuleFor(x => x.ReviewAssigneeId).GreaterThan(0)
.WithMessage(ValidatorMessages.MustBeSpecified);
RuleFor(x => x.Description).NotEmpty()
.WithMessage(ValidatorMessages.MustBeSpecified);
}
}
this Validator will be executed before BatchEditModel will be mapped to CreateBatchCommand
and in CreateBatchCommandHandler we have Business logic validation CheckUniqueNumber
public OperationResult Handle(CreateBatchCommand command)
{
var result = new OperationResult<int>();
if (CheckUniqueNumber(result, command.ClientId, command.Number))
{
if (result.IsValid)
{
var batch = _batchFactory.Create(command);
_batchRepository.Add(batch);
_batchRepository.Save();
result.Value = batch.Id;
}
}
return result;
}
My approach is putting validation in the domain model, I validate the functionality of aggregates, entities, value objects, etc.
Then you can validate application services too, and user interface too. But those validations are a plus, a validation enhancement from the user point of view, as validation is faster.
Why this duplication of validations at different layers? Well, because if you just rely on UI or application service validations, it maybe possible that if they don't work well for whatever reason, and you don't validate the domain model, you are executing domain functionality without validating it.
Also, I would point out that not all the validations can be done at UI or at application layer, because you may have to access domain.
Finally, doing CQRS or not is independent on where you decide to put the validations. It's just that if you do CQRS, then validations at application layer are easier to do, as you can put them in decorators that wrap commands and queries.
Hope my explanation helps.
where should put input validation [in Domain Driven Design]?
This is largely unrelated to DDD, but: the closest possible to the input source.
You aren't going to wait until invalid data has crossed 4 layers to discard it.
Input validation precisely means you don't need anything else (e.g. loading other data) to check it, so you might as well do it as soon as you can. Of course, caveats apply, like any validation that can be circumvented must be double checked - client side javascript for instance.
what if I use CQRS architecture?
I wouldn't expect CQRS to change things very much.
Usually, by the time you are invoking a method in a domain entity, your inputs should have already been converted from their domain agnostic form into value objects.
Value objects are expected to be constructed in a valid state, and often include a check of a constraint within the constructor/factory method that produces it. However, in Java and similar languages, the implementation of the constructor usually throws (because constructors don't have any other way of reporting a problem).
Often what clients want instead is a clear understanding of all of the constraints violated by the input data, rather than just the first one. So you may need to pull the constraints out as first class citizens in the model, as predicates that can be checked.
You should validate in your app service before attempting to modify your domain. Validation should be towards the edges of your app (but not in the UI) so invalid or incomplete requests aren't even getting into your domain model.
I consider it two levels of validation because you will validate the request before attempting some behavior on the model then the model should again verify for internal consistency, since it can never be persisted in an invalid state.
I'm not sure if this is limited to Yii2 or if it could be also discussed with other frameworks or even in general.
In Yii2 I can call validate() on a model object. This will return true or false. If it is false I can call getErrors() to see which validation problems currently exist within this object.
Why is this behavior implemented this way? Why does validate() not throw some ValidationExceptions? I find it also somehow strange that errors are part of the model object. Why are they not part of such an exception?
What are the advantages of this implementation? Why is it done this way? I would prefer exceptions. With this, I could better distinguish between desired and exceptional processing. All that is not desired is handled in catch blocks. The desired happens in try blocks. Isn't this a good idea?
Because in general the errors are used in combination with a form.
Let's say you have a form with some input fields (linked to the model attributes/properties) and you want to do something with these fields, maybe save them or something.
Before saving the fields you would like to verify that they are all valid. When the validate() method is called all attributes are validated one by one and each one will generate an error if needed. If the validation is false and you have an error collection you can again show the form, but this time attach the errors to the fields.
If you throw an exception each time an error occurs your application would stop running and only display the one error. Or you would have to write try-catch blocks for all attributes, which is just unnecessary. When your validation returns true you can run the next step which does the processing and you can be sure all values are valid.
If you really want exceptions you can, of course, write your own Validators (http://www.yiiframework.com/doc-2.0/yii-validators-validator.html)
Any given entity in my domain model has several invariants that need be enforced -- a project's name must be at least 5 characters, a certain product must exist to be associated with the project, the due date must not be prior to the current date and time, etc.
Obviously I want the client to be able to display error messages related to validation, but I don't want to constantly maintain the validation rules between several different layers of the program -- for example, in the widget, the controller, the application service or command object, and the domain. Plus, it would seem that a descriptive error message is presentation-related and not belonging to the domain layer. How can I solve these dilemmas?
I would create specific exceptions related to your expected error conditions. This is standard for Exception handling in general and will help with your issue. For example:
public class ProjectNameNotLongEnoughException : System.Exception
or
public class DueDatePriorToCurrentDateException : System.Exception
Mark these possible exceptions in the xml comments for the methods that may throw them so that applications written against your domain model will know to watch out for these exceptions and will be able to present a message within the presentation of the application. This also allows you to have localized error messages based on the culture without cluttering up your domain model with presentation concerns.
If you choose to perform client-side validation, I'm afraid that you can't have your cake and eat it too. In this case, you may have to duplicate validation logic in order to achieve the desired features while maintaining your architecture.
Hope this helps!
I realise this is an old question, but this may help others in a similar situation.
You have here Behavior and Conditions which you need to encapsulate into your domain model.
For example, the ProjectName having a requirement on a certain length I would suggest should be encapsulated within a ValueObject. It may seem overboard for some, but within our Domain Model we almost always encapsulate native types, especially String, within a ValueObject. This then allows you to roll your validation within the constructor of the ValueObject.
Within the Constructor you can throw an Exception relating to the violation of the parameters passed in. Here is an example of one of our ValueObjects for a ZoneName:
public ZoneName(string name)
{
if (String.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException("Zone Name is required");
}
if (name.Length > 33)
{
throw new ArgumentException("Zone name should be less than 33 characters long");
}
Name = name;
}
Now consumers of that ValueObject can either perform their own validation before calling the constructor, or not, but either way your invariants will be consistent with your model design.
One way we build validation rules within your Domain Model, and then utilise them within your UI is to use the Mediatr module, which uses a One Model In, One Model Out pattern, and allows you to define Validators for each of your Query or Command models. These are defined using FluentValidation. You can then add a Provider to the ModelValidatorProviders within MVC. Take a look at JBogards ContosoUniversity example here https://github.com/jbogard/ContosoUniversity/tree/master/src/ContosoUniversity and look at the DependancyResolution folder, DefaultRegistry.cs.
Your other example of a Product must exist to be linked to a Project. This sounds to me like a Domain Service would be the best option to facilitate the cooperation between 2 bounded contexts? The Domain Service will ensure the invariants remain consistent across the bounded contexts. That Domain Service would not be exposed publically, so you would need an ApplicationService or a CQRS type interface which will take that DomainService as a dependency, allowing the DomainService to perform the operations required. The DomainService should contain the Domain Behavior, whereas the Application Service should just be a facilitator to call that function. Your DomainService would then throw exceptions rather than result in inconsistent or invalid invariants.
You should ultimately end up in a position where you don't have duplicated validation, or at least you never end up with invalid invariants because validation has not been performed at some point, as validation is always handled within your domain model.
While a descriptive error message may seem to pertain to presentation moreso than business, the descriptive error message actually embodies a business rule contained within the domain model -- and when throwing an exception of any kind, it is best practice to pass along some descriptive message. This message can be re-thrown up the layers to ultimately display to the user.
Now, when it comes to preemptive validation (such as a widget allowing the user to only type certain characters or select from a certain range of options) an entity might contain some constants or methods that return a dynamically-produced regular expression which may be utilized by a view model and in turn implemented by the widget.
If a domain class will validate can I be assured it will save (assuming nothing super-drastic like the database is down)? More explicitly, under which scenarios will an object pass validation but throw an error on save.
under which scenarios will an object pass validation but throw an error on save.
Domain class constraints can check anything, so if "the thing they check" changes between the calls to validate() and save(), then it's entirely possible that the former will succeed and the latter fails.
Here's a very simple such example
Book.ISBN has a unique contraint
myBook.validate() is called and passes
another book with the same ISBN as myBook is saved
myBook.save() fails because the unique constraint on ISBN now fails
Save will throw an error if your database has additional constraints that don't allow the insert or update to succeed. If your database doesn't have any additional constraints and barring any sort of infrastructure outages, I can't think of any reason save() would fail if validate() is true.
If you validate something in code you can either work with a return value indicating that something is wrong or you can throw an exception. In my controller I have Exceptional validation like this:
void DoSomething()
{
Validate(); // throws exception if something is wrong
.....
}
I wonder if there is a common naming convention that implies that an exception is thrown when something is wrong so that I don't need to add the comment // throws exception if something is wrong and distinguishes from if (!IsValid())
Note: validation-naming-conventions does not answer my question.
Update after accepting the answer: What I have learned from this Question
AssertValid() or VerifyAndThrow() are good names (tnx #hacktick)
Validation must distinguish with a context (warning or error)
Exceptional Validation is good as a kind of Contract or second line of defense that might exist only in Debug mode to ensure that the surrounding if (IsValid(...)) does not miss something (tnx # Cody Gray)
Typically you would use:
// for a validations that returns just plain yes no (true|false). in the case of a property use caching for the last validationresult.
bool IsValid
// for a validation that returns a list of errors of some sort (messagelist, id list, custom objects, whatever you need).
object Validate();
// validates and throws an exception if one or more error occured.
void ValidateAndThrow();
Also make sure to consider if you need warnings of some kind. For example if you validate your registration DTO model and want to warn a user if the password is weak but do not want to prevent the user from saving it if he chooses to.