4 ms·
I can't figure out the point of this article. Why does adding one more seemingly arbitrary layer of abstraction help anything?
by lackbeard 11y ago
I can't figure out the point of this article. Why does adding one more seemingly arbitrary layer of abstraction help anything?
- jamestomasino 11y agoIf I read that correctly--and I most likely did not--it seems that he's making the argument that a misunderstanding of semantics and clear definitions lead to poor implementation of DI, IoC, and DIP. The final case seems to mostly address Java's flagrant mis/overuse of interfaces. Like you, though, I struggle to find a clear message. Is this a complaint about things being done wrong? The solution presented around Dependency Inversion Principles was really tough to understand. It looks like he just made everything harder. It's been so long since I've done anything but front-end web work, though, that might just be me.
- kasey_junk 11y agoThanks for the feedback. This was an article I wrote after having a few discussions with developers where people were confusing DI, IoC, and DIP (and IoC containers were thrown in as well). I posted it today as there were several other articles that were also mixing the topics up. My hope was to make the differences more clear. Not accomplishing that was the more probable outcome ;)
- mongol 11y agoWhy should one not use setter methods?
- chrisguitarguy 11y agoIf your objects require dependencies to do their jobs, it should be impossible to create objects without those dependencies. The objects' constructors should require them. Having setters is, arguably, fine (but probably unnecessary) as long as invalid objects can't be created.
- Roboprog 11y agohttp://en.wikipedia.org/wiki/Class_invariant http://en.wikipedia.org/wiki/Class_invariant (above is a special case of below) http://en.wikipedia.org/wiki/Design_by_contract http://en.wikipedia.org/wiki/Design_by_contract Alas, Eiffel looked like Modula (Pascal), rather than like C/C++, so it never caught on. The important part, though, was the idea of class invariants + method pre-conditions + method post-conditions. Meyer's book, from years before Java and "Java beans" infected the group-think, talked about classes that explicitly were constructed in a valid state (which also meshes well with the practice of immutability), and methods with explicit conditions of their requirements and what they were guaranteeing they would accomplish. "Java beans" pretty much took these otherwise sound engineering principles and pissed all over them. Rather than having a constructor that builds an object that you can then start using, you have to guess (unless documentation is very good, which it won't be) which setters must be called before "bean" is non-crap. Yes, I'm bitter that such an obviously flawed practice became standard operating procedure, to the point that doing things right is viewed as suspect.
- dack 11y agoSetters basically send a signal to the developer that the dependency is "optional", since someone can create the object and simply not call the setter. Most of the time, the dependencies are assumed to be set in, and will blow up at run-time when they are attempted to be accessed. By using constructor injection you prevent this from happening. Also, consider a case of refactoring. You have a class that is being created from a few places and add a new dependency via a setter to it. Compile your code, and it looks fine but actually isn't - you need to find all the places you create that object and provide the extra dependency. If you use constructor injection, you'd have a compile error (in a statically typed language) in all the places that need to be fixed.
- kasey_junk 11y agoUsing dependency injection adds complexity. You have to reason about how the injected functionality can change. If you use setter based injection (as opposed to constructor or parametric injection) then you also add the complexity of reasoning about when it can change.
- Roboprog 11y agoThank you, loved it. I think the DIP part could use a little more explanation, but the DI/IoC parts very much hit home with me, underscoring some points I have also been trying to get across to people.
- pacala 11y agoTL,DR: Complex logic depends on data objects declared in your module. Instead of Logic => Dependency, refactor as Logic => Data + Data => Dependency. The code is organized as: // What kind of Data Logic processes. trait Data { ... } // How Data reads from a concrete Dependency class DataFromDependency extends Data { ... } // Logic class Logic(data: Data) { ... } Whys: * Trivial testing of the Logic, by instantiating Data objects with fake data. If you ever had to instantiate a DB and populate it with 132 right objects just to test that date conversions work correctly, you know what this means. * The Data adaptors reduce the semantic surface of the Dependency to what Logic needs. This makes reading and reasoning about Logic easier, especially if Dependency is a "fully featured" library with tens of methods Logic couldn't care less about.
- nitrogen 11y agoIn Ruby this sort of thing comes naturally due to its much more flexible metaprogramming features than Java-like languages. Testing frameworks like RSpec and the various Gems that go with it for building mock objects make this very easy and common, without having to restructure the original code or have a bunch of nonobvious names for a bunch of patterns. I have nothing against Java and still take work in Java, but I think every Java developer would learn a lot from Ruby-like languages.