7

I'm confused by this post by Mark Seeman.

And his comment on IInitializable below:

The problem with an Initialize method is the same as with Property Injection (A.K.A. Setter Injection): it creates a temporal coupling between the Initialize method and all other members of the class. Unless you truly can invoke any other member of the class without first invoking the Initialize method, such API design is deceitful and will lead to run-time exceptions. It also becomes much harder to ensure that the object is always in a consistent state.

The same time he writes:

This issue is similar to the issue of invoking virtual members from the constructor. Conceptually, an injected dependency is equivalent to a virtual member.

I thinks this statement is true only if admit that constructed != initialized.

What we get now:
Dependencies are injected in constructor but it is not recommended to use them.
Initialize phase brings complexity and should be avoided.

Isn't it contradictory?

Imagine class needs to set its state using the provided dependencies. Loading saved setting for example.
Init is bad, constructor is bad, so where to perform this operation?

And another point:
Are not methods like Connection.Open() just another name for Initialize?

Question:
So can anyone describe a good initialization pattern in the context of Dependency Injection that addresses the concerns Mark Seeman brings up?

2
  • 3
    I suspect that if I look at this question long enough, I might eventually figure out what you're actually asking. Alas, I don't have the time right now... Commented Jul 25, 2013 at 23:11
  • @RobertHarvey Ok, it's vague, I agree. What is the good object initialization pattern if any exists? From Mark's article it follows that dedicated init phase is something to be avoided but I see no other ways to initialize object. Commented Jul 26, 2013 at 8:15

4 Answers 4

4

dedicated Initialise method is bad - if you use this you must construct an object and then not use it at all until you've successfully called Init, and always destroy it if the Init call fails. Its a mess of initialisation that is much better handled in the constructor.

If you only return a successfully constructed object that contains everything it needs to start working, then you have a much easier time as a programmer using that class.

Similarly, there shouldn't be a problem if the injected dependancy is resolved during construction.

However that means setting the DI object during construction - 'constructor injection', and I assume he's talking about 'property injection' where the config is passed in as a set of property calls after the object is constructed. This is the same problem where you had an Init method, but you now have a SetConfigX method. Names are different, obviously, but the principle is the same - you end up with a half-constructed object that you then fill out with the rest of its state before it can be used.

3

I thinks this statement is true only if admit that constructed != initialized.

You are missing the point it seems. Calling virtual methods from the constructor implicitly means that the object is not yet fully constructed (and initialized). The concepts are the same. You can't call virtual methods until all of the constructors have run (the object is fully initialized). Likewise, you can't call methods that use injected dependencies until they're populated (the object is fully initialized).

Dependecnies are injected in constructor but it is not recommended to use them.

That's not what the article is saying at all. It's saying that the constructor should be limited to accepting dependencies, not looking them up or configuring them, or really anything else. It also says that constructor injection is insufficient for some needs (circular dependencies), and awkward in others (where the constructor definition forces big inheritence hierarchies).

I don't want to put words into the article writer's mouth, but I would recommend using constructor injection until you find a good reason not to. It's the easiest to implement. It's the easiest to debug. It's the easiest to read.

So can anyone describe a good initialization pattern in the context of Dependency Injection that addresses the concerns Mark Seeman brings up?

Personally, I like factories that spin up an object (or set of objects) with all of their dependencies populated. This limits the places where care needs to be taken to the constructors of your components and the factories themselves. If the dependencies aren't found, you get an error immediately. If you get the object(s) back, you know they're in a good state.

It's not something that can be applied (well) to all problems, but in my experience, can be applied to most problems well and isolates a bit of complexity.

7
  • As I understood author's point is that constructor should only accept dependencies but not use them inside constructor. This is most confusing because initialization as a process can require calls to dependencies. Commented Jul 26, 2013 at 13:09
  • @voroninp - ech, no. Initialization cannot require calls to dependencies.
    – Telastyn
    Commented Jul 26, 2013 at 13:38
  • Could you provide more arguments why it cannot/musn't ? Commented Jul 26, 2013 at 14:36
  • @voroninp - for largely the reasons you're running into. You can't guarantee that arbitrary dependencies will be in a proper state to be used if they're not fully initialized. Even if you do "initialize on first use" your code will blow up if there are any loops in your dependency graph.
    – Telastyn
    Commented Jul 26, 2013 at 14:44
  • Calling virtual methods from the constructor (aka before all constructors are run) is generally fine in C++, unless you try to do something completely brain-dead. Commented Dec 13, 2014 at 22:19
0

Dependencies are injected in constructor but it is not recommended to use them.

I think the author is saying the opposite of that with a focus on loose coupling. He's quoted as saying:

"The Constructor Injection design pattern is a extremely useful way to implement loose coupling"

Loose coupling is the core of good software design. It makes classes reusable, extendable and testable.

Initialize phase brings complexity and should be avoided.

Yes it does, but that doesn't mean it can always be avoided. Constructors do not have a return value, and not all languages support throwing of exceptions. Some books argue that a constructor should always be successful, and I agree with this rule.

Here is some source code examples of both styles. Both approaches work, but which one is better?

try
{
    FileReader f = new FileReader("something.txt");
    String str = f.read();
}
catch(FileNotFound e) {...}

or

FileReader f = new FileReader("something.txt");
if(f.exists())
{
    String str = f.read();
}

The first example has the FileReader object dependant upon an external resource. If it can not access it, then it fails during the constructor. This creates dependency beyond the controller of the programmer, and also unit testing.

In the second example there is no dependency. The object is allowed to be created even if the resource doesn't exist. The dependency is now up to the programmer to enforce.

So how does this relate to initializing an object. It's very simple. Who should be responsible? The object or the programmer. That's up to the author of the object. He/she might have good reasons to give up control of constructing the object to the programmer using it.

If initializing an object is a complex task, then you localize that code into a factory class so you have one place to go to make changes.

Are not methods like Connection.Open() just another name for Initialize?

The method Connection.Open() is an initializer only if Connection.Read() fails if Open() was not called.

Here is the problem the author is talking about.

Connection con = new Connection();
con->Read(); // this will fail, Open() was not called

To fix the above code. You have to write this, and this is a bad design.

Connection con = new Connection();
con->Open("192.168.1.1");  // bug fix, forgot to call Open()
con->Read();

I've read many comments in source code by programmers who write "bug fix, forgot to call X(...)". The argument is that the bug was avoidable in the first place. Had the author of the Connection class not used an initializer.

Here is the solution to the problem.

Connection con = new Connection("192.168.1.1");
con->Read();

Now, how you handle a failed connection is answered higher up in my answer. Either the constructor throws an exception, or the programmer has to call isOpen() before read().

So can anyone describe a good initialization pattern in the context of Dependency Injection that addresses the concerns Mark Seeman brings up?

It might be hard to understand, but the answer is in the Single Responsibility Principle.

For my example with the Connection object. It broke the SRP rule. The Connection object opens and reads from the resource. That's two different responsibilities. We can fix this by fracturing the object into multiple pieces each with their own responsibilities.

Here is an example;

try
{
    SocketAddress addr = new SocketAddress("192.168.1.1");
    try
    {
        Socket s = new Socket(addr);
        try
        {
            SocketReader r = new SocketReader(s);
            if(r != null)
            {
                String str = r->Read();
            }
        } catch(ReadFailure e) {..}
    } catch(ConnectionFailure e) {..}
} catch(BadAddress e) {..}

Each object is responsible only for one thing.

  • SocketAddress will only construct successfully if the address is valid.
  • Socket will only construct if it can make a connection to the address.
  • SocketReader only work if it can read.

As you can see. You have to write a lot more source code, and this is why we often see dependency injection avoided. It's extra work on the part of the programmer.

0

For flexibility, DO NOT do initialisation in constructors.

For simplicity, i.e. if you can afford it and are sure it will not cause you headaches later, DO initialisation in constructors (RAII). Then you can make the usual safe RAII assumptions about (monolithic?) deallocations.

All programming relies on correct ordering of events. There is nothing "deceitful" about placing on the programmer expectations to perform certain operations before certain other operations (in this case, constructing -> initialising all members -> using the object). Seeman's idea of "deceit" is patently absurd.

I tend to favour felxibility (the former) these days as I've been burnt too many times by winding up needing the flexiblity that individual injection / initialisations of members brings. (by the by, I favour C over C++ for the same reason: flexibility.). Constructor injection is RAII. RAII admits (in its very name) to being a conflation of concerns. As a result, objects cannot go into a pool to be reconfigured / reused, they instead need to be reconstructed which means extra runtime allocations. There is a lack of any real control over instruction ordering (dynamic DI concern). And of course there are the long, ugly parameter lists.

Your Answer

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

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