2010 m. liepos 17 d., šeštadienis

DDD - too large Agregate root

Last week I ran into problem where my aggregate root had too many child entities, way too many. My aggregate root snapshot was about 20 MB and that of course gave me a sign that it is wrong.

Model was rather simple one. I had to create a domain model for voucher system. Every deal that our company creates would need about 100k vouchers. Every deal has vouchers that provides different gifts to customers. Those deals are created pretty often, so we are talking about millions of vouchers.

Now voucher was identified as entity because it has behaviours. And as an aggregate for them I have presented Stock entity. It holded references to all vouchers and those were accessible through it. Also it was responsible for generating vouchers and exporting them. I was using a rule that there always should be a higher 'thing' for my entities and that thing should know what entities exists out there. It's like for licenses we have stock, for invoices ledger and so on.
Now why it is wrong ? (Well I think it is wrong)

First of all in this way I am transferring repository responsibility to other object - stock, ledger etc. I am creating repository that holds all data in-memory while I do not need it. What I really need is just another domain service.
So, let me explain how I have re-modeled my domain here.

Stock aggregate root remains but voucher becomes an aggregate root. I do present new aggregate root - VoucherGenerator that has knowledge about voucher code generation strategies. And to solve actual problem I add new services like GenerateVouchersService, VoucherLookupService. Instead of having behaviour on stock 'GenerateVouchers' i move this to Generator AR and then use this in service GenerateVouchersService to actually create new vouchers and add those to repository.
In this was my repository does what it suppose to do - acts as in-memory domain objects collection and my domain entity becomes free of millions child entities. Of course it still has a map of voucher code - UUID in my stock aggregate and I use it to get voucher UUID that later is used to get entity from repository.

Of course Stock AR still will have lot of data in it, but what we can do is introduce 'ClearOldVouchers' behaviour. Or remove voucher once it was used. And if at some point later I will have to restore my entities, because of event sourcing I am still able to do that.

So as you see, in this way we have solved large-aggregate-root problem and at the moment it seems to be the best solution for me.

Any comments ? Have you any other solution ?