Well one important design principle for domain/business layer is to use rich models, thus to put business logic inside domain models and make the application layer as thin as possible. The tricky thing here is, what classifies as domain/business logic, and what does not. On web development, this may not be easy to figure out, as you do not have classes like Car or Cat in which the business logic is straightforward. A car can be driven and stopped, so drive() and stop() are clearly a business logic. A cat can meow and eat, so meow() and eat() are the domain logic. But what if you have a domain object User? The user can do many many things, I do not want to make an anemic user model, nor do I want to make it a God object that violates single responsibility principle. Do anyone of you know what exactly the responsibility/business logic for a typical User domain object should be?
Another thing I was wondering is about validation logic. Each domain model should be validated somehow, but is validation logic a part of business logic? If not, will it be violating the single responsibility principle to have too much validation logic/methods inside a domain model?? What if a domain model has rather complex validation logic? In this case, I am thinking about implementing validator classes/objects that the domain model can use to validate its data. But if validation logic is part of business logic, implementing validator class will make the model anemic as its business logic/responsibility will be incomplete. This is a huge dilemma I am facing, like where should validation go in my application. I’d appreciate if any of the advanced coders would give some advice on this topic. Thanks.
Make a list of things a User should be able to do, then it will be possible to see, whether User is really responsible for all of them.
Every business object should validate its input. But validation classes are neither business nor application logic. They belong into a validation service that can be used by anybody from anywhere in the system. The same applies, for example, to a Logging facility.
Validation is definitely business logic. Although a lot of it is simple, e.g. “You must provide a name” it’s still business logic insofar as it’s dealing with domain principles “All users must have a name” is a rule that stems from the domain. The application model/view/controller etc should never care about domain principles.
Where it really becomes apparent is when you have “Sorry, that email address is already registered” or “That username is already taken”. Here, the validation isn’t a simple regex but needs to do a lookup on data within the domain model.
Every business object should validate its input. But validation classes are neither business nor application logic. They belong into a validation service that can be used by anybody from anywhere in the system. The same applies, for example, to a Logging facility.
I disagree with this. While it can be appropriate to create a validation class, if that is the case it’s entirely encapsulated by the domain. Any time someone calls $model->save($user); $model->save() does the validation and throws an exception or returns false and gives the calling code a method for retrieving the errors. Whether this is done by a validation class or not is irrelevant.
The same is true of logging. If you want “Every time a user is updated, log who made the change” as a rule in the system then it has to be impossible to save a user without the log being done. if the logger is not enapsulated in the model and you have code like this:
And that code is sitting *anywhere* apart from the domain model then it's possible to call save without calling the log, which breaks consistency and invalidates the domain.
Validation logic is part of the business logic. But, validation happens in many places in an application. Thus it is reasonable to create a validation service, which gets the data and the rules as input.
“You must provide a name” is part of the business domain. Checking that the string name is not empty is a common activity that is needed everywhere in an application. If you have a validation service you could tell it to check that the supplied parameter is of type string, and the string has to have a certain minimum and maximum length, has to contain certain characters and so on. If you don’t have it, you will end up duplicating the same check all over your application.
Logging is a service that is needed everywhere, not only by the domain model. Domain model definitely has to get a logger from somewhere. But the logger itself is not part of the domain. Check out Aspect-oriented programming for a more thorough description.
I think we’re talking at cross purposes here. I was talking about the $log or $validation instances. While these can be instantiated anywhere, the ones used for the purposes above are encapsulated by the domain model. Anything using the domain model should not be aware they’re being used or anything about their implementation.
As the original question was “Where does validation of domain concepts belong” saying “validation classes are neither business nor application logic.” is at best confusing, which is what I was trying to clarify.
Essentially I wanted to point out that code like this:
if ($this->validator->validate($data)) {
$this->model->save($data);
}
Is wrong and the validate call belongs inside the $model->save() method.
Thank you so much for your inputs, Freakyrag and TomB. So in general, part of the validation logic should belong to the domain layer and needs to be managed by domain models, although it does not matter whether the model’s setter or other methods directly manipulate it, or delegate to a validator object. Is this correct? So if in TomB’s example above, the model’s save method is written like this:
public function save($data){
if(!$this->validator->validate($data)){
throw new InvalidDataException("Data is invalid");
}
$this->db->update($this->table, $this->id, $data);
}
Is this code above, the model has stored an instance of the validator class inside itself and is self-managing its domain-level validation. Is this practice okay? Or is it still considered removing validation responsibility from the model?
Your code implies that $this->validator knows how $data is structured and what validation rules to apply. That is only okay if $this->validator gets configured in this domain object specifically for the validation of this particular object and is not reused anywhere else. Otherwise this validator would have some kind of global state which you will have to keep track of, and that is something you don’t want to do.
Yeah of course I understand. In this case the validator will be a UserValidator class that handles complex validation logic, but will not be reused elsewhere since it is specific for user domain model class. I think in an ideal world I’d implement it as a private inner/nested class, but well since PHP does not support it I cannot restrict which class or client code can use it. Nested classes have their drawback though, but its in cases like this that they can be quite useful.
Your code implies that $this->validator knows how $data is structured and what validation rules to apply. That is only okay if $this->validator gets configured in this domain object specifically for the validation of this particular object and is not reused anywhere else. Otherwise this validator would have some kind of global state which you will have to keep track of, and that is something you don’t want to do.
Yep. The code you have is good, but only if your validator is configured specifically for the domain instance. So for example
class Domain {
public function __construct(Validator $validator) {
$this->validator = $validator;
}
}
$validator = new Validator;
$validator->set('name', '^\w+$');
new Domain($validator);
Typically I avoid validation classes for this reason, the added complexity, although better separation of concerns, makes maintenance difficult. Having an external validator that can work out “Sorry that username is taken” is far more difficult than having a the save method look like this:
public function save($data){
if(!$this->validate($data)){
throw new InvalidDataException("Data is invalid");
}
$this->db->update($this->table, $this->id, $data);
}
Although this looks like mixing concerns, what values are valid is part of the domain logic.
I’m new to OOP, but my understanding is that you want to think of things as objects versus bunches of functions like in procedural.
And I believe one object can use other objects which have other functionality.
So instead of having one User object with 500 methods, I believe good OOD says you might have a User object with a dozen methods but which interacts with 10 other objects which in turn have several methods of their own.
Not sure if I can think of any valid examples, but here are some possible classes/objects…