3

Hi im new to ddd design and is trying to develop my first application using this pattern working in C#

In my application i have an aggregate Contract that have child entity assets, when an asset is added or settled i should perform an accounting operation in another aggregate Accounts and ensure it in business logic.

Should i create a domain service that ensures that each operation in contract assets will raise an account operation, and call this service in application layer sending a collection of account entity. Or should I inject repository to this service load the account list and save the changes in account and operations list.

Or even make the methods in asset entity raise an event that enforce account changes. If this is the right approach, the event handle should be in the domain or application? If in the domain should the handler in the account entity perform the changes through respository injected?

Im a bit confused

George
  • 33
  • 3

2 Answers2

2

generally this kind of problems can be elegantly solved using events, and focusing on one aggregate per transaction.

Let's say your use case is to add an Asset to a Contract.

You will have an application service with a ContractRepository that will retrieve the Contract, and a method addAsset will be called on that Contract.

When you add an asset to your Contract aggregate, this aggregate will record a domain event, like AssetAdded, with all relevant information about that action. Then your application service will persist the updated Contract in the database and then it will publish the event to an asynchronous bus. In this moment you can send a response.

Some subscriber, inside your application, will be notified about that event and will do stuff. In this case you could have an UpdateAccountOnAssetAdded that internally will do the rest of the job.

This article will help you understand how everything is organized inside this kind of architecture.

Good luck!

rastafermo
  • 408
  • 1
  • 5
  • 13
  • Thanks for the answer rastafermo, this was the first solution i realized for this problem but the domain experts said a lot of times that every time an asset is added or settled it should raise an account operation, this is a Golden rule of this domain so if, i think that application should not be responsible to perform this operation but the domain it self instead. The problem starts because account is an aggregate (Customer can also modify the state of account), So without inject an repository in an domain service or method to load account, can i make this rule just inside the domain? – George Nov 17 '19 at 05:23
  • But if i inject the repository in an aggregate method or a service to load and save account, i will make the domain aware of persistence. I really don't know what's the most elegant solution here. Another option is make all aggregate methods internal and make a service that receives an collection of accounts and an contract the service handle the methods in both AR and ensure all necessary operations, and the application calls the service sending the two AR – George Nov 17 '19 at 05:27
  • But i really don't know what's the best option – George Nov 17 '19 at 05:28
  • Forget about using repositories inside domain objects, but is ok to have a service, like an application service, that retrieves everything you need with those repositories you mentioned, and then it passes everything to a domain service that is responsible to apply your domain rules and logic. You need to focus on how you could separate responsibilities. An application service should just be a facilitator for your domain, like retrieving aggregates from DB, but is your domain that actually perform logic upon those aggregates. – rastafermo Nov 17 '19 at 10:18
-1

Let’s take the last question first. Events are for things that can be done asynchronously and in this case async won’t work. Any time an aggregate is saved it should satisfy all business rules so you have to deal with asset and the account at the same time.

Services should be used sparingly. They operate on more than one AR where none has an enforced relationship with the others. In your case, Contract owns all the other entities involved so all work should be done inside a method on Contract. If that requires a repository, then inject it into the Contract.

Brad Irby
  • 2,397
  • 1
  • 16
  • 26
  • Hi Brad thanks for answer, but in my case account should be a separate aggregate because there is other operations that is not related to Contract. I musy be able to handle accounts outside of an aggregate Contract – George Nov 12 '19 at 14:30
  • Account can still be a separate aggregate while being owned by the Contract, just not the aggregate root. the diff is that an AR does not guarantee validity outside its AR boundary so saving a valid contract does not necessarily mean the account is also valid – Brad Irby Nov 12 '19 at 16:00
  • Thanks Brad, i wlll try find one way – George Nov 12 '19 at 16:58
  • One more doubt in this case, the aggregate Contract will hold reference to other aggregate Account that is correct? – George Nov 12 '19 at 17:41
  • So in AR Contract we have a behavior ``public void AddAsset(decimal assetValue, int assetType) { this.Assets.Add(new Asset(assetValue, assetType)); AccountingRules rules = this.IAccountingRulesRepo.GetByAssetID(assetType); Account accountDebit = new Account(rules.DebitAccount); Account accountCredit = new Account(rules.CreditAccount); accountCredit.Credit(assetValue); accountDebit.Debit(assetValue); this.IAccountRepo.Save(accountCredit); this.IAccountRepo.Save(accountDebit); }`` – George Nov 12 '19 at 18:00
  • In general, yes, but I would clean it up a bit and add some exception handling, like this https://gist.github.com/bradirby/f51a0e9f4cf0792ff7c55ff7de0245ce – Brad Irby Nov 12 '19 at 20:23
  • Thank you so much Brad, it clarify a lot of things – George Nov 12 '19 at 20:27