Talk:Dependency injection/Archives/2014/March

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia

Example code is verbose and does not explain anything

The section "A code illustration using Java" is waaay too long and only gets to the point in the very last sentence. However, a concrete example of DI is lacking. ThomasTenCate (talk) 04:23, 25 September 2008 (UTC)

I agree with that, but it's the most readable and understandable example and at least it's a little funny. I think we should leave it and modify the rest of the examples to be more "real-life-ish." —Preceding unsigned comment added by 74.238.168.219 (talk) 16:53, 14 January 2009 (UTC)

I'm proposing the code below to replace the present example code. I believe that, with adequate explanation it will work better to show what dependency injection is about. For more explanation, read it above. Ramiro Pereira de Magalhães (talk) 14:20, 16 February 2009 (UTC)

Notice: a new example has already been added. The one shown below is still there just to work as a context to the discussion. —Preceding unsigned comment added by Ramiromagalhaes (talkcontribs) 15:55, 11 July 2009 (UTC)
public interface ComponentInterface {

	public void doComponentStuff();

}

public class ComponentImplementation implements ComponentInterface {

	public void doComponentStuff() {
		Dependency dependency = new Dependency();
		dependency.doDependencyStuff();
	}

}

public class ComponentImplementationWithDependencyInjected implements ComponentInterface {

	private Dependency dependency;

	public void doComponentStuff() {
		getDependency().doDependencyStuff();
	}

	public void setDependency(Dependency d) {
		this.dependency = d;
	}

	private Dependency getDependency() {
		return dependency;
	}

}

public class ComponentFactory {

	public ComponentInterface createComponent() {
		ComponentImplementationWithDependencyInjected component =
			new ComponentImplementationWithDependencyInjected();
		component.setDependency( new Dependency() );
		return component;
	}

}
I still don't think this illustrates any sort of principle that hasn't already been clearly established (e.g. Abstraction/Polymorphism) In your example, the Dependency class could either be an interface or some base-class, but in either scenario this is simply "abstraction" and not some new principle all together. Why does passing in an interface or base class (which people have been doing for a long, long, long time) suddenly being renamed and re attributed? How is this any different from what Stroustrup covers in his FAQ here: http://www.research.att.com/~bs/bs_faq.html#oop ??? (and in particular, "The key point here is that f() doesn't need to know which kind of driver it uses; all it needs to know is that it is passed a Driver; that is, an interface to many different kinds of drivers.")
Maybe I'm missing something or I've misunderstood the example, but I am still really struggling to see how this is A) a genuinely new idea and not the same OO principles that have been espoused for decades, and B) something that should be attributed to Fowler. Jnoring (talk) 22:13, 16 February 2009 (UTC)
Those principles you mentioned are in fact important OO concepts. They are the building blocks to more sofisticated techniques or object arrangements like design patterns. Dependency Injection is nothing more than a name that we can use to refer to a specific arrangement that has a defined purpose, like any other design pattern. If I am not wrong, the GoF book says that a design pattern is not a "new idea", but is a solution commonly used to solve a certain problem. So, Fowler should only get the credits for creating the name "Dependency Injection" not to the pattern itself.
Now, about the technique, I think you're focusing too much on the strategy side of it, I mean, the capability this pattern gives you to change the implementation without changing the interface. In fact, this is vital to the pattern, but - in my opinion - what matters most is the removal of the instantiation of the dependency from the dependent class. Such actions become part of a third component that does its job as on the example above, or as in the Stroustrup article you mentioned, or by reading some configuration file. By doing this, the component can provide its services once it has its dependencies resolved by whatever means are available. Notice this component's client does not need to have access to the component's methods that are used to solve the dependencies (such as constructors or setters as in the example above) Ramiro Pereira de Magalhães (talk) 02:41, 21 February 2009 (UTC).
I don't agree. If the "capability" this pattern gives is it allows changing the implementation without changing the interface, then _it is nothing new_. Clearly this is the case, given Stroustrup's example: this is how you are _supposed_ to use an interface. And if fowler should only get the credits for creating the name "DI," but not the pattern itself....doesn't that imply he doesn't deserve any credit? I'm sorry but this whole article is ridiculous, and Fowler's paper consists of a strawman, followed up by pointing out the obvious. Jnoring (talk) 02:34, 26 February 2009 (UTC)
I think you did not read my post with attention, so I ask you to please read it, including the references I posted. I also recomend reading the book I mentioned so that a design pattern identification does not sound that weird to you.
But I agree that the article is not explaining DI very well. The problem is not just the example. I could explain to you what I think about it, but it would be easier to just fix the article. I'll try to do that when I have time.Ramiro Pereira de Magalhães (talk) 15:33, 1 March 2009 (UTC)
Well, at last I got time a little to change the article. It still needs a lot of improvements, though. An important step I must take is to find where did I get those informations from, so we can give it some good citations.Ramiro Pereira de Magalhães (talk) 05:28, 21 June 2009 (UTC)
As I see it, the main capability allowed by Dependency Injection is allowing to change (extend) the definition of an object without having to recompile everything using that object. This is a proper subset of all cases where an interface of the object is passed as a parameter (i.e. there are cases in which you pass an interface as a parameter, and you still have to recompile classes using the interface - those wouldn't use DI). Diego (talk) 14:56, 27 February 2009 (UTC)
Yeah, this sure is one important capability which is enabled by the fact that the class which is responsible to inject the dependencies is not the component itself, but a third party. This third party, this "injector" is the one who is responsible for that capability and it is where, I think, we should focus our attention in this article.Ramiro Pereira de Magalhães (talk) 15:33, 1 March 2009 (UTC)

Another problem I see with the example is the 'straw man' set up in explanation of the non-DI code - "As shown, the Car class needs to create an instance of an Engine ... such an approach still forces the Car class to know how to instantiate its own Engine." But this is not 'forced', and the implication that this is the only way to remove the simple-minded dependency is false. We should be comparing DI to other ways of avoiding this dependency, and the fact that the example implies there aren't any makes it weak. For instance, just what makes this better than a call to a factory that provides the engine? —Preceding unsigned comment added by 204.152.2.82 (talk) 13:52, 14 October 2009 (UTC)

Biggest problem I have with the current example is use of double for money. Use this code and Richard Pryor (or that stapler guy from office space) is going to show up in your parking space with a hot-rod he bought after embezzling all the half penny's you lost the company. If outdated movie references aren't enough proof for you, read this Galhalee (talk) 10:27, 13 March 2014 (UTC)

Don't double your money

Biggest problem I have with the current example is the use of double for money. Use this code and Richard Pryor (or that stapler guy from Office Space) is going to show up in your parking space with a hot-rod he bought after embezzling all the half penny's you lost the company. If outdated movie references aren't enough proof for you, read this. Seriously, don't teach people to do that. IEEE floating point numbers are for scientists, not accountants. Galhalee (talk) 10:27, 13 March 2014 (UTC)

DI vs Strategy Pattern

Can someone explain how DI is different then strategy pattern? — Preceding unsigned comment added by 198.208.251.23 (talk) 15:57, 26 September 2013 (UTC)

Rather than as some help desk conversation, please think of the answer to this question as a proposed section to the article and comment appropriately. The main point is the need to correct the current Motivation section. Galhalee (talk) 20:03, 15 March 2014 (UTC)


Using DI or the Strategy Pattern could actually end up with exactly the same code. The difference is intent. They both get you to separate and remove knowledge of an implementation from the client.


However, if you only have one implementation then when your peer reviewer asks why you're doing this your answer better not be the strategy pattern or she'll rightly beat you with the YAGNI stick. The point of strategy is the polymorphic power to swap out implementations, even at run time (something inheritance can't do). For that to work you'd need at least two implementations that implement the same interface.


DI has you do the same thing (the separation) for a different reason. Despite what the current Motivation section says, it's about the dependency inversion principle (Why do we have to tell this Foo thing what to be?), also single responsibility principle (hey, we just use Foo, building Foo is not our thing), loose coupling (we don't really want to know what Foo is anyway), substitution (we don't care if it's not a Foo so long as the way we talk to it doesn't change), reuseability (OK, so Foo is outta style, but we still rock), and creating a separation layer such as needed between business logic and data access layer (SQL, noSQL, we don't care, just save this somewhere already). It means the client never ever mentions Foo. IFoo maybe but not IFoo f = new Foo(); either. In fact, the new key word starts to get scarce.


Actually, who said you could call the interface IFoo? We're the client, we own the interface. Stop filling it up with methods we don't use. Foo and Foo's friends can play with other methods but we don't want to know about them. Here Foo, implement HowWeTalkToAnyFooishThing and don't go screwing with it without letting us know first.


If your constructor looks like this:
ClientClass() {
    this.foo = new Foo();
}


DI asks you to make it look like this:
ClientClass(HowWeTalkToAnyFooishThing fooishThing) {
    this.fooishThing = fooishThing;
}


That's the constructor style of DI. Use a setter instead or mention that setter in an interface the client implements and you get the other two styles of DI.


This is more then just DI I'm preaching here. This is SOLID. What we've done is simple. It's why we did it that is tough to explain.


When defending DI all you have to tell you're peer reviewer is that you don't want to depend on concrete implementations or be responsible for constructing them. You want to talk to those things through interfaces and you want something to just hand you a reference to them. Getting handed a reference IS dependency injection. The something could be a framework like spring, a factory (that builds you too), or just main(). The point of clean DI is that even this decision doesn't impact the client. Unlike Strategy, that makes sense even if right now you only have one concrete implementation.


The reason it makes sense is the same reason we use plugs and outlets in our homes. Sure, you could solder the wires in your toasters power cord directly into your house's wiring. But when the toaster breaks it's going to be a pain to fix. And whoever heard of a house that comes with a toaster?


Plugs and outlets are nice but they're expensive. When crossing an important boundary like your dry wall you definitely want them. But you'd probably fire an electrician who used them in every junction box (supposed to use wire nuts for those). Similarly, you may find people critical of over use of DI. The more significant the boundary being crossed (class, package, tier, library) the easier it is to justify using truly clean DI.


What's clean DI? No one should be able to look at the client and tell what's doing the injecting. Anything that gives it away, even annotations, represents something the code is dependent on. Something that you may have to change if you decide to inject using something else. When you use an alternative to DI like a Service Locator you're not removing all dependency. You're sweeping it into a corner.


The point of DI is to make a class that only offers it's own behavior. That is willing to talk to any object that implements it's interfaces. All without needing to rewrite it even if whatever is used to wire it together with other objects goes out of style and needs to change.
Galhalee (talk) 09:17, 13 March 2014 (UTC)

Dependency injection is...

The current statement, "Dependency injection is a software design pattern that allows the removal of hard-coded dependencies and makes it possible to change them, whether at run-time or compile-time" is not the definition used in the cited work[1]. That links to the abstract for this paper (See PDF link in lower left corner of abstract). On page 2 is an excellent definition of DI, "Dependency injection is a design pattern that shifts the responsibility of resolving dependencies to a dedicated dependency injector that knows which dependent objects to inject into application code". This keeps it from being confused with the Strategy Pattern's motivation to swap out implementations at run time. DI provides this power but only as a side effect. It is hardly the point. Galhalee (talk) 17:07, 16 March 2014 (UTC)

Introduction revision

ThomasO1989, why did you remove the concept of a reference being passed? Also, I'm trying to move away from the emphasis on swapping objects at run time as that's a motivation of strategy. For DI that's merely a side effect. DI just wants clients free of dependencies so the rest of the world can fall apart and the client doesn't need to change a line of its own code. Galhalee (talk) 02:39, 17 March 2014 (UTC)

Understood. Removed emphasis on "run-time" and explicitly referred to "reference" in the lead. It may be good to cover the difference between DI and the strategy pattern in the lead and in the Definition section as well. Also, feel free to ping me with {{ping|ThomasO1989}} when you have a question, as I may not see it immediately. --ThomasO1989 (talk) 02:52, 17 March 2014 (UTC)
Thanks, also, I am totally ignorant of proper citation procedures. That first citation is a URL hack of another one I saw and copied. I noticed dates inside that I have no clue if I am supposed to update. Please advise. Galhalee (talk) 03:58, 17 March 2014 (UTC)
If you're referring to the Martin Fowler citation, the only date you may want to update is the "accessdate" field. The other "date" field does not change, as it refers to the date the article was published. On an unrelated note, I feel that the opening sentence in the lead is becoming run-on and somewhat overly technical. It should be divided into two or more sentences. --ThomasO1989 (talk) 04:04, 17 March 2014 (UTC)
Yes that is the citation. I've updated it. And yes the first sentence is getting wordy. I've moved it into a second paragraph. How about I let you have at the whole introduction for a bit? Please ping me when you're done. Thanks for the help. Galhalee (talk) 05:03, 17 March 2014 (UTC)
I trimmed out some details that I thought were a little too much for the lead. It feels like it's trying to cover the entire definition of what and what does not make dependency injection, which might be overwhelming. I think that these details would be best appropriate in the Definition section. --ThomasO1989 (talk) 15:42, 17 March 2014 (UTC)

Definition

@ThomasO1989: Moved the details to the definition with some rewording. Take a crack at it. Thanks. Galhalee (talk) 19:10, 17 March 2014 (UTC)

Motivation

@ThomasO1989: Trimmed motivation down after Uses updated. Trying to avoid making the same point over and over. Galhalee (talk) 05:09, 19 March 2014 (UTC)

Examples replaced

@ThomasO1989: Have at it. Galhalee (talk) 08:39, 22 March 2014 (UTC)

@Galhalee: From a glance I notice some style problems. First is the repeated use of the word "you" and that it's written like instructions in a Head First textbook. Please avoid this, as it makes the article un-encyclopedic. Wikipedia is not a manual. Don't assume that the reader is interested in actually using DI. Second is the use of statements like "This is bad." and "So far so good." This is extremely un-formal for an encyclopedia. Same goes for the use of contractions like "it's", "isn't" and "doesn't". I'm letting you know this now before I make changes, so that you yourself can avoid this style in future edits. --ThomasO1989 (talk) 15:53, 22 March 2014 (UTC)
I've rewritten the "Refactoring in five seconds" to show the style I'd like the rest of the section to follow. The sections are renamed to avoid the manual-like intention.
Understood. Is the problem only with the text or are there problems with the code? Galhalee (talk) 16:44, 22 March 2014 (UTC)

--ThomasO1989 (talk) 16:24, 22 March 2014 (UTC)

Now that I look overall, the "Simple example" is already covered later in the Constructor injection section. It's not needed. "Complex example" is just a series of instructions to make a class fit the pattern. Like I said, Wikipeda is not a manual. I'm going to remove these sections altogether. We should focus on improving the existing sections instead. --ThomasO1989 (talk) 16:35, 22 March 2014 (UTC)
@ThomasO1989: "Complex example" is intended to show a dependency injection refactoring. It's meant to illustrate how wide the impact of a change like the "simple example" is to the rest of the system. Are you saying the code itself violates a wikipedia policy? Galhalee (talk) 16:58, 22 March 2014 (UTC)
I feel like iteratively refactoring the code is not the way to convey the benefits of DI. Objectively speaking, "Complex example" isn't an example of DI per se, it's an example of how to achieve it, which is what violates Wikipedia policy. The code examples already in the article already show how it's supposed to look. Since the goal is show the benefits of DI, I feel that rewriting Motivation should show this. You also must keep in mind that, like any pattern, DI has disadvantages. You shouldn't play up DI as a really great solution to a problem, otherwise you violate neutral point of view. --ThomasO1989 (talk) 17:10, 22 March 2014 (UTC)
@ThomasO1989:I don't mean to sound like Dependency Injection is a perfect solution. I would like to portray the mind set behind it. I'm still trying to find the right voice to do it with.
I had already made fairly critical additions to the disadvantages section. I'm trying to show DI as a solution to some problems and a way to over complicate others. Without showing the impact of refactoring the client on the rest of the system we'd actually be hiding one of its greatest disadvantages. It forces the creation of other code outside the client. That other code is what does the injecting and is a vital part of dependency injection.
I will admit it got fairly long because of the iterative steps. Would you accept if it was switched to simple before and after code listing? Galhalee (talk) 22:00, 22 March 2014 (UTC)

@ThomasO1989: I've unified the class names used in the examples so they are no longer conflict with other examples and made them less conversational. Is the hard coded example acceptable now? Galhalee (talk) 05:41, 23 March 2014 (UTC)

Destructive edit

@ThomasO1989: Did you honestly only mean to reorganize when you made this edit? "reorganise; having an overview halfway down the article doesn't seem to make sense to me, and a comparison with other options probably belongs near the end"

This edit did not merely reorganize. It destroyed cited content that was not merged into anything else.

@Galhalee: You're referring to this edit? It's quite clear I didn't do it, user Ironholds did. But I do agree that having Overview halfway down the article didn't make sense. I was thinking it should have been the first section after the Lead. --ThomasO1989 (talk) 08:21, 30 March 2014 (UTC)
@ThomasO1989: Ha, you're right. My apologies. How embarrassing. I guess I was used to you being the only other user making large changes.
Well then please offer your onion. Does it flow better organized like this or with an overview after the lead? I liked having the comparison to other patterns before the code examples because the code examples never explain the point of the pattern, just how it's achieved.
The comparison could be part of the Overview. Was thinking of having Overview then Examples as the first two sections. Galhalee (talk) 12:22, 30 March 2014 (UTC)


Comments

@Galhalee: Hey there, sorry for the week's absence, I was busy mostly with other articles and real-life, but I have some comments. The article is greatly improved, but I feel that the article is broken up into too many sections. Many of them are just for describing the pattern, its characteristics, and uses. I think one section, Overview, would encompass this better.

  • The Assembly comparison has problems. First, the use of "It turns out ... it's not implemented that differently." Turns out to who? This is using really casual textbook and instruction-like prose. It feels like the purpose of this section is to compare DI to other patterns. Can't this just be merged with the prose dealing with Strategy?
  • Definitions: it's nothing but random quotes. Can't they be merged elsewhere?
  • Equivalent terms: do you really need a whole section for this?
  • Elements: This can be merged into Overview.

--ThomasO1989 (talk) 16:29, 29 March 2014 (UTC)

@ThomasO1989: Glad to have you back. You're hard to replace. I'm glad you think it's improved.
The idea of an overview section sounds good. I'm reluctant to try to merge the different points together. That's how they were before and the concepts were getting muddled together.
The definitions are not random. They are from reputable sources and cited as such. The point was how different the definitions were. I had intended to add more as I found them. Is this not acceptable?
Different sources use a wide variety of terminology that needs to be explicitly dealt with. I'm trying to reduce this by ruthlessly re-editing the article to make the terms it uses consistent at least with it self.
I guess Textbook prose is hard to keep from writing after reading a lot of textbooks. I've made some edits to correct it. The point of assembly comparison was to admit dependency injections dirty little secret. You can't use it everywhere. At some point you have to breakdown and decide what dependent implementations to use. When you do that you're often using a service locator. This causes confusion because these are seen as opposing patterns. The point was that it's fine if it's done in one place in an application. It has nothing to do with strategy and shouldn't be dealt with until after the assembly examples.
Thanks for the feedback,
Galhalee (talk) 17:33, 29 March 2014 (UTC)
The current Overview section doesn't flow well. It goes all over the place, from comparison to other patterns, then to uses, then to definitions, etc. This confuses the reader. Defining what the pattern is should always come first. What it's used for won't make any sense for the reader if he doesn't know what it is. I feel that the Overview should actually be one whole section without subsections; things like "equivalent terms" can be described in a sentence or two instead of lists. In regards to the quotes, while they are relevant, they aren't integrated well. What I meant by "random" is that they're just kinda dumped there, like it was copy pasted from any source found on Google. I feel like this approach unintentionally slips into plagiarism territory. If you can define the pattern with one or two of the most useful quotes, you don't need more. Copying more and more quotes into the section isn't going to be useful to the reader. You should also paraphrase quotes instead of using them verbatim. In regards to DI's "dirty little secret", it sounds like a disadvantage. Could you merge this in the Disadvantages section? --ThomasO1989 (talk) 17:59, 30 March 2014 (UTC)
@Galhalee: I have a new version of the Overview section rewritten. I felt ultimately that there's a lot of repetitiveness and a lot of information that is either not vital or that should go into over sections. I've tried to condense the information into only a few paragraphs. There's still more work to be done, though, and it's difficult because not many references have been supplied. I've added many "citation needed" tags also. --ThomasO1989 (talk) 19:27, 30 March 2014 (UTC)
  1. ^ Niko Schwarz, Mircea Lungu, Oscar Nierstrasz, “Seuss: Decoupling responsibilities from static methods for fine-grained configurability”, Journal of Object Technology, Volume 11, no. 1 (April 2012), pp. 3:1-23, doi:10.5381/jot.2012.11.1.a3.