I have a PHP MVC application, and my 'M' has a service layer, mapper layer and domain layer. Where and how should I check to ensure that an object has all it's required properties?
It seems to me that these responsibilities don't belong in the mapper or service layer, so that leaves the domain layer itself. I put a method, checkRequired(), in my base domain class. It checks the object's properties against an array of $_required properties, and throws an error if any are missing.
When retrieving objects from the database, I have been calling checkRequired() as the last command in the object's constructor. If the object is a new entity (i.e. not retrieved from the database), I supply some default values (in the constructor) and then call checkRequired().
While this has been working OK, I now come to put some behavioural methods on my (somewhat anaemic) domain objects, and I run in to trouble. For example, a User can own many Pets, so on my User model I put an addPet() method. I know that I need to pass the Pet object in, since it's best to inject dependencies, and my real method signature is therefore User::addPet(ConcretePet).
But that's the problem! My Pets can't exist without a User (as their Owner), so I can't instantiate ConcretePet! I could make the User optional on the Pet, but this would be a backward step. I could move the contents of checkRequired() somewhere else, but where?
What's the typical way to solve such a common problem?
That checkRequired is not a DDD way. An enntity should be valid all the time. In other words - you should not have a way to put it in an invalid state (like missing properties). How?
When you just have public properties that you set, that's anemic. Properties that you persist in DB should be private. The only way to set them is through methods with a business meaning. These methods should check all the invariants (not just required fields - all kind of constraints that would make an entity valid or not) and prevent the update if some of them are not met.
About User->Pet topic: If the Pet can't exist without the User then probably the User is an Aggregate Root that is responsible for protecting invariants related to User and Pets. That means there should be a method addPet... well... maybe something more meaningful? adoptPet and breedPet (they might have slightly different rules and input)? And this adoptPet should ensure the invariant of the pet having a User... By the way - why User and not an Owner?
But Pet also can be an Aggregate Root. That means it's constructor should require a User parameter.
Note that it depends from the use case what is the aggregate root. In some cases Pet is treated as aggregate root but in case of pet adoption it's a part of User aggregate.
Make a undirectional relationship as possible as you can. If a pet could be tracked alone (I mean without a user), consider it as an aggregate root.
Place a User attribute in Pet but no pets attribute in User. Therefore you don't need to have a addPet() method in User.
If you want to find all pets belonging to a user, use a query instead:
public class PetRepository {
public List<Pet> findByOwner(String uid) {
//omitted codes
}
}
Hope this helps.
When retrieving objects from the database, I have been calling
checkRequired() as the last command in the object's constructor.
Off topic, but this can be problematic. Suppose that the set of required attributes changes at some point such that persisted entities are no longer valid. You still want to be able to reconstitute them, so you shouldn't run that check upon reconstitution. Instead, only run validation upon creation or during behaviors.
With regards to the addPet method, instead of passing an instance of a concrete pet class, pass the data required to create an instance of a pet as method arguments or as an instance of a PetInfo class. This would allow the User class to create a fully valid instance of Pet.
Related
Good morning,
I've a model where a User AR has a specific UserRole (administrator, reseller or client). For that AR, there are some guards I would implement which are:
An administrator cannot have a manager other than himself
A reseller cannot have a manager other than an administrator
A client cannot have a manager other than a reseller or client (sub-account case)
Let's say that I want to register a new User. The flow would be as follows:
RegisterUser request handler -> RegisterUser Command -> RegisterUser command handler -> User->register(...) method ->UserWasRegistered Domain event
How and where I should implement the guards to validate my User AR exactly? Right now, I've something that look as follows:
namespace vendor\Domain\Model;
class User
{
public static function register(
UserId $userId,
User $manager,
UserName $name,
UserPassword $password,
UserEmail $email,
UserRole $role
): User
{
switch($role) {
case UserRole::ADMINISTRATOR():
if(!$userId->equals($manager->userId)) {
throw new \InvalidArgumentException('An administrator cannot have a manager other than himself');
}
break;
case UserRole::RESELLER():
if(!$manager->role->equals(UserRole::ADMINISTRATOR())) {
throw new \InvalidArgumentException('A reseller cannot have a manager other than an administrator');
}
break;
case UserRole::CLIENT():
// TODO: This is a bit more complicated as the outer client should have a reseller has manager
if(!$manager->role->equals(UserRole::RESELLER()) && !$manager->role->equals(UserRole::Client())) {
throw new \InvalidArgumentException('A client cannot have a manager other than a reseller or client');
}
}
$newUser = new static();
$newUser->recordThat(UserWasRegistered::withData($userId, $manager, $name, $password, $email, $role, UserStatus::REGISTERED()));
return $newUser;
}
}
As you can see here, guards are in the User AR, which I think is bad. I'm wondering if I should either put those guards in external validators or in the command handler. Another thing is that I should probably also access the read model to ensure uniqueness of user and existence of manager.
And the last thing is, I would prefer pass a UserId VO rather than a User AR for the manager property, hence my thinking that guards should not be put in the User AR.
Your advice would be much appreciated.
As you can see here, guards are in the model himself which I think is bad. I'm wondering if I should either put those guards in external validators or in the command handler.
With DDD, you strive to keep business logic within the domain layer and more specifically into the model (aggregates, entities and value objects) as much as possible to avoid ending up with an Anemic Domain Model. Some types of rules (e.g. access control, trivial data type validation, etc.) may not be considered business rules by nature and could therefore be delegated to the application layer, but the core domain rules should not leak outside the domain.
I would prefer pass a UserId value object rather than a User aggregat for the manager property
Aggregates should aim at relying on data within their boundary to enforce rules as it's the only way to ensure strong consistency. It is important to realize that any checks based off data external to the aggregate could have been made on stale data and therefore the rule might still get violated through concurrency. The rule can then only be made eventually consistent by detecting violations after they occurred and act accordingly. That doesn't mean the checks are worthless though, as it will still prevent most violations to occur in low-contention scenarios.
When it comes to providing external information to aggregates, there are two main strategies:
Lookup the data before calling upon the domain (e.g. in the application service)
Example (pseudo-code):
Application {
register(userId, managerId, ...) {
managerUser = userRepository.userOfId(userId);
//Manager is a value object
manager = new Manager(managerUser.id(), managerUser.role());
registeredUser = User.register(userId, manager, ...);
...
}
}
When to use? This is the most standard approach and the "purest" (aggregates never perform indirect IO). I would always consider this strategy first.
What to watch for? As in your own code sample, it may be tempting to pass an AR into another's method, but I would try to avoid it to prevent unexpected mutations of the passed AR instance and also to avoid creating dependencies on a larger-than-needed contract.
Pass a domain service to the domain which it can use to lookup data on it's own.
Example (pseudo-code):
interface RoleLookupService {
bool userInRole(userId, role);
}
Application {
register(userId, managerId, ...) {
var registeredUser = User.register(userId, managerId, roleLookupService, ...);
...
}
}
When to use? I would consider this approach when the lookup logic itself is complex enough to care about encapsulating it in the domain rather than leaking it into the application layer. However, if you want to maintain aggregates "purity" you could also extract the whole creation process in a factory (domain service) which the application layer would rely upon.
What to watch for? You should always keep the Interface Segregation Principle in mind here and avoid passing large contracts such as IUserRepository when the only thing looked up is whether or not a user has a role. Furthermore, this approach is not considered to be "pure", because the aggregates may be performing indirect IO. A service dependency could also need more work to mock than a data dependency for unit tests.
Refactoring the original example
Avoid passing another AR instance
Explicitly model the supervision policy policy as a first-class citizen, associated to a specific role. Note that you could use any modeling variants where the rule is associated to the role. I'm not necessarily satisfied with the language in the example, but you will get the idea.
interface SupervisionPolicy {
bool isSatisfiedBy(Manager manager);
}
enum Role {
private SupervisionPolicy supervisionPolicy;
public SupervisionPolicy supervisionPolicy() { return supervisionPolicy; }
...
}
class User {
public User(UserId userId, Manager manager, Role role, ...) {
//Could also have role.supervisionPolicy().assertSatisfiedBy(manager, 'message') which throws if not satsified
if (!role.supervisionPolicy().isSatisfiedBy(manager)) {
throw …;
}
}
}
Normally - Domain Driven Design calls for rich domain models, which normally means that the business logic is located in methods that represent parts of the domain.
That would normally mean that the command handler would be responsible for the plumbing (loading data from the database, storing changes in the database), and would delegate to the domain model the work of calculating the consequences of the user request.
So the "guards" would usually be implemented within the domain model.
And the last thing is, I would prefer pass a User Id rather than a User for the manager property, hence my thinking that guard should not be put in the User model.
That's fine - when a the domain model needs information that isn't local, you normally either lookup that information and pass it in, or pass in the capability to look up the information.
So in this case, you might be passing in a "domain service" that knows how to look up a UserRole given a UserId.
Are you telling me that it is perfectly valid to pass a domain service to an aggregate? At instantiation level or only to the method dealing with?
My strong preference is that services are passed as arguments to the methods that need them, and are not part of the instantiation. So the entities in the domain model hold data, and collaborators are provided on demand.
"Domain Service" is the third element of the domain model described by Evans in Chapter 5 of the blue book. In many cases, the domain service describes an interface (written in the language of the model), but the implementation of the interface is in the application or infrastructure "layer".
So I would never pass a repository to the domain model, but I would pass a domain service that delegates the actual work to a repository.
Is it OK for my domain objects to use a factory method, or factory layer, when they need to?
I have been trying to get client code to create and inject dependencies wherever they exist, however it seems that this is not always the right thing to do. In this question here, for example Where to check for mandatory properties in a domain object?, a User can own many Pets; and a Pet cannot exist without a User.
I have been trying to create a Pet, then add it to the User's collection, but the problem is that in order to create the Pet I need to supply the User (which defeats the purpose of having a User::addPet(ConcretePet) method).
What I would rather do is have a User::addPet() method that accepts an array of parameters, then creates the Pet using either a factory or a factory method. Is this reasonable?
EDIT: Another Scenario
Here's another scenario where I would like my domain model to access a factory. If my User's need a License object for each Pet they own, wouldn't it make sense to create this in the User::addPet(ConcretePet) method? Sure I could create the license in the service layer, but again that means taking business logic away from the domain!
If a pet cannot exist without it's user, it does not mean a user can exist without pet.
The question is whether the pet needs it's user and vice versa. I can pretty much think about both existing alone, and cross-referencing them might either be a good idea or not, depending on the problem. Generally speaking I'd say it's rather not so good, because it means that the user can interact with the pet, and the pet can interact with the user, and both interactions can trigger reverse interactions, resulting in an endless loop.
A safer solution would be to have an object that contains both user and pet and directs all interactions between them: A user-pet-relationship.
If you state that you cannot inject an objects dependencies, then you are doing something wrong. If you want to inject a factory instead, you are going to use the service locator antipattern, which is another code smell that should be avoided.
What I would rather do is have a User::addPet() method that accepts an
array of parameters, then creates the Pet using either a factory or a
factory method. Is this reasonable?
It is not. You do not have any more information inside this function than outside. All the pet parameters do exist, and you have the user object. What else do you need to create a pet with a relationship to the user, and then add that pet to the user?
I have a data model object User. My app also has some other data model objects, Fork and Options, for example. Users have forks and branches. My app has to run a lot of queries with some combination of User/Fork/Options etc. information. For example, you can see a page of User's Forks. This would require a query that joins that User (e.g. the logged in user in the session) on Forks.
I don't want to violate the Law of Demeter, and I am also typically against getters (and setters) in general, so I don't want to implement User::getID() or User::getUsername().
However, the alternative does not seem much better to me. What has ended up happening is that I implement various methods in User to run these queries (e.g. User::getForks()). In general this works, but the User class has become monolithic which is bad in its own way.
What's more is I'm not sure how I would resolve a query of two data model objects. For example, I could have a User with an id and a Fork with an id and want to check that the fork belongs to the user. This requires that either the Fork exposes its id to the user, the User exposes its id to the Fork, or both expose their ids to the controller (or whatever else). None of these seem desirable, and I'm not sure which to choose. Is there some other alternative that I'm missing?
In another similar step, I'm not sure of the best way to add information to the view. I have a view object, and typically I use a method like User::addForksToView(View $view), which will run a query or queries and do some processing, but this also increases the size and responsibility of User. I think this is a similar problem.
Rather than a getForks method in the User object, use a ForksFactory or something like it. The factory can have methods like fromUser(User $user) and byId($id). That way the User object does not have a hidden dependency upon the Fork object, and probably a hidden dependency on database access. The ForksFactory has a dependency on database and contains the code needed only to get the data and create Forks, that's all it knows how to do. Where as the Fork object would not have a dependancy on the database, and now the User object doesn't need to know anything about Fork, indeed Fork could not exist at all and the User doesn't care. This is the idea of a single-purpose object.
As far as getters and setters, why not expose properties like id and name as public? Alternately, you can use the magic methods __get and __set to control which properties are treated as read-only, if that is your concern. Otherwise, you may as well expose the properties -- that is perfectly acceptable.
The other code you mention sounds like it suffers from the same problem -- one object, one purpose. Every object should, in theory, stand in isolation or have any dependencies injected in the constructor. Your objects should not require that another object is defined or one of its methods will fail.
An Entity (let's say a UserEntity) has rigid rules for it's properties, and it can exist in 2 states - persisted (which means it has an id) and pre-persisted (which means it does not have an id yet).
According to the answer to this question about how to handle required properties, a "real" UserEntity should only ever be created with an id passed in to its constructor.
However, when I need to create a new UserEntity from information sent by the browser, I need to be able to validate the information before persisting into the db.
In the past, I would simply create a blank UserEntity (without an id), set the new properties, and the validate it - but, in this new, more secure way of thinking about Entities, I shouldn't ever create a new UserEntity without its id.
I don't want to create TWO places that know how to validate my UserEntity's properties, because if they ever change (and they will) it would be double the code to update and double the chances for bugs.
How do I efficiently centralize the validation knowledge of my entity's properties?
Note
One idea I had is reflected in this question, in which I consider storing the non-state properties like email, password and name in a standardized value object that would know about the rules for its properties that different services, like the Controller, Validator, and Repo, or Mapper could use.
that's what factories are for. to the factory method you pass only the data that is required to enforce the real invariants of UserEntity (take some time to figure out what are your real invariants of UserEntity and you'd better do it with your domain experts).
in the factory method you create a new Id and pass it to the UserEntity constructor.
In this stage i don't think it is that bad to discard the instance if the validation inside the constructor fails. in the worst case - you've lost an id... it's not a case that suppose to happen quite often - most of the time the data should be validated in the client.
Of course another option is that in the factory method you first validate the parameters and only then create a new Id and pass it to the UserEntity constructor.
itzik saban
I think you have a couple of options to consider:
(1) Consider your first comment:
An Entity (let's say a UserEntity) has rigid rules for it's
properties, and it can exist in 2 states - persisted (which means it
has an id) and pre-persisted (which means it does not have an id yet).
Here, you are already mention that validation actually depends on whether the entity has been persisted. In other words, if the entity hasn't been persisted, then it should be valid without the ID. If you continue with this domain specification, I feel the validation should act accordingly (e.g. return isValid even without an ID if the object hasn't been persisted)
(2) If you assume "valid" means the object has an ID, then you would need to generate the ID upon creation. Depending on how your IDs are generated, this could get tricky (e.g. save to database and return created ID, or generate unique identifiers somehow, or ...)
Using either approach, its probably worth implementing common base class(es) for your Entity (e.g. with ID) to help minimize duplicating validation across the different states. Hopefully, this shields the derived entities from the common validation as well.
In my opinion , save() , and load() methods should be doing both validation and setting ID attribute . And by the way an entity without Identity attribute is not a entity at all .
In my view Identity attribute should be validated and ensured when entity is in transit e.g
loading from db , loading from file or (after) saving to db such that
if loading from db fails discard the entity saving to db/file fails discard the entity .
Since validation is business log /behavior etc and a better pattern for that would be
Strategy Pattern (http://en.wikipedia.org/wiki/Strategy_pattern)
The topic of how to do validation correctly is somewhat of a grey area.
Validation is typically cast as Invariant and Contextual validation. Invariant validation pertains to those things that, according to your problem domain, have to be present in order for your model to function properly in its intended role. Contextual validation pertains to state that's valid within a given usage context (e.g. A Contact used for emailing needs an email address, but doesn't need phone number; a Contact used for catalog mailings needs a mailing address, but doesn't need an email, etc.).
If you want to be architecturally pure, then technically the concerns of input validation (what your customers are typing into a user interface) and the state of a given entity are two different concerns. Ideally, your domain should have no knowledge of the particular type of application it's written for and therefore shouldn't be burdened with providing error messages suitable for use, either directly or indirectly, in displaying error messages back to the user. This presents a bit of an issue, since it can lead to duplicate or triplicate error checking (client side, service side, domain-level), so many opt for a more pragmatic approach of dealing with most validation external to the entity (e.g. validating an input model prior to entity creation).
I don't see the problem with persisting invalid data. What is valid or not is a business concern and can sometimes depends on the situation. The database doesn't care about these business rules.
If I have to fill out a big form online and the very last step requires me to enter my credit card information and I don't have my card ready, I'll have to discard all that information and the next time enter it all over again (which won't happen because I rather go somewhere else). I would like that application to store the information I already gave and later on I can make it functionally valid. As long as it isn't valid, I can't order things online.
I asked this question a while back but now I'm looking to implement an actual separation between my database access layer and the domain layer. I am also going to be working to move business logic into the domain where it belongs and out of the controller scripts.
I'm using Zend Framework which implements the Table Data Gateway and Row Data Gateway patterns for the data access layer, but it apparently fails to really define how to build a domain layer that is separate from the data access layer. I've considered using an Active Record pattern where the domain logic coexists with the data access logic, but I have the following situation that occurs at least once that I don't think Active Record will handle:
I have a single table "Person" which contains person_id and userType fields.
Each userType (admin, buyer, associate, supervisor) has specific business logic associated with it and all types inherit some basic functionality from a Person object.
I don't want to bloat the Row Data Gateway object with business logic that belongs specifically to just one type of user but I'm not certain how to construct the domain layer to represent the different types of users. For example, do I make a Person object that contains the PersonGateway object and then write wrapper functions that pass calls to the gateway object, or do I write the Person object to extend the PersonGateway object and then only implement the specific functions that I need?
Likewise, I would typically think that this is (in part) a factory problem where I need a factory method that will instantiate the correct sub-class based on userType. Is that still the best method here with Zend Framework's Zend_Db class?
Any suggestions or links to tutorials that talk about how to properly create a domain model on top of Zend_Db would be greatly appreciated.
Domain Models extend nothing. They're just plain classes you use to encapsulate business logic. They may use data access objects, so there may be a protected instance of a row data gateway object inside the class. A Row object usually represents an instance of the domain more closely than a Table object. Besides, you can always get the Table object with the Row's getTable() method.
Typically DM classes have an interface with methods corresponding to higher-level operations you can do with that class. But you don't necessarily want to surface all data access operations.
class Person {
// Zend_Db_Table_Row object
protected $data;
public function subscribeToService(Service $service) { ... }
public function sendMailTo(Person $recipient) { ... }
public function changePassword($newPassword) { ... }
}
I also blogged about this subject last spring, and wrote about it on the ZF mailing list recently.
As far as tutorials and resources, try http://domaindrivendesign.org/