[kforge-dev] Dependency Injection in Domain Model, Kforge

John Bywater john.bywater at appropriatesoftwarefoundation.org
Mon May 14 21:53:36 UTC 2007


[Posted on behalf of David Heath; his attempt bounced.]


Dear All,

I've recently started some work with John to make piece of software
caleld "eternity", for helping to run fixed time-box projects. In the 
process
of this, I started working with the Domain Model library, and noticed a
problem with the current dependency injection system in use.

The current library, which was taken from:
    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413268

has code which looks a bit like this (example from dm.plugin.base):

     from dm.ioc import *

     class PluginBase(object):
         logger = RequiredFeature('Logger')

The calls to RequiredFeature within services, together with the widespread
import of dm.ioc, exhibit the "container dependency" anti-pattern:

     http://www.picocontainer.org/Container+Dependency

This is a problem because it eliminates some of the main benefits of
dependency injection, namely:

     i) container agnosticism: with container dependency, components 
expect a
particular type of container to be in use. Components can't be used in other
containers, or on their own. If container dependency is eliminated,
components could be used stand-alone or in other frameworks and containers
with no problem
     ii) testability: with container dependency, you have to use and 
configure
a particular container in order to test. In the DM case, the container is
just a global variable, and so it's hard to avoid interference between one
set of tests and another. Without the container dependency, you can unit 
test
each component in isolation, and don't need to use a container. The
dependencies can be explicitly satisfied in the tests, e.g. by providing 
mock
objects.

After a bit of research, and seeing the elegant approach which had been 
taken
in ruby [1], I decided to see if I could find a simple, easy to use,
non-intrusive way to make dependency injection work for the domain
model/kforge code. To this end I implemented a simple dependency injection
container which I've called "DIPPY" (for Dependency Injection in 
PYthon). The
source code can be downloaded here:

http://project.kforge.appropriatesoftware.net:9080/eternity/svn/trunk/src/ete
rnity/

The code is in dippy.py. There are also full unit tests in dippy_test.py 
plus
a simple example in dippy_example.py.

About DIPPY:

My aim with DIPPY was to make a very simple container supporting primarily
constructor injection and also setter injection, which would support the
current code of DM without requiring it to be modified too much. The Pico
Container folks make point out some strong benefits of constructor injection
over setter injection [2], but setter injection can be less intrusive and is
more similar to the current implementation using RequiredFeature().

Migrating to constructor injection would require some simple refactoring of
the domain model code. The final result would be an easier to test system,
with more explicit dependency relationships, and obviously no longer
suffering from the container dependency anti-pattern. Migration could be 
done
in a piecemeal fashion, whilst keeping all tests running.

Other python frameworks:

I've also just realised that my initial research wasn't thorough enough and
that there are actually two other dependency injection frameworks for 
Python:
PyContainer and Aglyph. Of the two, Aglyph seems to be under more active
development and also has unit tests wheras PyContainer does not. They both
provide facilities for doing component wiring using XML files (which I don't
really think is that useful), and Aglyph also allows component wiring in
plain python (not sure about PyContainer).

Questions:

Sorry for the long email, and thanks for making it this far. I'd love to 
hear
your input and thoughts on this. Do you have any experience with any of the
other python DI frameworks? What do you think of DIPPY? Do you think it 
would
be good to refactor DM to us constructor injection or is it just fine how it
is?

Best regards,

David Heath

links:
[1] 
http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc
[2] http://www.picocontainer.org/Constructor+Injection

--
http://davidheath.org/







More information about the kforge-dev mailing list