We're having a bounded context dealing with payments.
I'm trying to model case, where Merchant can create another merchant and inherit some of its properties in this case: users that are needed for authentication to another bounded context (payment processor) that acts as open host service with anti-corruption layer on our side.
class Merchant {
public Merchant registerSubMerchant(name, ..);
...
}
The problem is, that User is also an aggregate as Merchant is. The process will create an instance of merchant, stores it, but I also need to load all users from parent merchant, and assign them to newly created merchant and also generate new user for authentication against our system:
users.filter(user -> user.realm() == PAYMENT_PROCESSOR)
.forEach(user -> {
user.assignTo(merchantId);
userRepository.store(user);
});
User anotherUser = new UserForOurSystem(passwordGenerator).assignTo(merchantId);
userRepository.store(anotherUser);
Whole process should be (I suppose) in one transaction to be valid. Now here's the problem: I'm breaking the rule (and I guess also many other) that only 1 aggregate instance can be modified (or created?).
I know that I'm doing something wrong, but I'm not sure if users should be wrapped inside the Merchant aggregate or should know about some users and their passwords etc.. How can I model such situation?
-
2User shouldn't be an aggregate. You're thinking at the wrong level of abstraction; a User is an Entity. So is Merchant.Robert Harvey– Robert Harvey09/18/2017 15:12:15Commented Sep 18, 2017 at 15:12
-
Look at Fowler's description of DDD Aggregate: "A DDD aggregate is a cluster of domain objects that can be treated as a single unit."Robert Harvey– Robert Harvey09/18/2017 15:34:03Commented Sep 18, 2017 at 15:34
-
So you're suggesting to model merchant as aggregate with list of users? Problem is, that relation between merchant and user is m-n and I'm not totally sure about loading and persisting such aggregate.Slimer– Slimer09/18/2017 17:39:59Commented Sep 18, 2017 at 17:39
-
1You must agree, that it's common, that aggregate is sometimes just entity (possibly with some value objects/another entities) that encapsulates/wraps some business behaviour. E.g. Product, or BacklogItem..Large clustered aggregates can lead to performance issues and to transaction inconsistency. Maybe you did come across this article. [Evans] is like Bible...can be interpreted in many ways.Slimer– Slimer09/19/2017 07:47:02Commented Sep 19, 2017 at 7:47
-
1You could have a 'saga' to handle creation of a sub-merchant. It creates the sub-merchant in one transaction, then adds it to each users of the original merchant (in separate transactions). If any fail, it handles the error appropriately (probably by retrying and/or notifying someone (user or administrator) of the issue - a rollback seems unlikely to be what you'd necessarily want here. You should only update 1 aggregate per transaction.TomW– TomW09/19/2017 20:51:35Commented Sep 19, 2017 at 20:51