Discussions

News: Dependency injection and open vs. closed designs

  1. Rickard Oberg walks us through the difference between a sample design without Dependency Injection, and with. He uses the example to explain how DI allows for your designs to be more "open", flexible, and ready for change. And we all know that change will happen.

    Conclusion
    The conclusion of this is that all the components that you write should use the "open" design principles, whereas the composer would typically be done using the "closed" design principles. Yet, even this last part is not strictly necessary. You could make the composer scriptable, configurable, and even allow for it to work together with other composers which handle parts of the system. In essence, you could let your entire system be designed like a village: each house is internally "open", yet created by a composer with a varying degree of "closedness", for rigidity, and then let each such house (or subsystem) interact. This would most likely yield the best results not only at the point of construction, but also in terms of how well it can adapt to change in the future.

    If you decide to follow these principles when designing systems, there are a number of new questions that arise. Should I make the houses large or small? Should I let them interact a lot or not at all? How many should I create? I believe this is where software engineering becomes a craft, and there really is a need for good software architects, who can "see" on a case by case basis the answers to these questions. But that's a different topic.
    Read Rickard in Dependency injection and open vs. closed designs

    Threaded Messages (28)

  2. Please.[ Go to top ]

    I'm sorry, but that article is just laugable. Anyone taking it seriously should have their head examined. His example is so hypothetical and abstract as to give absolutely no information.

    The first clue is when he adds getBar() to the class and says "This method really has nothing to do with the function of Foo, per se". That's called bad design.

    He then calls adding a Bar to the constructor of Foo "dependency injection", but really, it's just properly designing the class (assuming it makes sense).

    He has this assumption that Foo should not own a Bar and should not create an instance of it. This cannot be true across the board. What are the requirements of Foo? If Foo meets those requirements the way it was implemented, what ist he big problem?

    What the author is leading us to conclude is that we should heavily parameterize every class, such that the sacred rule of never hardcoding anything can not be violated. It's just preposterous to say that across that board, and his example is just absurd, given that we have no requirements of what any of those classes are supposed to do.

    Now, I'm not saying the opposite, either. Allowing flexibility in your classes is a good thing, and many tenents of OO design are there to make it easy to do. However, making blanket statements and providing silly meaningless examples should not be accepted as rational thought or serious discourse.

    Yet another example of why TSS is so mediocre and amateurish. Crap like this blog entry should not be linked to. If you like what the guy is saying, having him write a real article.
  3. Please.[ Go to top ]

    What are the requirements of Foo? If Foo meets those requirements the way it was implemented, what ist he big problem?
    The entry is not about what we know. It's about what we don't know, i.e. the future. It's about the assumptions we have now, and how they can have an impact on what we have to do in the future.
    What the author is leading us to conclude is that we should heavily parameterize every class, such that the sacred rule of never hardcoding anything can not be violated.
    Sorry, never said that. The point is that even seemingly simplistic code often makes unnecessary assumptions. Those assumptions may be true now, but they may not be true tomorrow. The suggestion, then, is to put all those assumptions in one place, as it makes them easier to manage.

    Of course, these are only principles, and as such there is no "right" or "wrong", only cause and effect. What is "right" depends on whether you like the effects or not. For example, some people like their code to be rigid, for various reasons.
    It's just preposterous to say that across that board, and his example is just absurd, given that we have no requirements of what any of those classes are supposed to do.
    I never said that you should do it "across the board". In fact, I even suggested that using it too much may cause the system to be so flexible that it caves in under its own flexibility. Decisions has to be made somewhere, and the blog entry merely suggests that those decisions are made in one place, for the purpose of making the code more "future-compliant". It is also about simply being aware of that you *are* making assumptions in the first place. Not many reflect on the fact that by writing the first version of Foo implicitly means that you are not open to change in Bar.

    What the blog entry does it to describe two different design principles: open and closed. I tried to explain some of the consequences of using each principles. I'm surprised that it evoked such strong emotions.
  4. Please.[ Go to top ]

    I like the blog entry. Some of the thinking reminds me of the old Shlaer-Mellor methodology in the early '90s. They would call the open design "polluting your domain" and invented all kinds of patterns to avoid this. The CASE tools would actually check the dependency graph and generate error messages if you introduced incorrect dependencies. Unfortunately this approach was very complicated and was probably responsible for the term "analysis paralysis". I think there were some cool ideas though. Since Booch and Rational won the methodology war it has gone away but here is a bit of info: http://www.c2.com/cgi/wiki?ShlaerMellorMethod
  5. Please.[ Go to top ]

    I'm surprised that it evoked such strong emotions.
    Don't worry, Rickard : artists and genius are often misunderstood.
    I'd just like to thank you because it's the first time I find a simple, clear and understandable explanation of IoC. This way of doing things and its advantages are really difficult to grasp at first sight (to me it has been much more difficult than AOP). Perhaps you should also invite your readers to switch to Pico container or Spring documentation, so they can better appreciate what can be done based on this simple principle. This article on TSS is also another good explanation (especially the chapter about "Inversion of control container").
  6. Please.[ Go to top ]

    Sorry, I've forgotten the link : http://www.theserverside.com/articles/article.tss?l=SpringFramework
  7. Please Yourself[ Go to top ]

    Rickard wrote a decent article that casually (but well) describes issues to consider when coding up the components of your system.

    To me, the article reads as "keep these things in mind" - not as "your stupid if you don't do these things everywhere".

    He also includes some verbage to remind you to not go overboard.

    Your comments in response to this article seem to be laughable.
  8. Please Yourself -[ Go to top ]

    Well, what I'm really saying is that what the blog entry was trying to communicate (as clarified by the author's post here) IS good, but the way in which he wrote it is just dangerous and bad. He should inject some dependancy into his post.

    I think to really illustrate that point, show us some REAL classes, with some REAL requirements, and then show how the design decision affect implementation and maintenance. It wouldn't have been too hard.

    And, let's not forget: YAGNI. I see countless articles, patterns and techniques all geared towards planning for the millions of things that could possibly happen in the future, and having worked with people who employ those approaches, I believe it to be a very dangeous thing for the community to adopt.

    Most of us have to deliver working code on time and time and time again, I see people wanking off with new technique X or pattern Y resulting in a system that is no more maintainable, but took twice as long to create.
  9. YAGNI ? - YDGNI !![ Go to top ]

    I don't think YAGNI applies here though...

    One of the key benefits that de-coupling dependancies like this brings (assuming you adopt best practice and inject the dependancies back in using interfaces) is that you can inject mock depedancies.

    This allows you to test effectively without having to build shed loads of infastructure code to support the tests.

    So, you ALREADY have 2 different implementations for your injected dependancies, your production implementation class and your mock object... (albeit you may code your mocks using dynamic proxies a'la easymock)

    More a case of YDGNI (You DEFINATELY gonna need it...)
  10. Dave C,
    Please don't take this as a flame. You make some decent points, but some of your comments

    here:

    "...He then calls adding a Bar to the constructor of Foo "dependency injection", but really,

    it's just properly designing the class (assuming it makes sense)."

    And in previous threads:

    " When I read about IOC, I was like 'isn't everyone already doing this? Isn't this just

    called Good Class Design?'"

    make me question whether you really get Dependecy Injection/Inversion of Control. Or,

    perhaps I don't fully get classic, good OO design. To me, the big shift (which I don't see you noting) is that classes are handed (injected with) what would normally be "private"/self-managed objects according to classical design - that's the whole inversion thing. In fact, it kinda felt contrary to Good Class Design when I first started using it. But, the benefits (testability being the chief among them, for me) seemed to outweight the cost (kinda breaks encapsulation by having clients of some sort pass in this "private" stuff).

    So again, not flame bait. Just wondering if you shouldn't (re?)read something like Martin Fowler's article on Dependency Injection.

    Mike
  11. Deja Vu[ Go to top ]

    Dave C,

    It seems you're unable to disagree with people without insulting them by calling what they write "crap" and ramming words into their mouth, which demonstrates your ignorance and narrow-mindedness. Your manner of treating Rickard is the same way you treated me: it's downright obnoxious, offensive, and mean. The technical merits of what people write are up for debate; at least they're contributing food for thought and something to ponder on. But your only contribution here is an intolerable condescending attitude (ironically coming from a "nobody") and setting a negative tone for the thread. If you don't like what TSS publishes, the door is wide open. And trust me, you won't be missed.
  12. Please.[ Go to top ]

    Rickard you have done great jobs. At least you share your contribution and experience to communities. As for Dave, stop criticising and start contribute. If you not satisfied with the articles, just give your comments and examples rather than criticising. Keep up the good job Rickard.
  13. In reply to the previous post:

    I'm pretty sure that Rickard would not advocate heavily parameterising EVERY class to use you language, as much as I presume you were not advocating that everything should be hardcoded.

    On balance however, dependancy injection provides the massive benefit that its possible to change the implementations of the dependants used. Which makes code significantly easier to test with mock objects and reuse in different scenarios. That alone is worth the effort involved making classes more configurable.

    Secondly, parameterisation of this sort allows classes to adhere more closely to the 'do one thing well' principle; which makes implementations easier to understand and maintain.

    My preference is usually to parameterise classes 'heavily'. Unless there is a compelling reason not to, the benefits of doing so are too great to ignore, and the extra work required to perform the wiring up is easily handled in containers like Pico and Spring.
  14. Why is this news ?[ Go to top ]

    Long before this was renamed this dependency Injection , long before this was named IoC , we called this common sense. Anyways, I am glad to know it is back in fashion.
  15. Re: Why is this news ?[ Go to top ]

    Well, what we do is we take what to many people is common sense or experience and we write it down and give it a name and make it a "design pattern". We include clues about what situations call for usage of the pattern, in hopes people don't apply it recklessly since it has a fancy name with a nice ring to it.

    What I don't understand is how these things seem to take on lives of their own. While perhaps a small fraction of the community, there seems to be an endless stream of people who want to make blanket or even quasi-religious statements about applicability of the pattern. There are lots of fad-like qualities involved.

    But whether you should apply the "Dependency Injection" pattern is really a no-brainer most of the time. If some other code would be better at creating/configuring a service your class depends on, then injecting a dependency is a good idea, if not the only idea. If it happens that your class needs it right from the start and it can't be changed later, then the constructor is an obvious choice. If it can be changed later, maybe a property would be needed instead or in addition.

    There are plenty of cases where you don't want to do this, of course. If your class is the authority, having others inject the dependency would be confusing and if the wrong thing is injected the code might not function. Dependency injection doesn't necessarily make the code easier to change; if you change the code later to have an additional dependency then all the clients have to be changed only if you are injecting that dependency.

    So what I really don't get is how this has anything at all to do with an "open" or a "closed" mode or mindset, unless it is an attempt to associate words with each other. In any quasi-religious discussion of computing Open supposedly is Good, and Closed is supposedly Bad with little consideration of the circumstances. So is the point of the article then that "dependency injection"=Open=Good and "dependency creation" or "dependency lookup" are Closed=Bad? Either way this thought really doesn't contribute anything and this post and resulting thread wasn't worth putting on TSS, unless it's just a friendly reminder that Pico container is still out there.
  16. Re: Why is this news ?[ Go to top ]

    In any quasi-religious discussion of computing Open supposedly is Good, and Closed is supposedly Bad with little consideration of the circumstances. So is the point of the article then that "dependency injection"=Open=Good and "dependency creation" or "dependency lookup" are Closed=Bad?
    If you read the article you will find, if you look closely, that not only does it say that "open" is Good and that "closed" is Good, it also states that "open" is Bad and that "closed" is Bad. Furthermore, it also suggests, right at the end:
    I believe this is where software engineering becomes a craft, and there really is a need for good software architects, who can "see" on a case by case basis the answers to these questions.
    In other words, not only is there consideration of the circumstances, the conclusion is that circumstances are what really matters! The principles described are only an attempt at objectively describing cause and effect of two types of code. When and how to apply those principles, in order to maximize some subjective "goodness", is entirely based on the circumstances.

    Considering this, it seems like we're not having a "quasi-religious discussion" after all, as you implied.
  17. Re: Why is this news ?[ Go to top ]

    Sorry Rickard, I didn't mean that you were the religious one. But I will try to argue that you are making some rather blanket statements in you article.

    Should I use "open" or "closed" in my Foo component?
    The conclusion of this is that all the components that you write should use the "open" design principles...
    And what does "open" mean to Rickard's article?
    In short, there are no implicit assumptions about Bar, which means that Foo will never be changed due to a change in Bar. This is what I'd call an "open" design, since it is open to the possibilities of change.
    Here's where I get lost. The first part, on the face of it, is false. A change in Bar's public interface may change Foo. There are also negative consequences to the cost of change when a dependency is injected, making it less open to change: If, after injecting the dependency, I decide that my Foo needs a Baz instead of a Bar in its implementation (and the public interface differs), then all the clients would have to change, whereas they wouldn't if it was not injected. So that means Foo has a high cost of change and is "closed" right? Anyway, I guess the "open" vs. "closed" thing is lost on me.

    Or if you mean that the components will be designed with some dependency holes, the composer fills them, having dependencies is defined as open, and filling them is defined as closed, then I don't see what's not obvious here. Tautologies are the best blanket statements.

    I think we'd do better to fully explain the implications of injecting something or not, and thereby how to tell when to do which. I think there is craft at this "how-many-doors" level too, not just at the "how-big-of-a-house" level.
  18. Re: Why is this news ?[ Go to top ]

    Sorry Rickard, I didn't mean that you were the religious one. But I will try to argue that you are making some rather blanket statements in you article.Should I use "open" or "closed" in my Foo component?
    It depends on the circumstances, in particular whether Foo is a composer or not. If it is a composer you might want it to be closed, which means that it encapsulates the configuration needed by the current requirements. If it is not a composer then you would want it to be "open", in the sense that it does not try to assume too much about stuff that it depends on work, as outlined in the blog entry.
    Here's where I get lost. The first part, on the face of it, is false. A change in Bar's public interface may change Foo.
    You are lost because you are reading rather selectively. "Changes" in the context of the blog entry refer to how components are instantiated, configured, and managed.
    There are also negative consequences to the cost of change when a dependency is injected, making it less open to change: If, after injecting the dependency, I decide that my Foo needs a Baz instead of a Bar in its implementation (and the public interface differs), then all the clients would have to change, whereas they wouldn't if it was not injected. So that means Foo has a high cost of change and is "closed" right?
    Nope, because that work is precisely what a generalized PicoContainer would handle for you. In other words, by delegating such tasks to Pico you are minimizing the impact of change in terms of "code you have to change" when Foo is changed.
    Anyway, I guess the "open" vs. "closed" thing is lost on me.Or if you mean that the components will be designed with some dependency holes, the composer fills them, having dependencies is defined as open, and filling them is defined as closed, then I don't see what's not obvious here. Tautologies are the best blanket statements.I think we'd do better to fully explain the implications of injecting something or not, and thereby how to tell when to do which.
    "open"/"closed" refers to the possibilities of change in Bar. If Foo is "open" it means that it does not make any assumptions about how Bar will evolve. If Foo is "closed", on the other hand, it assumes one or more things and have hence "closed" off some possibilities for change in Bar, as any such change would lead to a change in Foo. If you don't like the words "open" and "closed" I suppose you could use the terms "unlimited" and "limited" instead. The "open" version of Foo is "unlimited" with regard to what you can do with Bar, whereas the "closed" version of Foo "limits" what you can do with Bar. Does that work better for you?
  19. Re: Why is this news ?[ Go to top ]

    DI is an example of "Object Composition" in Gang-of-Four terminology. This technique is an element of many patterns, notably the Property getter and setter pattern in Java Beans. And IOC is the core principle that makes a Framework a Framework. There is certainly a value to restating these principles, because "good design" is not instinctual, it is learned, and that is why programmers get the "a ha!" experience when they first encounter these ideas.

    Paul Copeland, JOT Object Technologies
    http://www.jotobjects.com/
  20. Re: Why is this news ?[ Go to top ]

    The "open" version of Foo is "unlimited" with regard to what you can do with Bar, whereas the "closed" version of Foo "limits" what you can do with Bar. Does that work better for you?
    Certainly you can do more with Bar if you pass it in. But the tradeoff you face for it is that you are limited as to what you can do with Foo without changing (or anticipating the automagical results of) someone else. Others have to change what they are doing to account for a change in Foo's use of Bar, and do so correctly.

    If you need flexibility of Foo with respect to Bar of course you'll inject Bar somehow; that's not news. But if you don't think you need flexibility in Bar but think you might in Foo, what do you do? That decision takes craft, and sometimes the answer is even determined by whether you want to leave a tripwire behind or not.
  21. Re: Why is this news ?[ Go to top ]

    Long before this was renamed this dependency Injection , long before this was named IoC , we called this common sense. Anyways, I am glad to know it is back in fashion.
    Again, same reply I gave to Dave C. I do see DI & IoC as fundamental shifts in thinking. Not the whole loose coupling, that's been a goal forever. The shift is in what is beign loosely coupled - the fact that it's being extended to "private/implementation-ish" objects which classes merely need to "get their job done", and which aren't part of the traditional public/service API the classes exists for. An example is a "Service Locator" type object being injected into a class. Classic design, to my mind, would say that this is solely the concern of the implementation. Dependency Injection/IOC inverts that principle and makes it the concern of "someonething else", like the IoC container or a client (though the latter may be bad. I accepted the compromise for testability).

    Or, am I wrong in thinking thinking this is a big shift? I'm somewhat new on the block with only 5 years experience...
  22. Re: Why is this news ?[ Go to top ]

    Claiming that the Dependency Injection pattern refers to what kind of stuff gets injected is sort of putting the cart before the horse. Injecting stuff that would otherwise be private for testing purposes sounds like a different idea that's covered by other patterns; maybe it's better described as a Strategy for implementing Mock Objects.

    There have certainly been people doing all of these things correctly for more than 5 years. There have also been people doing bad things, even in the name of good design, for as long. So the concept of the "classic design" is a bit spotty, and might just be whatever you need it to be for purposes of argument.
  23. Re: Why is this news ?[ Go to top ]

    Again, same reply I gave to Dave C. I do see DI & IoC as fundamental shifts in thinking. Not the whole loose coupling, that's been a goal forever. The shift is in what is beign loosely coupled - the fact that it's being extended to "private/implementation-ish" objects which classes merely need to "get their job done", and which aren't part of the traditional public/service API the classes exists for. An example is a "Service Locator" type object being injected into a class.
    I do not see it as a fundamental shift in thinking really. I see it as another framework for configuration. That is exactly what dependency injection is: Configuration. It has been longstanding practice that for basically everything that you would "inject" into your classes, classical component oriented programming would have some indirection mechanism that picks up this from configuration / naming service / whatever. Where classical design would not do that, dependency injection is bad design or at least overengineering.

    The interesting thing is that IoC now realizes that just injecting stuff is not enough. We need transactions/naming service/dynamic binding/AOP etc. all as part of configuration - or so some say - and still claim that it is easier to use than the classical way. Sure, cause they built it themselves.
    I wrong in thinking thinking this is a big shift? I'm somewhat new on the block with only 5 years experience...
    Yes
  24. My first impression of this article was positive. "Good stuff", I thought. I've thought some of the same thoughts, and confirmation like this is always nice.

    After reading a few of the negative responses, I quickly scanned the article again, and realised that it is actually so abstract that only people who already know or have experienced what the author is talking about will understand it.

    Anyway, I guess it's up to TSS to decide whether they want to post these "semi-religious" ;) articles or more down to earth ones? Go ahead and knock TSS on the choice of authors, but it would be nice if everybody would try to be more constructive about the critique of the authors writing.
  25. I often have to deal with code which uses lots of singletons and nearly no interfaces. Looks like many programmers discovered this pattern and started to use it everywhere... It is a pain to unit-test it, it is a pain to write mock objects. I usually follow some common sense guidelines: always try to pass an interface, always try to return an interface, do not write methods with more than three or four parameters (use a value object instead). Of course, these are some basic Fowler's laws.
    Yes, maybe IoC it is only common sense, but in my career I have found a lot of code written without even this minimum level of common sense, so I don't understand all these hard criticism against this article: it's only a blog, after all, and it exposes some good, even if simple, ideas. Still too many programmers love to show their muscles writing complex code for the sake of it. But I am going out of scope now...
  26. I often have to deal with code which uses lots of singletons and nearly no interfaces.
    Now there is no reason not to use a singleton with interfaces :-). On top of that you touch an interesting spot, because a lot of the time "IoC" and "open design" are about externalizing the singleton. However no matter where the singleton gets defined, it still remains a singleton - that said, it could be done otherwise, but how many independent connection pools, logger implementations, calendar factories etc. would you want to have in your system - now really :-).
  27. I think that a singleton is a way to use a class. I mean that, IMHO, a class should not know to be a singleton, but client code should manage the class as a singleton instance. So I prefer to pass singletons as regular parameters to constructor instead of wiring them inside the client code. Containers like Spring and Pico help a lot, because they put "singletonality" in configuration files. Of course, as you write, there are exceptions: for example it could not be a good idea to pass the singleton logger instance as a parameter. It's plain common sense.

    Kind regards.
  28. Open AND Closed Design[ Go to top ]

    Maybe this feature should have been entitled "open AND closed design" since it is more about a design dynamic than a best practice. Rickard's blog reminded me of how a deceptively simple design decision can have far-reaching consequences. "Closed" elements are not bad, but "Open" ones are, in a way, more interesting. They have a cascading effect that creates many more possibilities than one might expect from so small an adjustment. I think it's the elegance of this little shift in perspective that captured Rickard's attention, and his blog invites us to consider where it may lead. (It must be disappointing to him that so few readers responded in that spirit.)
  29. Open AND Closed Design[ Go to top ]

    Maybe this feature should have been entitled "open AND closed design" since it is more about a design dynamic than a best practice. Rickard's blog reminded me of how a deceptively simple design decision can have far-reaching consequences.
    Agree. I think the example was purposefully simple to illustrate this point. If it's too abstract as some posters have indicated, the concept should be straightforward to find examples either from your own experience or from opensource projects. Here's one example from commons-httpclient. (It appears that they've made configuration of HttpClient more "open" in the most recent revision.)
    I think it's the elegance of this little shift in perspective that captured Rickard's attention, and his blog invites us to consider where it may lead. (It must be disappointing to him that so few readers responded in that spirit.)
    I'd suggest that if you're a avid student of software design principles who's open to new ideas and you didn't have a little "aha" moment while reading this article that you revisit it at some point in the future.