Hi,
On Sat, May 18, 2013 at 11:11:19AM +0300, Niklas Laxström wrote:
They proposed a solution (work around in Wikibase) to
allow writing
better code in Wikibase. [...] But as a reader I
did not understand how it works
I was also surprised to realize that although the report constantly
talks about a lack of dependency injection {,mechanism,facility} (in
their meaning), their solution is not dependency injection (in the
common meaning), but a service locator (in the common meaning) :-)
Seeing a separate service locator in a friendly extension comes even
as a greater surprise to me.
Although it's already close to 10 years old, to me, Martin Fowler's
article on dependency injection [1] is still a great primer on “how it
works”. The article provides nice short code snippets (Java, but they
should be easily readable by any PHP developer) and diagrams on how
things get created in different scenarios.
or what would be the practical gains
for the code complexity that the solution itself introduces.
I am probably biased, but for me, implementing only the service
locator solution they propose, comes with little gain.
Service locators are “only” a tool assisting in decoupling direct
dependencies between objects. That's good already, but service
locators do not help with composition of objects, which is most of the
work. They also do not help/allow to read off dependencies from
objects (as for example constructor injection would).
Additionally, MediaWiki already partly uses service locators (Getting
a Database connection). Nothing to gain in such parts.
Through service locators' additional indirection, they slow down code
a bit, but are a first step to allow for easier testing.
The real paradigm shift would be to go for dependency injection (in
the common meaning) and start using an inversion of control container.
* What would that cost us?
Some performance, due to the decoupled dependencies.
* What would that buy us?
Testable code.
Example? Example.
When implementing a unit test for a plain project renaming in gerrit,
I started stubbing the required objects and the test reached ~1000
lines of code (a single test! :-( ) although I was only 3/4 through
with setting up the required stubs.
This insane amount of code for a single test did not come as a
surprise. After all, the function under test had to move the project
around in the database, move it in the file system, add git commits to
child projects, ... and to test in isolation, you'll just have to stub
all that out.
And every further test of a different path through the same method,
would mean adding ~1300 lines of code to the test case.
So, since gerrit already embraces dependency injection, IoC, and
coding by contract, I could break the project renaming code into
smaller objects, and let the IoC container do the composition on its
own. Thereby, testing each of the parts in full isolation is
easier. And variations in code paths can be tested right where they
are. It's no longer needed to test the whole code as one blob.
For this concrete example, testing only the top-level method (assuming
sub-tasks meet the contract) requires 16 tests. For the unrefactored
code, that'd be ~20k unmaintainable lines for the tests alone.
After the refactoring for dependency injection and IoC, the whole file
of the test case including header, imports, ... (and the tests) is
~0.5k lines.
Of course, we can always refactor code even without dependency
injection or IoC containers. Everyone is doing that :-) “Dependency
Injection” is just the hip name for a series of patterns that allow to
decouple objects. And IoC containers just make it easy to stitch them
back together at run-time.
Best regards,
Christian
[1] "Inversion of Control Containers and the Dependency Injection
pattern". Available at
http://www.martinfowler.com/articles/injection.html
--
---- quelltextlich e.U. ---- \\ ---- Christian Aistleitner ----
Companies' registry: 360296y in Linz
Christian Aistleitner
Gruendbergstrasze 65a Email: christian(a)quelltextlich.at
4040 Linz, Austria Phone: +43 732 / 26 95 63
Fax: +43 732 / 26 95 63
Homepage:
http://quelltextlich.at/
---------------------------------------------------------------