Steve Freeman Rotating Header Image

Is Dependency Injection like Facebook?

The problem with social networks

I think there’s a description in Paul Adams’ talk about online vs. offline social networks of how Dependency Injection goes bad, particularly when using one of the many automated frameworks.

Adams describes a research subject Debbie who, in “real life” has friends and contacts from very different walks of life. She has friends from college with alternative lifestyles who post images from their favourite LA gay bars. She also trains local 10-year olds in competitive swimming. Both the college friends and swimming kids have “friended” her. She was horrified to discover that these two worlds had inadvertently become linked though her social networking account.

This is the “Facebook problem”. The assumption that all relationships are equivalent was good enough for college dorms but doesn’t really scale to the rest of the world, hence Google+. As Adams points out,

Facebook itself is not the problem here. The problem here is that these are different parts of Debbie’s life that would never have been exposed to each other offline were linked online.

Like most users, Debbie wasn’t thinking of the bigger picture when she bound the whole of her life together. She was just connecting to people she knew and commenting on some pictures of guys with cute buns.

Simile alert!

Let’s revisit the right-hand side of that illustration.

This is Nat‘s diagram for the Ports and Adapters pattern. It illustrates how some people (including us) think system components should be built, with the domain logic in the centre protected from the accidental complexity of the outside world by a layer of adapters. I do not want to have my web code inadvertently linked directly to my persistence code (or even connected to LA gay bars).

That’s the trouble with the use of DI frameworks in systems that I’ve seen, there’s only one level of relationship: get me an object from the container. When I’m adding a feature, I just want to get hold of some component—and here’s an easy way to do it. It takes a lot of rigour to step back at every access to consider whether I’m introducing a subtle link between components that really shouldn’t know about each other.

I know that most of the frameworks support managing different contexts but it seems that, frankly, that’s more thinking and organisation than most teams have time for at the beginning of a project. As for cleaning up after the fact, well it’s a good way to make a living if the company can afford it and you like solving complex puzzles. More critical, however, is that the Ports and Adapters structure is recursive. Trying to manage the environments of multiple levels of subsystem with most current containers would be, in Keith Braithwaite‘s words, “impossible and/or insane”.

new again

The answer, I believe, is to save the DI frameworks for the real boundaries of the system, the parts which might change from installation to installation. Otherwise, I gather object assembly into specialised areas of the code where I can build up the run-time structure of the system with the deft use of constructors and new. It’ll look a bit complex but no worse than the equivalent DI structure (and everyone should learn to read code that looks like lisp).

If I later find that I can’t get access to some component that I think I need, that’s not necessarily a bad thing. It’s telling me that I’m introducing a new dependency and sometimes that’s a hint that a component is in the wrong place, or that I’m trying to use it from the wrong place. The coding bump is a design feedback mechanism that I miss when I can just pull objects out of a container. If I do a good job, I should find that, most of the time, I have just the right components at the time that I need them.

8 Comments

  1. Gregwar says:

    I got some remarks:

    1) What if you would completly change the functionning of a feature, factoring code involving for instance classes renaming ? If you want to set up a Factory instead of excepting users instantiate you class ? Do you seriously think that’s reasonable to except all users that use your library to follow every of your updates ?

    2) Your article title lets suppose that you are comparing DI with Facebook, but you are comparing DI CONTAINERS with Facebook

    3) DI helps to explicitly expose the dependences between objects, you can easily, with some code parsing or static analysis, understand what is depending from what, the container is just a popular and simple way of imagining DI but not a standard. Don’t forget you can have as much containers as you want, one for the 10-years and one for the gay bars for instance, objects in the containers will have their own live and interact with each other in their own context, the same way Debbie could create lists on her Facebook account and avoid any linking between the two parts of her life

  2. Jamie says:

    In the meaning of life, during sex education classes, the teacher asks about foreplay and a young fellow makes a remark, I’ll let your readers google it. The teacher replies, “what’s wrong with a kiss, boy”?

    I remember taking over a failing project that was using Java and Spring. I knew what a factory was and how to build objects, but I’d not seen Spring up until that point. One developer explained this all to me, I had no problem following, but wondered about a the levels of mis-direction. I did a Monty Python and said, “what’s wrong with new(), boy”? The developer couldn’t answer.

    I know the problems with new(), course I do, but you start with a kiss and move on from their, you don’t start with, well, a full on DI container.

  3. JH says:

    The problem is that you are assuming you have one interface to “rule them all” which is the essence of the Facebook problem you are describing.

    One class in an assembly, say, your domain, could have a dependency on a localization provider (providing strings for display). That class should drive out it’s requirements.

    e.g. A validation class in your domain may have a dependency on an interface that provides the string “Your selection is not valid”.

    To use constructor dependencies as an example:

    class Validator {
    IValidationLocalizationProvider provider;
    public Validator(IValidationLocalizationProvider provider) {

    }
    }

    interface IValidationLocalizationProvider {
    string InvalidSelection { get; }
    }

    The point is that a class (whatever is actually implementing your interface) can also implement other interfaces as well. So, if you have another class that has some localization dependencies, this concrete implementation can implement both.

    e.g.
    //This interface may be used elsewhere in the system
    interface IMyOtherLocalizationProvider {
    string LeastFavoritePet { get; }
    }

    class MyLocalizer : IValidationLocalizationProvider, IMyOtherLocalizationProvider {
    string InvalidSelection { get { return “Your selection is not valid.” } }
    string LeastFavoritePet { get { return “Cats.” } }
    }

    The point of this whole comment is that interfaces are cheap. Create them freely. They can be implemented in a concrete fashion anywhere you’d like (yay for IoC containers).

    You don’t need “one interface to rule them all (a la the “facebook” problem you describe). You can have multiple interfaces, many. It’s okay. Don’t have fear of having an interface with only one method in it. Your IoC container will be able to take care of it on your behalf… as long as you’ve actually implemented it concretely.

    Now, to complete the circle; Google+ allows you multiple “circles” to publish to. Allowing you to publish what you want to expose only to those in the circle you want to publish to. This is more the way you should be using your IoC container.

  4. @JH I know you can do that. I haven’t often seen it used properly in the wild. The common use of the frameworks (not DI itself) seems to encourage people towards having one “God” object that implicitly drags in everything with it.

  5. martraire says:

    “save the DI frameworks for the real boundaries of the system, the parts which might change from installation to installation. Otherwise, I gather object assembly into specialised areas of the code where I can build up the run-time structure of the system with the deft use of constructors and new.”

    That’s exactly the style that we used some time ago for a derivatives trading exchange, and I loved it. We called these specialised areas responsible for instantiation “bootstrap” classes, and there were only 2 or 3 of them for the whole system. The rest was DI via pure discipline (pass every dependency through constructors), without a container.

    We did need 2 or 3 factories to inject some classes at a later time and/or multiple times, but nothing complex. This rustic bootstrap code also had some conditionals (e.g. prod or staging), and could introduce some decorators for logging, time watching, error catching… You don’t need AOP when 5 decorators are enough.

    Later we considered using Guice to ease with more options of runtime configuration, driven by DB configuration, but we never really had to do the actual move. As @Jamie says: “you don’t start with, well, a full on DI container.”

  6. Brian Marick says:

    Obviously I’m way late to the party here, and I don’t have anything direct to say about the technical issue. However, the “Facebook problem”. I am reminded of Granovetter diagrams and their connection to capability security (based around the idea of A can’t do anything to B unless some third object C introduces them and gives A the capability to do that thing).

    http://www.cap-lore.com/Crypto/Granovetter.html
    http://www.erights.org/elib/capability/ode/index.html

  7. [...] year Steve Freeman published a blog article describing how the use of dependency injection could lead to coupling between objects that should have no knowledge…. The essential idea is that using dependency injection uniformly for all relationships between [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>