
Dependency Injection is a Virtue - mpweiher
http://blog.metaobject.com/2013/01/dependency-injection-is-virtue.html
======
h2s
Couldn't agree more. If the behaviour or outcome of a function depends on the
current time, then the current time is an input to that function. Inputs to
functions should be declared explicitly as arguments where possible.

The existence of Time.now and the fact that it's _possible_ to stub this
method are not in themselves a good enough justification for excluding the
current time from the list of explicit inputs. The length of the list of a
function's inputs is one of the indicators of whether a function has too many
disparate inputs and therefore too many responsibilities. Obscuring this
number is likely to lead to more cluttered code.

In DHH's example, Time.now should be called somewhere higher up the call stack
where its return value doesn't matter to the outcome of the function in which
it resides. It should look like this:

    
    
        def publish!(time)
          self.update published_at: time
        end
    

That way the inputs are clear. It also happens to mean that you can test it
without requiring the linguistic flexibility provided by Ruby, but that
doesn't mean that testability in inflexible languages is the only reason why
it's the right thing to do.

~~~
wyuenho
I think most of you are missing the point. I think the example DHH used should
be interpreted as calling

    
    
        post.publish!
    

is easier than

    
    
        post.publish! Time.now
    

Since when you publish, the time of publication is the only value that make
sense. Now, you can argue that you can set a default argument to Time.now, but
that's weird code that only make sense if you need to supply a value other
than Time.now, which you will only do in testing, so the code in DHH's example
is optimal.

The point of DHH's blog post is, in a flexible enough language like JS, Ruby
and Python, you can still test pretty much anything without DI. I honestly
don't know any other reason why one would want to use DI other than making
Java testable. In fact, you don't even need that in Java anymore because you
can use Mockito these days and it can mock private stuff.

The stupidest reason I keep hearing over and over again is DI makes it
possible to change an implementation at runtime. Wait what? Don't you have to
change the application.xml file in Spring and restart the app? AFAIK there's
nothing in Javaland that lets you listen to config file changes and then
magically reconfigure the app context and make a copy of said context as a
thread local in every new thread. Correct me if I'm wrong please. Even if
there was, what magical alien land would require such a "feature", and such
feature is so important that requiring your entire code base to be littered
with all these indirect abstractions acceptable?

~~~
Xylakant
DI to swap out an implementation at runtime is an extreme edge case, though
"runtime" may mean "the app can determine at startup which implementation
makes sense". If you want to have a look at a nice usage of DI, peek into the
source of Elasticsearch. You can swap out pretty much any relevant part of the
implementation. You can for example change the HTTP acceptor to provide
authentication [1] or add SSL [2] So there are cases where changing the
implementation makes sense.

[1] <https://github.com/Asquera/elasticsearch-http-basic>

[2] [https://github.com/Asquera/elasticsearch-ssl-transport-
plugi...](https://github.com/Asquera/elasticsearch-ssl-transport-plugin)

~~~
wyuenho
For which any simple configuration mechanism will do, and as long as you stick
with coding to the interface, the problem is solved. So while technically this
is called DI in Java, it's simply code taken as granted in many dynamic
languages because of duck-typing. So yes, this is totally valid use case, but
one with no need for a DI container in dynamic languages to solve.

~~~
thelawal
First a DI container is not a necessary to do DI in any of the discussed
languages. This is shown by the fact that you describe using duck-typing as
method of doing DI in Ruby.

------
barrkel
Every few years, there are fashions in our industry that feel like moral
virtues to follow; structured programming, object orientation, patterns,
functional, TDD, IoC. They warm the cockles of your heart, make you feel good
about yourself.

But I am suspicious of this feeling, because it is an emotional in-group
attachment, a bit like a religion. All religions have costs to following them,
so that disbelievers may be easily recognized and (to a greater or lesser
degree) demonized. But the world isn't and shouldn't be so black and white.
Actions should be analyzed more carefully, and above all, rationally.

Code structured in a fashionably virtuous way makes me suspicious that the
situation may not have been analyzed dispassionately. The style may be an end
in itself.

I'm especially on guard because I used to be an acolyte of the OO religion.

~~~
Jach
In other words, you're part of the _Programming, Motherfucker_
(<http://progmofo.com/>) religion now? ;)

~~~
cnlwsu
I have never seen this before... I think I was just converted.

------
stephen
Personally, I feel that a lot of the Java hate is misplaced.

Just because most Java programmers/architects use/love J2EE, crazy XML/DI
frameworks, etc. is not a fundamental attribute of the language itself, just
an unfortunate result of how it's mainstream usage has evolved.

I assert you can write "nice Java", either with something like (shameless
plug):

[http://draconianoverlord.com/2011/03/17/frameworkless-
di.htm...](http://draconianoverlord.com/2011/03/17/frameworkless-di.html)

Or, for a better source, GooS, Growing Object-Oriented Software, by Steve
Freeman and Nay Pryce:

<http://www.growing-object-oriented-software.com/>

...although, yes, a more succinct language like Scala helps too.

~~~
ssmoot
Piggy-backing on your response:

The J2EE hate is a cheap shot. It's just a stack of tools/APIs. Which part of
it do you hate?

The Servlet API is just Java's version of Rack. It's actually mostly pretty
nice. It definitely have it's faults, but it's also much more robust than
Rack.

Is it ejbeans?

Is it JMX?

I mean, what is the hate exactly? People might be rightfully annoyed if you
just said "I hate Rails" when you actually meant "I hate Devise".

Anyone running JRuby Rails apps are using a portion of J2EE and they may not
even know it. It's what allows you to flop between Mizuno, Trinidad or
Torquebox and not have to care.

------
mdemare
Mostly disagree. Pure functions are beautiful and have their place, but not
every function should be a pure function. And a Rails controller method is the
opposite of a pure function - it has a database connection, several file
descriptors and hundreds of objects at its fingertips. That is its strength,
and DI has no place there.

That said, if you have a pure function, and you need to know the current time,
consider keeping it pure with DI.

~~~
mercurial
Er. Obviously, not every function can be a pure function, otherwise your
program will not work. However:

\- controllers should not touch the data layer directly (and therefore follow
SRP)

\- controllers should have their business layer services injected from
somewhere else

This does not make them pure in the sense they remain (indirectly) functions
with side-effects, by virtue on relying on business services, which themselves
interact with data access services which do IO. However, it does make them
testable without resorting to hacks and offers a clean interface.

~~~
mdemare
The vast majority of Rails apps fail those conditions. I'd say that it's not
the Rails Way to follow those precepts, so I believe your comment dismisses
Rails in one stroke. I'm not sure if that's a very productive line of thought.

~~~
mercurial
It's not impossible to achieve with Rails, it depends on what you put in your
fat models. There is nothing which keeps you from having an intermediate
business layer. I'm not sure how you would handle DI cleanly though, maybe
it's possible with Rails 3? My brief experiments with Rails date from a few
years ago, so I'm a bit fuzzy about this sort of details.

I'm confused about your comment regarding productivity. Either my
recommendations are mostly valid, in the sense that they offer a distinct
advantage over the current, Rails-y way of doing things, or they are not (but
in which case you would need to make a cogent argument for why they are not).
If they are, surely recognizing the shortcomings of a particular design/set of
accepted practices is a benefit.

The fact that Rails 3 has undergone significant architectural changes with the
merge of Merb shows that Rails did not emerge perfect from the thigh of DHH.
And we all strive to improve ourselves and the tools we work with (or
alternatively, for those of us for whom this is not an option, we stay with
PHP or VB and stare blindly at people talking about "MVC").

------
darkxanthos
"I don't like this tool. I've found ways around using it." "I use this tool a
lot."

Why is this so controversial? It's a hammer. Ultimately you're trying to get
two pieces of wood held together and you've all found a way to do that.

As long as both camps can sustainably produce maintainable software the point
is moot.

------
xrd
DI is why I see AngularJS as the best of the new JS frameworks out there.
Given current JS language limitations DI makes AngularJS so testable, and you
cannot say this about other tools like Backbone.

------
tszming
I think DHH is actually not complaining DI in a general sense - DHH just want
to emphasize DI is not required in dynamic language such as Ruby.

He also said that the real problem is when people applying techniques to solve
one language's limitation on other language which problem does not exist and
think it is okay. _(..While we can cross-pollinate some ideas between
languages, there are many we cannot. ..)_

So, if you are using Java, it is perfectly fine to continue to use DI, but
think carefully when you are using DI (framework/container) on Ruby..

------
jebblue
I think the Spring concepts confuse things more than solve problems. Example:
configuring stuff in a bean.xml file, your code does not own the creation of
the instances, some magical springy mechanism does it for you. What's wrong
with just letting the program read its startup parameters from a properties
file? Stack traces from springy code is just that like trying to eat a pea
with a knife.

~~~
brown9-2
Nothing is wrong with letting your program read it's startup parameters from a
properties file (and thus doing all the wiring up of classes in code
yourself). Spring and it's bean.xml files are meant as a replacement option
for that for when you find that doing-it-yourself is too tedious/too much
code.

------
smoyer
I agree ... I won't even complain about Java's DI implementation. I've used
both Weld and Guice and will admit that both have edge cases that aren't
ideal, but it's better than the alternative.

In general, I think I'll choose MF over DHH anytime both have an opinion:

<http://martinfowler.com/articles/injection.html>

------
laureny
I can't for the life of me find the connection that DHH is making between
dependency injection and the fact that a language is dynamically or statically
typed.

These two concepts are completely orthogonal to each other.

------
deltasquared
No, Dependency Injection is a language specific pattern. A pattern useful in
Java, but not in Ruby.

------
martinced
_"Having hard-coded class-names like in the example Time.now is effectively
the same as communicating via global variables."_

But having DI is exactly that: DI is about glorified global variables!

I realize most HN participants living in the Java/C# + ORM ([N]Hibernate)) +
XML + SQL hell are just loving DI because it's a tad bit less worse then
global variables but, dudes, there's another world out there.

A lot of functions can be made idempotent (always returning the same output
for a given set of inputs) and also pure (idempotent _and_ without any side-
effect) and this facilitates everything: it gets much easier to "recreate the
state" and it makes it easier to reason about your programs.

It's sad because HN is a community built by pg, who talked about "beating the
average", about using Lisp dialects, about Emacs, etc.

I took all his writing as "thinking outside the box".

And what do I see here? I see that HN is mostly consisting of enterprisey
programmers living in the Java/C# + ORM + XML + SQL hell and not even
realizing there's another world out there.

It is sadening me.

~~~
mpweiher
Did you bother to read about Newspeak or click on the links?

Did you see the part about Java "AbstractAbstractFactory" actually being very
close to "worse" than global variables?

<http://newspeaklanguage.org>

But apparently clicking on links is too hard, so I'll quote inline:

"Newspeak is a new programming language in the tradition of Self and
Smalltalk. Newspeak is highly dynamic and reflective – but designed to support
modularity and security. It supports both object-oriented and functional
programming.

Like Self, Newspeak is message-based; all names are dynamically bound.
However, like Smalltalk, Newspeak uses classes rather than prototypes. As in
Beta, classes may nest. Because class names are late bound, all classes are
virtual, every class can act as a mixin, and class hierarchy inheritance falls
out automatically. Top level classes are essentially self contained parametric
namespaces, and serve to define component style modules, which naturally
define sandboxes in an object-capability style. Newspeak was deliberately
designed as a principled dynamically typed language. We plan to evolve the
language to support pluggable types."

Sheesh.

Update: I know the creators of Newspeak, but am not affiliated in any way.

