Wrox Programmer Forums

Need to download code?

View our list of code downloads.

| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
BOOK: Patterns, Principles and Practices of Domain-Driven Design
This is the forum to discuss the Wrox book Patterns, Principles and Practices of Domain-Driven Design by Scott Millett; ISBN: 978-1-118-71470-6
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Patterns, Principles and Practices of Domain-Driven Design section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developers’ questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old May 29th, 2015, 03:47 AM
Authorized User
Points: 136, Level: 2
Points: 136, Level: 2 Points: 136, Level: 2 Points: 136, Level: 2
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2015
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
Lightbulb Expressive Domain Focused APIs

Thank you very much for the awesome book. I already finished reading the book and now implementing different aspects of it.

My question is about the Expressive Domain Focused APIs that you are talking about on page 602. I'm using NServiceBus to implement a scenario where the UI sends a command called 'DeactivateProduct'. There is a command handler called 'DeactivateProduct' and another event called 'ProductDeactivated'. The command handler gets the product from the repository and change the status to 'deactivated' and sends a 'ProductDeactivated' event. The 'ProductDeactivated' event has a handler also.

How can I make the handler for the command and the event more expressive? My concern is about getting lost in many handlers.

I think the 'DeactivateProduct' command can be a member of the app service. The app service method can send a command through the NServiceBus bus called 'DeactivateProduct' which is ultimately being called by the UI.

How can I express the 'ProductDeactivated' event? Should there be a method called 'ProductDeactivated' on the product entity? Or the product entity should be derived from the IHandleMessage and have an implementation of the Handle method?

I appreciate your response.

Last edited by varghesep; May 29th, 2015 at 03:50 AM..
Reply With Quote
  #2 (permalink)  
Old May 29th, 2015, 04:24 AM
Wrox Author
Points: 237, Level: 4
Points: 237, Level: 4 Points: 237, Level: 4 Points: 237, Level: 4
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2015
Posts: 59
Thanks: 1
Thanked 5 Times in 5 Posts
Smile

Hi,

I'm really happy to hear that you enjoyed the book and are starting to put some of the concepts into practice

I would almost-certainly have a Product.Deactivate() method. That is precisely what we mean by an expressive behaviour-focused API. A method that expresses a domain concept and encapsulates the Entity's state so that it cannot be modified by other parts of the system.

In general, I'd recommend having an application service named after the business use case, which is DeactivateProduct, which is invoked in your DeactivateProduct command handler.

That app service would then load the Product via a repository and call the Deactivate() method. Inside the app service, you would then publish the external ProductDeactivated event using Bus.Publish() once Product.Deactivate() has returned.

Implementing the IHandleMessages interface on an Entity would lead to technical concepts obscuring domain concepts and it could make dealing with the lifecycle of an Entity tricky, so I would recommend avoiding that.

You could also implement this scenario using the DomainEvents as shown in Chapter 18. However, you would still have the Product.Deactivate() method. This implementation would differ in that Product.Deactivate() would raise an internal ProductDeactivated event which the service layer handles by publishing the external ProductDeactivated event. This would work with any of the Domain Events pattern options shown in Chapter 18.

Hope that helps. But Please feel free to ask more questions.

Nick

Last edited by nick_t; May 29th, 2015 at 07:36 AM..
Reply With Quote
  #3 (permalink)  
Old May 29th, 2015, 08:21 AM
Authorized User
Points: 136, Level: 2
Points: 136, Level: 2 Points: 136, Level: 2 Points: 136, Level: 2
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2015
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
Lightbulb Expressing the handlers as APIs

Thanks for the quick response.

I went through the Chapter 18. I see a few different implementations that you suggest to idecouple the sender and receiver. In my case I wont be able to use them but only NServiceBus. So, I have to depend on the Bus.Send as you suggest on Page 414.

Your suggestion in the previous response to send the ProductDeactivated in the app service will help to move the infrastructure concern out of the domain. This has a side effect because you have to go to the app service to see what happens next. I would rather prefer using Bus.Send in the Product.Deactivate method and send a ProductDeactivated event.

Let me take the case little further. Take a case where I have a different bounded context called Purchase. The business requirement is the purchaser should stop buying the product if it is deactivated.

The concern that I mentioned in my previous post can be visible in this example. I prefer expressing the concern as APIs rather than events but still have to use NServiceBus.

My questions are:

1. In the Purchase BC, who should handle the ProductDeactivated event? Is it the app service or the domain service or the product? Please see the next question.

2. There will be Product.StopBuying() method which sets a flag. This should happen inside a Handle(ProductDeactivated product). Where this handler should be implemented? In the app service or domain service? Or the Product itself? Note: The product entity in the purchase BC and the catalog BC are different.

Appreciate your response.

Last edited by varghesep; May 29th, 2015 at 08:27 AM..
Reply With Quote
  #4 (permalink)  
Old May 29th, 2015, 08:46 AM
Wrox Author
Points: 237, Level: 4
Points: 237, Level: 4 Points: 237, Level: 4 Points: 237, Level: 4
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2015
Posts: 59
Thanks: 1
Thanked 5 Times in 5 Posts
Default

Hey,

It's good to see that you have a separate Product entity in the the different bounded contexts. That shows you understand the importance of linguistic boundaries

One page 414 the Bus.Send() call is happening inside an event handler that lives in the service layer. This is an external event that is published between bounded contexts. We recommend publishing external events from the service layer, but you can do it multiple ways....

If you want to publish external events from the domain, but you don't want to publish an internal event using the Domain Events pattern, you can create a domain service contract as shown on page 394. Using this approach, you would have an interface in the domain, perhaps something like IProductDeactivatedNotifier. But the implementation will live in the service layer. There's an example on page 398 of using a domain service in the domain.

There are challenges involved when you want to inject a domain service into an entity though. This is also discussed from page 398 onwards in the section "In the Domain".

Quote:
Your suggestion in the previous response to send the 'ProductDeactivated' in the app service will help to move the infrastructure concern out of the domain. This has a side effect because you have to go to the app service to see what happens next. I would rather prefer using Bus.Send in the Product.Deactivate method to send a ProductDeactivated event.
I'd just like to back up and discuss the concern you raise here. Your point is valid, but you can look at this configuration in multiple ways. Since the event is external it is handled by other bounded contexts, so it isn't part of the workflow inside the bounded context that sends it. Basically, there's nothing that comes after it inside this domain model. So, it's worth reconsidering. Adding Bus.Send to your domain to send an external event is really starting to clutter the domain with technical concerns.

Quote:
1. In the Purchase BC, who should handle the ProductDeactivated event? Is it the app service or the domain service or the product? Please see the next question.
The most common approach is that initially the event will be handled by an NServiceBus handler that is implemented within your service layer. That would then invoke an application service that would load an entity from the domain and call a method on it.

I think Figure 25-1 could be a useful visual indication of what I am suggesting. It shows how external events are sent from an application service in bounded context A to an application service in bounded context B.

If you imagine bounded context B is your Purchasing bounded context, assume there is an application service in there that handles the message from the application service in bounded context A and invokes the application service in bounded context B.

Quote:
2. There will be Product.StopBuying() method which sets a flag. This should happen inside a Handle(ProductDeactivated product). Where this handler should be implemented? In the app service or domain service? Or the Product itself? Note: The product entity in the purchase BC and the catalog BC are different.
Since this handler is handling an external event it should live in the service layer. Going back to Figure 25-1, it is the handler that receives the message from bounded context A, and it invokes the application service in bounded context B. Therefore it lives in the service layer of bounded context B (your purchasing bounded context).

Note: I refer to the "service layer" which is also known as the application service layer or the application layer. In Figure 25-1 it is labelled the application layer.

Thanks for you questions. This is fun. Let me know if I can provide any further assistance.

Last edited by nick_t; May 29th, 2015 at 08:54 AM..
Reply With Quote
  #5 (permalink)  
Old May 29th, 2015, 10:43 PM
Authorized User
Points: 136, Level: 2
Points: 136, Level: 2 Points: 136, Level: 2 Points: 136, Level: 2
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2015
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
Default Testing events

Thanks for the response. It is more clearer.

Jimmy Bogard wrote about a better design for testing which can be seen here. However this has a dependency on a dispatcher.
Reply With Quote
  #6 (permalink)  
Old May 30th, 2015, 03:28 AM
Wrox Author
Points: 237, Level: 4
Points: 237, Level: 4 Points: 237, Level: 4 Points: 237, Level: 4
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2015
Posts: 59
Thanks: 1
Thanked 5 Times in 5 Posts
Default

I've spoken to a few people using the Domain Events pattern recently, and that alternative approach - using a dispatcher - is what they were all using. We did cover that version of the pattern in the book as well.
Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Same pages for sub domain from main domain vivek_inos ASP.NET 1.0 and 1.1 Professional 1 February 13th, 2007 10:15 AM
Accessing Windows Task Manager through APIs vishnu_attur Visual C++ 1 September 1st, 2005 05:31 PM
Using dSign 3.0 APIs in .NET prasanthknair General .NET 0 December 14th, 2004 08:29 AM
How Could I use C APIs with different DataType?? 6cet6 VS.NET 2002/2003 0 March 24th, 2004 09:20 PM



All times are GMT -4. The time now is 09:12 PM.


Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.