Why not use an IoC container to resolve dependencies for entities/business objects?
F

2

87

I understand the concept behind DI, but I'm just learning what different IoC containers can do. It seems that most people advocate using IoC containers to wire up stateless services, but what about using them for stateful objects like entities?

Whether it's right or wrong, I normally stuff my entities with behavior, even if that behavior requires an outside class. Example:

public class Order : IOrder
{

    private string _ShipAddress;
    private IShipQuoter _ShipQuoter;

    public Order(IOrderData OrderData, IShipQuoter ShipQuoter)
    {
        // OrderData comes from a repository and has the data needed 
        // to construct order
        _ShipAddress = OrderData.ShipAddress;  // etc.
        _ShipQuoter = ShipQuoter;

    }

    private decimal GetShippingRate()
    {
        return _ShipQuoter.GetRate(this);
    }
}

As you can see, the dependencies are Constructor Injected. Now for a couple of questions.

  1. Is it considered bad practice to have your entities depend on outside classes such as the ShipQuoter? Eliminating these dependencies seems to lead me towards an anemic domain, if I understand the definition correctly.

  2. Is it bad practice to use an IoC container to resolve these dependencies and construct an entity when needed? Is it possible to do this?

Thanks for any insight.

Frechette answered 29/1, 2011 at 3:55 Comment(3)
just do stuff that you need to because it makes your work easier, not because probably this is how you should do itTape
As a self-taught programmer, I have gone that route, and it led to the software that is currently used by my company. A procedural/transaction script based software was what emerged, partly because it was easiest and party because I didn't know any better. It is absolutely painful to maintain and expand, which is why I'm taking the time to re-write it and seeking advice from people who have already overcome these problems on how not to make the same mistakes.Frechette
related: #828170Mackenzie
P
95

The first question is the most difficult to answer. Is it bad practice to have Entities depend on outside classes? It's certainly not the most common thing to do.

If, for example, you inject a Repository into your Entities you effectively have an implementation of the Active Record pattern. Some people like this pattern for the convenience it provides, while others (like me) consider it a code smell or anti-pattern because it violates the Single Responsibility Principle (SRP).

You could argue that injecting other dependencies into Entities would pull you in the same direction (away from SRP). On the other hand you are certainly correct that if you don't do this, the pull is towards an Anemic Domain Model.

I struggled with all of this for a long time until I came across Greg Young's (abandonded) paper on DDDD where he explains why the stereotypical n-tier/n-layer architecture will always be CRUDy (and thus rather anemic).

Moving our focus to modeling Domain objects as Commands and Events instead of Nouns seems to enable us to build a proper object-oriented domain model.

The second question is easier to answer. You can always use an Abstract Factory to create instances at run-time. With Castle Windsor you can even use the Typed Factory Facility, relieving you of the burden of implementing the factories manually.

Peking answered 29/1, 2011 at 12:15 Comment(7)
Thanks Mark. I've seen the Typed Factory and read your other posts on the Abstract Factory method, but I have never seen any examples of them being used to resolve entities. Is this because most people design their entities without any dependencies except a repository? Am I getting into trouble down the road if I make rigorous use of something like Typed Factory to resolve my entities that have outside dependencies?Frechette
The thing I was trying to say is that if your Entities contains other collaborators that may access other Entities, etc. you may run into all sorts of maintenance issues - not to mention the SRP violations and the N+1 issues. That's why Evans recommends treating each Entity as an Aggregate Root.Peking
In my example ShipQuoter pulls shipping rates for an order from a webservice (e.g. UPS). Would you make this a Service that accepts IOrder, or would you make it part of the domain object like Order.GetRates?Frechette
I would spend a lot of time figuring out how I could avoid a synchronous pull in the first place. You more you pull data in synchronous, blocking fashion, the more brittle your design becomes. That's why CQRS is such an attractive alternative.Peking
Thanks Mark, this gives me something to think about. I appreciate your time.Frechette
Your link to Greg's paper is dead. But it's still available here. And it appears like this is a newer version.Promenade
Clarification, anemic domain models have nothing to do with dependencies. You can have a rich domain objects with no dependencies as long as they encapsulate and perform domain logic, e.g. validations, calculations, business rules...Grantley
J
1

I know this is an old post but wanted to add. The domain entity should not persist itself even if you pass in an abstracted repository in ctor. The reason I am suggestion this is not merely that it violates SRP, it also contrary to DDD's aggregation. Let me explain, DDD is suited for complex apps with inherently deep graphs, therefore, we use aggregate or composite roots to persist changes to the underlying "children", so when we inject persistence into the individual children we violate the relationship children have to the composite or aggregate root that should be "in charge" of the life cycle or aggregation. Of course the composite root or aggregate does not persist it's own graph either. Another is with injecting dependencies of DDD objects is that an injected domain object effectively has no state until some other event takes place to hydrate its state. ANy consumer of the code will be forced to init or setup the domain object first before they can invoke business behavior which violates encapsulation.

Jaques answered 22/9, 2017 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.