0

Lately, I have invested my efforts into learning and understanding DI. Now that I'm growing more fluent with it, some other concerns come up.

Shall list members be injected into domain model?

In the famous example of Ninject, the idea as I see it is:

public class Warrior {
    public Warrior(IWeapon weapon) { this.weapon = weapon; }

    public void Attack() { weapon.Hit(); }
}

public Archer : Warrior {
    // Here, the weapon would be bound to a bow.
    public Archer(IWeapon weapon) : base(weapon) { }
}

public Ninja : Warrior {
    // On the contrary, the weapon would here be bound to a katana.
    public Ninja(IWeapon weapon) : base(weapon) { }
}

Hence contextual binding to define what weapon should be created depending on what the IWeapon is injected into.

I understand that injecting a DAO into my model would be implementing the Active Record design pattern, which is considered somehow an anti-pattern by some people. Others would prefer POCOs as domain objects, simple data representation, which is not following the rules of DDD.

Back to my concern, I would say that Warrior, Archer and Ninja are all part of my domain model.

Now, what if my model has an IList<T> instead of a IWeapon? Would DI be of any use, or would it become useless?

public class MyClass {
    public MyClass(IList<MyOtherClass> myOtherClasses) {
        MyOtherClassesA = myOtherClasses.OfType<MyOtherClassA>().ToList();
        MyOtherClassesB = myOtherClasses.OfType<MyOtherClassB>().ToList();
    }

    public IList<MyOtherClassA> MyOtherClassesA { get; protected set; }
    public IList<MyOtherClassB> MyOtherClassesB { get; protected set; }
}
  • Am I pushing it too far?
  • Am I missing something?

EDIT

No, do inject them! But don't inject one list of a base type, which you then split by derived types.

Let's put ourselves in the context of Scrum and a Sprint.

In a Sprint, the Development Team may have Bugs, Impediments, Tasks and UserStories.

All of these have a Title and a Description, plus some other properties specific to each type. Let's make an abstract class called Artifact (not ScrumArtifact).

Artifact

public abstract class Artifact {
    public string Description { get; set; }
    public string Title { get; set; }
}

Bug

public class Bug : Artifact {
    public string Resolution { get; set; }
}

Impediment

public class Impediment : Artifact {
}

Task

public class Task : Artifact {
    public float EstimatedTime { get; set; }
    public float RealTime { get; set; }
}

UserStory

public class UserStory : Artifact {
    public string AcceptanceCriteria { get; set; }
    public int BusinessValue { get; set; }
    public int Complexity { get; set; }
    public IList<Impediment> Impediments { get; protected set; }
    public IList<Task> Tasks { get; protected set; }
}

Here, I have a UserStory which "depends" on two lists: Impediments and Tasks.

So I should have the constructor of UserStory taking two lists as follows.

public UserStory(IList<Impediment> impediments, IList<Task> tasks) {
    Impediments = impediments;
    Tasks = tasks;
}

And my unit test:

[TestFixture]
public class UserStoryTests {
    [Test]
    public void ImpedimentsShouldBeInitializedByDefault() {
        userStory.Impediments.Should().NotBeNull().And.BeOfType<IList<Impediment>>();
    }

    public void TasksShouldBeInitializedByDefault() {
        userStory.Tasks.Should().NotBeNull().And.BeOfType<IList<Task>>();
    }

    [TestFixtureSetUp]
    public void UserStorySetUp() {
        impediments = new Mock<IList<Impediment>>();
        tasks = new Mock<IList<Task>>();
        userStory = new UserStory(impediments.Object, tasks.Object);
    }

    private Mock<IList<Impediment>> impediments;
    private Mock<IList<Task>> tasks;
    private UserStory userStory;
}

The problem comes with the Sprint. The Sprint rather require four lists, and I find it too much of objects to inject for clarity and readability. It is said, if I'm not mistaken, that a class with too much dependencies might break the Single Responsibility Principle. Though I'm not breaking the SRP even with the Sprint class, I feel quite uncomfortable with injecting four different lists. I thought I could use polymorphism to inject one list which would contain them all, since after all they are all basically Artifacts.

Perhaps shall I simply consider using the AbstractFactory pattern so that my four lists get initialized properly as expected, and I would only have to inject one single factory class which single responsibility consist of creating lists?

Community
  • 1
  • 1
Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • I don't understand, what this has to do with DDD? Can you inject lists? Sure. Should you split lists up by concrete subtypes? Rather not. Think of cases where items are injected, which are of neither of your expected subtypes. Or a list, which doesn't contain any items of the subtypes you expect. – EagleBeak Jun 05 '14 at 08:05
  • Are you suggesting that I simply initialize the lists with the `new` keyword from within the constructor without any use of DI? If that is so, I feel okay about this. I just wish to learn what is the limit where DI shall not be considered, or else, doesn't offer any advantage. – Will Marcouiller Jun 05 '14 at 14:03
  • No, do inject them! But don't inject one list of a base type, which you then split by derived types. – EagleBeak Jun 05 '14 at 14:28
  • Please have an eye out my edit. – Will Marcouiller Jun 05 '14 at 15:41
  • Check out [this question](http://stackoverflow.com/questions/4603555/how-to-deal-with-constructor-over-injection-in-net) to understand what to do when your constructor gets too broad, i.e. suffers from 'over-injection'. – EagleBeak Jun 05 '14 at 15:51

1 Answers1

1

I think you misinterpreted the Ninject example a little bit. It doesn't involve different warrior classes, which are tied to a specific subtype of IWeapon. There's only a Samurai, who can use any type of IWeapon. So an Archer, who can only use a specific kind of weapon is not accounted for and wouldn't fit in well. Instead just inject a Bow into a Samurai.

Injecting lists is totally OK. Some DI containers even allow for autowiring lists. I.e. you can tell the container to inject all implementations of your interface found in a given assembly as a list.

But that only really works if you can treat all members in the same way, i.e. you don't have to differentiate by subtype. If you want to separate your warrior's melee weapons from his collection of bows, it's better to inject two different lists of two different types.

If you want to learn more about proper DI patterns, I can very much recommend Dependency Injection in .NET by Mark Seemann.

EagleBeak
  • 6,939
  • 8
  • 31
  • 47
  • +1 Thanks for enlighten me up. I took the example inspired from Ninject off the top of my head without verifying anything, only to setup my idea. =) – Will Marcouiller Jun 05 '14 at 15:47
  • I have been recommended this book more than once. I finally bought it a few weeks ago. Now, you convinced me to begin my reading. ;) Thanks for your time! – Will Marcouiller Jun 06 '14 at 00:44
  • I wonder anyway whether lists shall be injected, since they're part of the model itself, if you take for example my edit on Scrum. A Sprint is defined by its user stories, and a user story is in turn defined by its tasks, bugs, impediments and maybe other user stories along the way. That is the sole definition of the domain model. So how may the model benefit from lists injection? I hope Mark Seeman's book will answer such questions! =P – Will Marcouiller Jun 06 '14 at 01:51