Injecting services into entities

One of the comments that came up from the Strengthen your Domain series was the idea of injecting services into your entities, instead of using domain services, double dispatch or domain events.  For quite a long time, this was not easily possible technically, but some of the more mature ORM frameworks now support this scenario.

It’s a question that gets routinely asked on various ORM and DDD mailing lists, “How do I inject services into my entities”?  Even if it’s now technically possible, the answer is the same now as it was before: you don’t.

It seems like this ability could solve quite a few problems, where behavior in my entities gets too large, but I don’t want to completely remove the entry points for this behavior from my entities.  This is a good goal, but injecting services into entities (or worse, having the entity service locate them) is a wolf in sheep’s clothing.

It turns out that following this path for dependencies introduces a few not-so-obvious problems in your domain model design.

Problem 1: Confusion on what the dependency is used for

One of the design smells you’ll often find early when following dependency injection practices are services that take several dependencies whose usage is highly fractured.  One method uses dependency A, B and C, while another method uses D and E.  When changing the behavior of this class, it’s difficult to understand the nature, size and side effects of the change.

With a service in an entity constructor, the confusion can increase.  Typically, entity constructors are used to provide the invariants.  A Transaction cannot be described as such unless I provide the Transaction Type (deposit/withdrawal/transfer) and the amount.  With an additional service in the constructor, it’s not immediately clear why exactly I need this extra service.  Is it for some core behavior, or just one method or property?  When I start to modify this entity through unit tests, I now have to make a decision every time I use the entity on whether or not I need to supply this extra parameter, or just leave it null.  Typically, when a service has dependencies that are used for only certain operations, I just let the test fail and through trial and error try and figure out what is needed.  Which brings us to the next problem.

Problem 2: Difficulty testing

When a constructor requires a dependency, but only uses it for a subset of the object’s operations, then the dependency only becomes partially required.  I could supply a null value or pass in just a no-op stub, but it leaves us with a rather strange design.  This object says it needs all these parameters to do its job, but it only needs some of the parameters some of the time.  This is what I run into with an entity that takes a dependency.  The behaviors on an entity can grow over time, but a constructor usually stays fairly static.  Once the invariants are determined, these aren’t likely to change much over time.

As behaviors grow, some operations may need to rely on services.  For unrelated operations on an entity, I don’t want to be effectively punished for the complexity required in a separate operation.  Forcing me to supply a constructor dependency introduces pain.

Solutions

I have found that optional dependencies seem to fit just fine with entities.  For example, if I want to integrate logging into my operations, I can fairly easily implement the Null Object pattern, and allow my entity to be used without that optional dependency.  Because that logging class might be supplied as a property, it communicates explicitly that this dependency is not required.

Otherwise, I’ll stick to the more obvious solutions of domain services, double dispatch and domain events.  Injecting services into entities just makes them harder to understand and use.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Domain-Driven Design. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://thesoftwaresimpleton.blogspot.com/ Paul Cowan

    I think domain events or domain services are the preferable way of handling these issues.

    Passing a service into an entity “seems” equal to constructor injection.

  • http://thinkbeforecoding.com thinkbeforecoding

    When your entities publish their changes as Domain Events, there’s no need for text logging inside entities anymore.

    Having dependencies in entities looks like a design smell : Fields in entities represent their state and Services are not part of their state.

  • http://andyhitchman.wordpress.com Andy Hitchman

    I was one of the people asking for clarification on this point, so thanks for addressing it.

    To me, it seems wrong that the ‘consumer’ of an operation on an entity needs to pass the dependencies that allow the entity to work.

    An example I encountered recently was where an entity, say, Customer, needs to be able to lazily enumerate associated aggregates, say Orders. The interface Customer.GetOpenOrders() is a lot cleaner (obvious?) is it doesn’t need additional parameters like an order repository/service.

    I suppose you could more naturally express this specific case by inverting the dependency and having the order service take a customer entity.

    I agree that the partial requirement of injected services into a constructor for some subset of behaviour is hard to unravel and can make tests fragile. Adding behaviour that requires a new dependency in the constructor is also a problem for potentially breaking unit tests.

    Auto mocking solved these problems. Also, pushing all of the dependencies into a nested class and injecting this into the constructor helps keep the number of parameters on the constructor down to invariants plus one (at the risk of making the code less obvious).

    Do you consider these ‘solutions’ an improvement?

  • http://simon-says-architecture.com/ Szymon Pobiega

    The third problem is lifecycle management. Entities have very different lifecycle then services. Injecting services into entities ties their lifecycle to lifecycle of the entity. That can cause network connections to be held for much longer then necessary (if, for example service implementation contains WCF client).

    Another problem in injecting service into the entity is that is states clearly that particular service is part of the model. Is EmailSender (example of service) part of Customer’s (example entity) model? Clearly not.

  • http://isaiahperumalla.wordpress.com isaiah

    @andy
    In my experience having to pass a domain service such as a repository into an enity, is usually a hint something I need to rethink my design choices. In general an aggregate root should not have non-transient references to other aggregate roots. In your example Order seems like an aggregate root and doesnt seem right for customer to be holding references on to this.
    More over lifecycle of entities and services are completety different. . One of key benefits of tests is the feedback they provide and help guide your design, i’m not a fan of tools like auto-mocking container and among others, they silence the feedback from test and simple hide underlying design issues

  • http://andyhitchman.wordpress.com Andy Hitchman

    @isaiah

    So, if my Customer can’t contain a set of Orders (another aggregate), where does the responsibility for getting orders for a customer lie? Are you suggesting I need a service that takes a customer object or a specification for a customer and return a set of orders?

    Isn’t having the ‘GetOrders’ method on the Customer object preferable in terms of discoverability for maintenance in the future?

    The domain model says Customer have Orders, rather than needing to know that a service (/repository) can get Orders for Customers. (The GetOrders method is implemented to use this service internally)

  • http://isaiahperumalla.wprdpress.com isaiah

    Well it all really depends on the context, it may well be that customers has orders within its aggregate. But in that case Orders shouldnt have a repository of it own. In my experience Orders would be its own aggregate root, Orders have their own identity, not reliant on identiy o the customer,, a Customer could potentially have thousands of orders, its doenst fit well for customer to be managing all this. again all this depends on the context of your domain. anyways again the main thing from a DDD point of view is if it makes sense in your domain for orders to be part of the customer aggregate then Orders should’nt be retrieved from a repository, , it should be in the Customer, whether its lazy loaded or not is an implementation detail.
    “The domain model says Customer have Orders…” do you mean the domain experts say that ?

  • http://sm-art.biz ulu

    I think we already can have a lazy customer.Orders property without injecting a service. NHibernate or whatever ORM handles that for us. From this, customer.OpenOrders is just a simple LINQ query. In your tests, the entity will not query the database, even though you don’t mock any services. In production, you’ll have a proxy object with the required service auto-injected for you.

  • RichB

    Let’s say you have a database which stores encrypted credit card numbers.

    Obviously, the encryption key is held securely outside of the database. And it would make sense for a domain entity to be responsible for transparently encrypting/decrypting the credit card number.

    Would you inject the encryption key into this domain entity?

  • RichB

    Additionally, as an “encrypted credit card number” is a different “type” than something which is not encrypted, perhaps using an IUserType and then injecting the encryption key into this IUserType is a better way to model it?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @RichB

    Still no need to:

    public string GetCreditCardNumber(IDecryptor decryptor) {
    }

    If it’s an actual persisted value then yeah, IUserType would work. I’d probably go that route myself.

  • Michael Annucci

    The frustrating part for me is that there is a dearth of good information on this topic that yields truly best practices.  Everything that you read (Martin Fowler et. al.) suggests that the anemic domain model is a code smell. Inevitably if you suggest using lightweight DTO data containers with a service layer you get called some sort of anti-pattern procedural programmer. Yet, the reality is that for most MVC based forms over data applications you will end up with an anemic model using service layers for behavior if you want an easily testable and maintainable application.

    As example let’s talk about the Customer.Orders situation from the comments below.  It isn’t about weather Orders is a root or about lazy loading from O/RM.  I am more interested in the best methodology for creating testable, loosely coupled rich domain models.  I only see examples for the most trivial of cases with no real complex dependencies.  In reality an application that has a create  new Order behavior is much more complicated that merely persisting raw data into the DB.   Initially it seems obvious to place the NewOrder() method as part of the Order domain object. 

    Very quickly you will run into dependency issues were those dependancies are needed only for this method and will tightly couple the order to many other services/objects.  Something as simple as calculating the order total comes to mind.  You will need to access the Customer.Billing address in order to determine state and local taxes.  You will have multiple repository hits to get current tax rates.  Another hit to the Order.Products.Materials collection will be necessary since some Bill of Materials are tax exempt.  Then there is a call to the business rules service to validate that some order items either require or disqualify other line items.  Another call to Inventory to calculate shipping items on hand (and shipping time). Another call to  Shipping service with Customer.ShippingAddress to figure out estimated shipping costs.  When that is all done the Order.Salesperson and Customer need to get notified by email through yet another application service.

    I could go on but I hope you all get the point.  This quickly becomes a strongly coupled untestable system just to adhere to the rich domain model.  This could all easily be resolved by creating an IOrderProcessingService whose single responsibility is to coordinate the above workflow. Since all of those dependencies are required for the service you can use constructor injection or your favorite DI container to initialize the service rather than jamming them into a rich Order object as nullable properties. Simple, testable, maintainable but not “correct”?  I must be missing something here.

    • Anonymous

      Don’t assume that DTOs mean that your domain model is anemic. Imagine if your DTOs were actually command messages, and your domain model accepted command messages in a method.

  • Anonymous

    Have to agree with Michael Annucci – there seem to be lots of opinions out there, but not much consensus on best practice or analysis from the DDD experts of the pros and cons of each approach.  Here’s Dan Haywood,  a very capable guy, suggesting some of the approaches you are against:  http://danhaywood.com/2010/04/30/accessing-domain-services-from-entities/.  I also have concerns that in data heavy applications (as most I work with in financial services are), the pure DDD approach (what I think you are encouraging here) either 1) results in anemic domain entities (where the majority of meaningful processing is done in a domain service layer) or 2) fails to make the best use of the more efficient database processing.

  • David Leonhart

    In your solution do you mean to inject a “LoggingService” Nullobject via property setter (by a ApplicationService or DI container)?
    I do not like this approach.
    I rather raise a domain event (eg. OrderCanceled) which is handled by the LoggingService.