Shared business logic and events in DDD

Viewed 35

I am currently checking out the DDD pattern and (tried) to refactor a project of mine accordingly.

Now I got a case where I don't really know what to do: Some business logic can be called by multiple entities. In my case it's possible to mark items as hidden.

The item can be a Product or a Category (or many more).

The related event is called MarkedItemAsHidden, fired by an action handler called MarkItemAsHidden, which accepts the item as first parameter and fires the event based on the item's class.

So I got:

  • Events: MarkedItemAsHidden
  • Actions: MarkItemAsHidden($item)
  • Projector: HidingProjector

But where do I put those classes?

My app has a Domain-directory, which includes:

  • Product
  • Category
  • Cart
  • ...

but I can't really decide where to put these "shared classes".

1 Answers

Some of what you are describing lies outside the boundaries of your Domain.

Your Domain starts from the Application Services. Application Service lie on the boundary of your Domain. The job of the Application Service is to translate external messages into Domain Actions.

For Example: Assuming you have a complete application with UI and Domain. You want to mark an "item" as Hidden. So you:

  1. Trigger from your "Action Handler" that might be in the UI (a button that's clicked as an example.). This is outside of the Domain. Your click generates an event that is handled by the ApplicationService(ItemAppService). How exactly the event gets to the Application Service is an implementation detail (it's not a DDD concern). For Example: ItemAppService could be a Controller class in a Rest API App. In this example, your event is a HTTP Request and the Implementation Detail would be something like the ASP.net core API framework that routes that HTTP call to your Controller.

  2. ItemAppService.Hide(ID: String) is the method that's ultimately triggered. ItemAppService is in the Domain and Using Domain Concepts like Factories and Repositories, it can retrieve an instance of "Item".

  3. After retrieving the "Item", it'll then call a DomainService (or the appropriate Domain Class based on your Ubiquitous Language) that knows how to hide an item.

  4. It then returns some sort of a response to the caller on the results.

ItemAppService doesn't care how its hide function is called. You can't pass hide a Domain Entity because that'll mean that the consumer of the Domain action knows what and how to get an Entity.

If your intention is to use Events and Triggers as part of your Domain Model, those concepts must be translated into the Ubiquitous Language. When you do something like "generate an event" inside your Domain, your Domain doesn't care how you "generate an event" so that logic or processing is usually left to something outside of the domain (that's injected in through IOC) that can contain the specific knowledge of how to "generate an event".

Related