Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I've been contemplating how to balance testable design using dependency injection with providing simple fixed public API. My dilemma is: people would want to do something like var server = new Server(){ ... } and not have to worry about creating the many dependencies and graph of dependencies that a Server(,,,,,,) may have. While developing, I don't worry too much, as I use an IoC/DI framework to handle all that (I'm not using the lifecycle management aspects of any container, which would complicate things further).

Now, the dependencies are unlikely to be re-implemented. Componentisation in this case is almost purely for testability (and decent design!) rather than creating seams for extension, etc. People will 99.999% of the time wish to use a default configuration. So. I could hardcode the dependencies. Don't want to do that, we lose our testing! I could provide a default constructor with hard-coded dependencies and one which takes dependencies. That's... messy, and likely to be confusing, but viable. I could make the dependency receiving constructor internal and make my unit tests a friend assembly (assuming C#), which tidies the public API but leaves a nasty hidden trap lurking for maintenance. Having two constructors which are implicitly connected rather than explicitly would be bad design in general in my book.

At the moment that's about the least evil I can think of. Opinions? Wisdom?

share|improve this question

3 Answers 3

up vote 3 down vote accepted

Dependency injection is a powerful pattern when used well, but all too often its practitioners become dependent on some external framework. The resulting API is quite painful for those of us who don't want to loosely tie our app together with XML duct tape. Don't forget about Plain Old Objects (POO).

First consider how you would expect someone to use your API--without the framework involved.

  • How do you instantiate the Server?
  • How do you extend the Server?
  • What do you want to expose in the external API?
  • What do you want to hide in the external API?

I like the idea of providing default implementations for your components, and the fact that you have those components. The following approach is a perfectly valid, and decent OO practice:

public Server() 
    : this(new HttpListener(80), new HttpResponder())
{}

public Server(Listener listener, Responder responder)
{
    // ...
}

As long as you document what the default implementations for the components are in the API docs, and provide one constructor that performs all the setup, you should be fine. The cascading constructors are not fragile as long as the set up code happens in one master constructor.

Essentially, all the publicly facing constructors would have the different combinations of components you want to expose. Internally, they would populate the defaults and defer to a private constructor that completes the setup. In essence, this provides you some DRY and is pretty easy to test.

If you need to provide friend access to your tests to set up the Server object to isolate it for testing, go for it. It won't be part of the public API, which is what you want to be careful with.

Just be kind to your API consumers and don't require a IoC/DI framework to use your library. To get a feel for the pain you are inflicting make sure your unit tests don't rely on the IoC/DI framework either. (It's a personal pet peeve, but as soon as you introduce the framework it's no longer unit testing--it becomes integration testing).

share|improve this answer
    
I agree, and I'm certainly no fan of IoC config soup - XML configuration is not something I use at all where IoC is concerned. Certainly requiring IoC usage is exactly what I was avoiding - it's the kind of assumption a public API designer can never make. Thanks for the comment, it's along the lines that I was thinking and it's reassuring to have a sanity check now and again! –  kolektiv Jan 5 '11 at 10:37
    
-1 This answer basically says "don't use dependency injection" and contains inaccurate assumptions. In your example if the HttpListener constructor changes then the Server class must also change. They're coupled. A better solution is what @Winston Ewert says below, which is to provide a default class with dependencies pre-specified, outside of the library's API. Then the programmer is not forced to set up all the dependencies since you make the decision for him, but he still has the flexibility to change them later on. This is a big deal when you have third-party dependencies. –  M. Dudley Mar 22 '13 at 15:27
    
FWIW the provided example is called "bastard injection". stackoverflow.com/q/2045904/111327 stackoverflow.com/q/6733667/111327 –  M. Dudley Mar 22 '13 at 15:33
    
@MichaelDudley, did you read the OP's question. All "assumptions" were based on the OP's provided information. For a time, the "bastard injection" as you called it, was the favored dependency injection format--particularly for systems whose compositions don't change during runtime. Setters and getters are also another form of dependency injection. I simply used examples based on what the OP provided. –  Berin Loritsch Mar 22 '13 at 15:38

How about providing a subclass which provides the "public api"

class StandardServer : Server
{
    public StandardServer():
        this( depends1, depends2, depends3)
    {
    }
}

The user cannew StandardServer()and be on their way. They can also use the Server base class if they want more control over how the server functions. This is more or less the approach I use. (I don't use a framework as I haven't yet seen the point.)

This still exposes the internal api, but I think you should. You've split up your objects into different useful components which should work independently. There is no telling when a third party might want to use one of the components in isolation.

share|improve this answer

I could make the dependency receiving constructor internal and make my unit tests a friend assembly (assuming C#), which tidies the public API but leaves a nasty hidden trap lurking for maintenance.

That doesn't seem like a "nasty hidden trap" to me. The public constructor should just be calling the internal one with the "default" dependencies. As long as it's clear that the public constructor shouldn't be modified, everything should be fine.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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