5

I am a bit new to DDD and bear with me if my understanding seems way off.

My question is about Udi's solution to domain events, particularly the class DomainEvents (see code below)

An excerpt from Udi's code. It lives domain model as a static class.

public static class DomainEvents
{ 
   [ThreadStatic] //so that each thread has its own callbacks
   private static List<Delegate> actions;

   public static IContainer Container { get; set; } //as before

   //Registers a callback for the given domain event
   public static void Register<T>(Action<T> callback) where T : IDomainEvent
   {
      if (actions == null)
         actions = new List<Delegate>();

      actions.Add(callback);
  }

  //Clears callbacks passed to Register on the current thread
  public static void ClearCallbacks ()
  { 
      actions = null;
  }

  //Raises the given domain event
  public static void Raise<T>(T args) where T : IDomainEvent
  {
     if (Container != null)
        foreach(var handler in Container.ResolveAll<Handles<T>>())
           handler.Handle(args);

     if (actions != null)
         foreach (var action in actions)
             if (action is Action<T>)
                 ((Action<T>)action)(args);
  }
} 

Based on the code above, in order for the DomainEvents to be used by the domain model, both must first be in the same assembly. Which makes the DomainEvents part of the domain model right? (I may be wrong here)

So my question is: Does DomainEvents itself breaks the rule "ubiquitous language of DDD"? Because it's implementation does not pertain to any domain.

My other concern is that the static member IContainer creates an ioc-container-dependency in the domain model. Though I am not really sure if Udi's IContainer is an interface or an actual IoC container.

My 2nd question is: What is this IContainer in the DomainEvents class? If it is truly an IoC container then doesn't it break the rule of "DDD should not have an infrastructure in the domain"? Is my understanding correct that an IoC-Container is considered an infrastructure? (Please correct me if I'm wrong)

If you may find any of this confusing, please say so.

EDIT:

I have built my projects where the domain model is separated on its own assembly (I call this business layer) with absolutely no references to any infrastructure components. See onion architecture.

enter image description here

Now I want to incorporate the domain events pattern. But doing so forces me to add infrastructure components to my business layer. Components being the DomainEvents and an IoC framework just to satisfy the IContainer, both having no relation to the domain whatsoever.

Isn't one of the idea of DDD is about separating the infrastructure from the domain?

Now I will play the pragmatic programmer, I just wanted to know that is it generally ok to do so? are there alternatives? What are you thoughts on this approach? Am I missing something basic here?

3
  • The "onion architecture" is one architecture (and IMO a rather old-fashioned, unwieldy one) and is not synonymous with DDD. Are you asking if this fits in DDD, or if it fits in this one particular architecture you chose? Obviously it doesn't work with that architecture, which is why that architecture sucks for SOA where pub/sub is ubiquitous. But pub/sub is part of your domain if you choose to make it part of your domain; the idea of DDD is for business owners to be able to understand the domain model, and most people understand pub/sub far better than a mess of dependencies.
    – Aaronaught
    Dec 29, 2013 at 19:36
  • @Aaronaught DDD might not be about separating domain from infrastructure, but it is only sane way how to do it. If you combine your domain and infrastructure, you will find it will make code non-self-descriptive, hard to reason about and hard to unit test.
    – Euphoric
    Dec 29, 2013 at 19:56
  • If you decide to go for a static reference or if you want to inject a domainevents instance into each entity method is up to you, the static approach makes your API cleaner, but do keep in mind that if you use anything like async await inside your code for whatever reason or pass the same entity off to another thread, the thread static version will mess things up for you. Dec 30, 2013 at 13:10

3 Answers 3

3

I agree with you for the first sub-question:

From my point of view the class DomainEvents is infrasturcure code that should not be implemented in the domain itself.

So instead of a static class DomainEvents in the domain layer i would prefer a nonstatic class DomainEvents in an infrastructure layer that implements an IEventHandling interface (in the domain layer) with methods Register, Raise, ...

The ioc container injets the implementation of IEventHandling as singleton to every class that needs DomainEvents.

 > My 2nd question is: What is this IContainer in the DomainEvents class?

The IOC-Container is infrastructure code so it is hidden behind an interface.

From architectual point of view i prefer referecing the ioc container only in one initialisation module and nowhere else. Therefore the icontainer should not be referenced from the class DomainEvents. Instead i would prefer to have a method DomainEvents.RegisterHandler and i would rename DomainEvents.Register to DomainEvents.RegisterEvent.

The ioc container initialisation module is repsonsible to register all handlers.

4
  • You really should read Udi's post on this - he and NServiceBus are all about abstractions and dependency injection, but that only adds value to the extent that it reduces coupling or improves testability. Hiding DomainEvents behind an interfaces accomplishes neither of those things; it's complete testable without the dependency injection and the coupling is the same either way (one class, one method). In fact this is pretty much the only part of the framework that isn't hidden behind an interface.
    – Aaronaught
    Dec 29, 2013 at 19:27
  • 1
    @Aaronaught That is actually wrong, hiding the mediator service behind interface does reduce the coupling, because then the code using the mediator doesn't know about how the mediation happens. And it also improves testability, because you can mock the mediator and don't have to reason about inner workings of the mediator when you only want to test the publishers and subscribers.
    – Euphoric
    Dec 29, 2013 at 19:58
  • 2
    @Euphoric: That makes no sense. The code using the mediator already knows nothing about how the mediation happens. The only difference is "instance vs. static". And while in many cases there's a major benefit to being able to mock/stub/whatever, it's not a benefit here because the event broker already provides all of the same tools that a mock does. It doesn't do anything by itself, it just allows you to trigger certain actions when certain events happen, which is (almost) exactly what a mock does.
    – Aaronaught
    Dec 29, 2013 at 20:07
  • 1
    I'm curious, how would you implement this IEventHandling without breaking the abstraction of every class in the domain model? are you planning to inject it to the constructor in every class? That would just pollute my entities. The DomainEvents seems more attractive at this point.
    – Yorro
    Dec 30, 2013 at 3:52
2

The DomainEvents isn't part of the domain model, it's an infrastructure component used to support loosely-coupled domain models.

The container isn't strictly required (which is why the code as written allows it to be null), it just allows a declarative rather than imperative style of registering handles.

In other words, you can use it either like this:

public SomeClass()
{
    DomainEvents.Register<SomethingHappened>(() => RespondToSomething());

    void RespondToSomething() { ... }
}

Or like this:

public class SomeHandler : Handles<SomethingHappened>
{
    public void Handle(SomethingHappened e) { ... }
}

Both accomplish more or less the same thing, but the first version requires an instance to exist before the event is published. Each version has its place; the first version tends to be more useful in rich client applications, where it is essentially the well-known Event Broker pattern, and the second version is more useful in service applications, where in Udi's world the pattern is now actually formalized as the In-Memory Bus and is not a whole lot more than a generic in-process, non-durable message.

And yes, IContainer is in fact the IoC container, but again, this is an infrastructure component, nothing in the domain model itself depends on the container.

I'm not sure what you mean when you refer to "break[ing] the rule of not having infrastructure in the domain" - I'm not familiar with this rule, but even if you want to follow it, sometimes purity really needs to take a back seat to pragmatism. If the end result is collapsing 10 dependencies down into 1 dependency without a wrapper, that's a win, regardless of what architecture you're trying to follow.

4
  • 1
    With regards to the "not having an infrastructure in the domain", isn't one of the idea of DDD is about separating the infrastructure from the domain?
    – Yorro
    Dec 29, 2013 at 3:06
  • In order for the domain model to reference the DomainEvents it has to be in the same basket as domain model right?, this is my main concern. Please see my edited question (labeled as EDIT).
    – Yorro
    Dec 29, 2013 at 3:27
  • @Yorro: What "basket"? What are you talking about? You seem to be trying very hard to draw a physical line around what you're calling the "domain model", but unless you can find me some kind of reference to substantiate the claim that a domain model can't depend on infrastructure... well, it doesn't exist. In Udi's world (and SOA in general), domain models are represented as Sagas, which means they already have an infrastructure dependency (on the bus). Now, they shouldn't have any dependencies on shared data (e.g. making SQL queries), but that's a very different issue.
    – Aaronaught
    Dec 29, 2013 at 19:32
  • The phrase "in the same basket" is just common idiom. When domain model calls an infrastructure components, it introduces a bidirectional dependency, which I find not a good design.
    – Yorro
    Dec 30, 2013 at 8:44
1

The idea of some kind of Publish-Subscribe within domain is not bad. It might be good abstraction that within domain, some events happen and others can react to them. And some kind of mediator exists, allows loose coupling between publishers and subscribers. So within ubiquitous language, there can be "entity X subscribes to events of type Y and will do Z" and "entity X publishes event of type Y when Z happens". This answers your first question.

But the implementation is wrong. There should be some kind of service, that mediates between the publishers and subscribers. And within domain, the service will be represented by an interface. The actual implementation of the interface will be inside the infrastructure. This way, there is no need for any container in the domain, because container is part of the implementation. And this answers your second question.

For example, in your code, you are creating dependence of your domain on IoC container. But IoC is part of infrastructure, so the dependency is the wrong way. By adding an interface in between, you can correct the direction of the dependency and put the implementation into infrastructure, where it belongs.

9
  • 1
    @Aaronaught The point of interface is to separate the demands of the domain and the implementation of those demands by infrastructure. Yorro is having those problems EXACTLY because he has the implementation inside the domain. This is basic Dependency Inversion Principle.
    – Euphoric
    Dec 29, 2013 at 19:50
  • 2
    The point you're missing is that an event broker is a form of dependency inversion. It's an alternative to the more conventional point-to-point subscription model (EventHandler) or the imperative model of taking on several dependencies and embedding the entire workflow in the top-level model. The question is what additional value you gain from hiding the event broker behind an interface. It means that everything which uses it (which in SOA is... just about everything, period) now requires an additional constructor argument, which is huge overhead. What's the upside?
    – Aaronaught
    Dec 29, 2013 at 19:58
  • 2
    It's not "inversion between publishers and subscribers", that doesn't even make any sense, it's simply a form of dependency inversion. The event broker is a mediator. Without it, you would have dependencies between the individual endpoints. And no, unfortunately, you didn't explain why there is any practical benefit to "mediating" what is already a mediator - or if you did, then you communicated it poorly, because it's not evident from your answer or any follow-up comments. Why, in a practical sense, would you want to hide it behind an interface? What do you gain?
    – Aaronaught
    Dec 29, 2013 at 20:05
  • 1
    Honestly, even with your edit... it's like you're assuming that by depending on a particular class, you're depending on all of the things that class depends on. But that's simply not true, because nothing ever needs to create an instance of DomainEvents. It's completely opaque; anything that depends on DomainEvents depends only on DomainEvents. Whether it's a class or an interface makes very little difference here.
    – Aaronaught
    Dec 29, 2013 at 20:09
  • 2
    WTF? No, that's not how dependencies work. Otherwise it would defeat the whole purpose of abstraction. An interface doesn't magically make the dependencies go away, it just allows you to substitute something else - and in this case there's never anything else you'd want to substitute. You're referring specifically to an adapter pattern, not the DIP itself. Honestly, you really should just read Udi's entire post and not just the code snippet in the question, because he's already addressed almost all of this. Go read it. I'm not arguing anymore.
    – Aaronaught
    Dec 29, 2013 at 20:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.