DDD session

36 views
Skip to first unread message

Udi Dahan

unread,
Aug 14, 2008, 9:56:14 AM8/14/08
to altnetisrael
Just finished watching the DDD recording.

I think that the first step in getting a business logic rich domain
model is to follow this rule:

The service layer, after retrieving the relevant domain objects with a
repository, can only call one method on one object from the domain.

For an example, look at this post:

http://www.udidahan.com/2008/02/15/from-crud-to-domain-driven-fluency/

Hope that helps,

--
Udi Dahan - The Software Simplist

Gustavo Ringel

unread,
Aug 14, 2008, 10:09:08 AM8/14/08
to altnet...@googlegroups.com
Good post. I sometimes do the traditional ORM actions as you called them and the code is not as simple to read as the one you are proposing...

Anyway you should be called IUdi IDahan...interfaces all the way :).

Well, its a change of mind i have done partially...sometimes i still live with the pitiable Appointment...

Gustavo.

Ayende Rahien

unread,
Aug 14, 2008, 10:21:30 AM8/14/08
to altnet...@googlegroups.com
Udi,
Assumes that the code need to generate additional actions. The example we keep getting back to is sending email :-)
How would this look like? Would the service know about this? Or is this handled in the entity?

Udi Dahan

unread,
Aug 14, 2008, 11:09:41 AM8/14/08
to altnet...@googlegroups.com

> Assumes that the code need to generate additional actions. The example we keep getting back to is sending email :-)

> How would this look like? Would the service know about this? Or is this handled in the entity?

 

The logic that says that now is the time to do X, that would be in the domain. The actual doing of X probably should be external to the domain.

 

On email…

 

Before getting into the DDD part of the answer, we need to understand failure scenarios.

 

Let’s say that when an order is received we need to send an email to the user – a common requirement.

Now, let’s consider what happens when the SMTP server is down – it happens.

If we were to try to send the email as a part of the code that performs the transaction of handling the order, we may timeout effectively loosing the order – not good.

Therefore, the sending of the email should be performed asynchronously with respect to the receipt of the order, that is, we can successfully receive the order and later, try (and try again) to send an email and be consistent with respect to the business requirements.

 

Back to the domain:

 

The domain can raise an event stating OrderAccepted – as I demonstrated in this blog post:

 

http://www.udidahan.com/2008/02/29/how-to-create-fully-encapsulated-domain-models/

 

In our service layer we would have an object responsible for the rule “when an order is accepted, need to send an email” that would subscribe to that event. When the event fires from the domain model, our SendEmailMessageWhenOrderAccepted object would use some kind of “bus” to send a EmailUserMessage with the relevant information.

 

Another process/server in the system would be responsible for handling EmailUserMessages and using the SMTP server to do so.

 

I have the code up that does the messaging and sending email stuff here:

 

http://www.udidahan.com/2008/06/06/web-scalability-slides-and-code/

 

I’ll also be putting up the thread-safe “events infrastructure” on my blog soon, so keep an eye out for that if you do go this route.

 

Does that help?

 

--

Udi Dahan - The Software Simplist

 


No virus found in this incoming message.
Checked by AVG - http://www.avg.com
Version: 8.0.138 / Virus Database: 270.6.3/1610 - Release Date: 13/08/2008 16:14

Ayende Rahien

unread,
Aug 14, 2008, 11:39:46 AM8/14/08
to altnet...@googlegroups.com
Let us take it one step further, why should the service handle this event ?
Why not send a real message directly from the domain?

That is, something like:

// domain method
public void CompleteOrder()
{

   new NotifyUser{ ... } .Send();// Or maybe use the bus passed as argument, or something in this order

Udi Dahan

unread,
Aug 14, 2008, 11:48:01 AM8/14/08
to altnet...@googlegroups.com

That would introduce a dependency on the concept of messaging into the domain model. I would assert that the same domain model could be used with a regular web services service layer and one that uses messaging. In my opinion, separation of concerns is first and foremost about concepts and only after that about actual code dependencies.

 

The farthest I would go with this would be to have the domain raise an event NeedToEmailUser. However, the data in that event would need to be generic enough that it wouldn’t matter if we were doing HTML, RTF, or plain text emails – same goes for text messaging, or any other external communication.

 

Does that make sense?

Ayende Rahien

unread,
Aug 14, 2008, 11:56:06 AM8/14/08
to altnet...@googlegroups.com
I don't see SoC problem with introducing the _concept_ of messaging.
Or, to be rather more exact, I don't like the idea of using CLR Events in this fashion, because it seems like the calling code now have much deeper ties to the domain than it should.
Knowing that a piece of code would raise an event, as an example, is a problem.

Ken Egozi

unread,
Aug 14, 2008, 12:00:39 PM8/14/08
to altnet...@googlegroups.com
I'd say that "Send an Email" is a Domain concern and should be expressed within a Domain Service (without implementation ofcourse)
now the implementor of IEmailService would put the message in a Queue/DB-table/DirectlyToSmtp/TieItToADove.
it's not the Service Layer responsibility.

Ayende Rahien

unread,
Aug 14, 2008, 12:04:30 PM8/14/08
to altnet...@googlegroups.com
I would take this a step further.
The request to send email shouldn't involve a service.
Dispatching a message can be part of the domain

Ken Egozi

unread,
Aug 14, 2008, 1:53:12 PM8/14/08
to altnet...@googlegroups.com
the service could be a part of the domain

domain service == when a piece of logic span across aggregate boundaries.
so let's say you create an account, and a person, and you associate the account with that person, you won't put it in Person as Person behaviour has nothing to do with accounts. you won't put it on Account as an account is valid without a Person connected to it (say an account which is for an external application to do stuff through some API).
so:

IAccountCreationService.Execute (...) {
  create account;
  create person;
  associate account to person;
  call IEmailService to send message to someone;

Udi Dahan

unread,
Aug 14, 2008, 2:34:03 PM8/14/08
to altnet...@googlegroups.com

Who said the calling code is the one that would necessarily subscribe to the event?

 

You could have one service layer class which handles messages, dispatching calls to the domain model. Another class, not necessarily even in the service layer subscribes to the NeedToSendEmail event and handles it.

 

> Knowing that a piece of code would raise an event, as an example, is a problem.

 

No more Button1_Clicked?

Udi Dahan

unread,
Aug 14, 2008, 2:40:54 PM8/14/08
to altnet...@googlegroups.com

I might tighten up your assertion Ken:

 

The need to notify a user is a domain concern – sending an email is one implementation of that, which may depend on the users preferred contact settings.

 

So, while the domain should say WHEN a user needs to be notified (events are a good way to do that), why should it depend on the way that occurs (IEmailService)?

 

I find that the greatest value comes from having an entirely independent domain model – testability, maintainability, versionability, etc.

 

--

Udi Dahan - The Software Simplist

 

Udi Dahan

unread,
Aug 14, 2008, 2:43:52 PM8/14/08
to altnet...@googlegroups.com

Then what happens when you get something that works on accounts and products? Another domain service? And then something that works on all three? Another domain service which “orchestrates” the others, or bypasses them? Is this not the path to procedural hell?

 

If you can’t tell, I’ve never liked those domain services J

 

--

Udi Dahan - The Software Simplist

 

Ken Egozi

unread,
Aug 14, 2008, 2:46:26 PM8/14/08
to altnet...@googlegroups.com
so, IUserNotificationService instead implemented by EmailUserNotificationService.

the thing is - who is in control.
I think that explicitly calling the notification service from the service that is doing the change is the thing.
and, if the logic was well encapsulated within a domain entity, thus no domain service was there, I see no problem with putting the IUserNotificationService (which still is a domain service) as a dependency of User entity.
if we're denying our entities from our general development practices (like DI), then they're not POCOs anymore right?
the only 'problem' is that the entities are not being created by the IoC but rather by the ORM. so we need to use some kind of a service locator within the entities (which is again, perfectly fine) or try to hook into our ORM to make is create instances through IoC.

Ken Egozi

unread,
Aug 14, 2008, 2:47:30 PM8/14/08
to altnet...@googlegroups.com
it's not procedural hell.
it's a bunch of classes, each very well defined and encapsulated, with an easy to understand flow and meaning.

Ayende Rahien

unread,
Aug 14, 2008, 2:48:08 PM8/14/08
to altnet...@googlegroups.com
Can you show some sample code to explain what you mean by that? What other class? How is it hooked up?

Udi Dahan

unread,
Aug 14, 2008, 2:52:16 PM8/14/08
to altnet...@googlegroups.com

Sample code – a singleton class which is brought up at service startup and subscribes to DomainEvents.NeedToNotifyUser. That’s it. No magic.

Udi Dahan

unread,
Aug 14, 2008, 2:56:22 PM8/14/08
to altnet...@googlegroups.com

“A bunch of classes” – why didn’t you say so in the first place?

 

;-)

 

If “create account” appears on more than one class, that’s a violation of the DRY principle. If one service calls another, that’s the first step towards procedural hell. For larger systems, this can be the kiss of death. Smaller systems may not feel the pain as much.

Udi Dahan

unread,
Aug 14, 2008, 2:58:01 PM8/14/08
to altnet...@googlegroups.com

> if we're denying our entities from our general development practices (like DI), then they're not POCOs anymore right?

 

How is it that if no dependencies need to be injected that the entities aren’t POCO anymore?

Ayende Rahien

unread,
Aug 14, 2008, 3:04:38 PM8/14/08
to altnet...@googlegroups.com
Something like this?

public class DomainEvents
{
   public static Action NotifyUser = delegate 
   {
         new NotifyUser().Send();

Udi Dahan

unread,
Aug 14, 2008, 3:17:04 PM8/14/08
to altnet...@googlegroups.com

Actually more like this:

 

public static class DomainEvents

{

                public static DomainEvent<NotificationArgs> NeedToNotifyUser = new DomainEvent<NotificationArgs>();

}

 

public class HandleNeedToNotifyUser

{

                public HandleNeedToNotifyUser(IBus bus)

                {

                                DomainEvents.NeedToNotifyUser.Subscribe(

                                                bus.Send(new NotifyUserMessage( /*data from args*/)); //or SendEmailMessage if you like

                                );

Ayende Rahien

unread,
Aug 14, 2008, 3:46:39 PM8/14/08
to altnet...@googlegroups.com
Why do you have this indirection?
Why not send the NotifyUserMessage directly from the entity?

Udi Dahan

unread,
Aug 14, 2008, 3:55:01 PM8/14/08
to altnet...@googlegroups.com

That would create a dependency from the core business logic of the system to its external schema and the API for working with that schema. I prefer the flexibility of being able to independently vary each of them.

Ayende Rahien

unread,
Aug 14, 2008, 4:00:50 PM8/14/08
to altnet...@googlegroups.com
Good answer, although I am not sure that I agree.
The schema can be dealt with on as needed basis, not from the get go. I am not sure what you mean by API for working with the schema, however.

Udi Dahan

unread,
Aug 14, 2008, 4:05:56 PM8/14/08
to altnet...@googlegroups.com

API = bus – the way we send messages.

Ayende Rahien

unread,
Aug 14, 2008, 4:11:04 PM8/14/08
to altnet...@googlegroups.com
Hm, I am not seeing how this relates.
public class DomainMessaging
{
   public static Action<IMessage> Send;
}


Now you don't have API issues.

Udi Dahan

unread,
Aug 14, 2008, 4:22:33 PM8/14/08
to altnet...@googlegroups.com

Where’s publish?

Ayende Rahien

unread,
Aug 14, 2008, 4:28:47 PM8/14/08
to altnet...@googlegroups.com
Send == Publish
I am not using the exact terminology as NSB, sorry.

DomainMessaging.Publish( new NotifyUser{} );

Udi Dahan

unread,
Aug 14, 2008, 5:00:20 PM8/14/08
to altnet...@googlegroups.com

Careful – keep going down this path and you’ll have collapsed your service layer and domain model together. While that may be OK for DDDD within a service boundary, its applicability is limited.

Ayende Rahien

unread,
Aug 14, 2008, 5:05:12 PM8/14/08
to altnet...@googlegroups.com
Can you explain why?
Consider the fact that the domain model can publish messages, and handlers take care of them. What is the purpose of the service layer in this case? 

Udi Dahan

unread,
Aug 14, 2008, 5:07:53 PM8/14/08
to altnet...@googlegroups.com

Handlers are the service layer. The question is, if your domain model can send messages, will it also reply?

Ayende Rahien

unread,
Aug 14, 2008, 5:12:57 PM8/14/08
to altnet...@googlegroups.com
My thinking is that it send messages when it want to do something extra.
Generate email, contact a separate system, etc.
Logic is in model, mainly. Sagas for orchestrations.
Handlers to locate the appropriate entity and call the model on it, or to handle the external system requests.

Can you think of a scenario when a reply is needed?

Udi Dahan

unread,
Aug 14, 2008, 5:21:49 PM8/14/08
to altnet...@googlegroups.com

> Can you think of a scenario when a reply is needed?

 

In my design, handlers reply. That’s because outside the service layer, nobody does messaging.

There are many cases where messaging interactions are still request/response – require a reply.

 

Re “contacting a separate system”, since the service layer can’t know which object in the domain model initiated the call, how would it know to route the response to that object?

Ayende Rahien

unread,
Aug 14, 2008, 5:34:27 PM8/14/08
to altnet...@googlegroups.com
Let us consider something like this, completing an order. Just so we will have the context to talk about.

public void Complete()
{
       OrderNumber = CreateOrderNumber();
       new NotifyUserOnOrderCompletionMessage { OrderId = Id, UserId = User.Id } .Publish();
       new OrderCompletedEvent{ OrderId = Id}.Publish();
}

And assume that we want to get the order number of a completed order.
The responsability for replying to the completor would be on the handler. 
The domain would only publish interesting message. 

Udi Dahan

unread,
Aug 14, 2008, 5:52:09 PM8/14/08
to altnet...@googlegroups.com

I’ll let you in on a secret…

 

Most of this is moot.

All of this is handled by sagas.

Ayende Rahien

unread,
Aug 14, 2008, 5:56:24 PM8/14/08
to altnet...@googlegroups.com
Probably.
Reply all
Reply to author
Forward
0 new messages