Last week, I was working with a C++ team and they needed some testing help so I pulled out my bag of tricks. I showed them how they could make their code more testable by externalizing object creation and adding constructor parameters. They were a little shocked that I would add constructor parameters just to make code testable, so I asked whether they’d ever heard of dependency injection (DI). My question was met with silence, but frankly I expected it. In my experience, few people in the C++ community seem to know about dependency injection. Part of this is understandable. C++ has been growing away from Java for the last seven or eight years. There used to be a rather large overlap between C++ and Java programmers, but that’s changed. The Java community has spent a great deal of time developing frameworks and tooling to advance their practice, but tooling is difficult in C++ so that community has been spending a great deal of time pushing templates as far as they’ll go.
I was talking to Scott Meyers at
a conference earlier this year and he said that he felt that the real fork in
the road was ease of parsing and tractability of analysis; that C++ was
developed before people realized just how valuable those attributes were in a
language, and as a result, the things that people do with reflection and
tooling in Java are now attempted with template meta-programming because it
seems like the easiest avenue. It
doesn’t look all that easy from where I sit, but it does look like a committed
course of action. The C++ and OO
communities don’t seem to have much in common any more in the solution space,
but they do have some common problems.
Testability is a tough taskmaster. It’s hard to write code that is easily testable unless you’re very diligent. When we work in statically typed languages, code is coupled by default. If a class uses another class, you have a compile-time dependency. C++ does have a sneaky way out of this problem. Templates are essentially un-typed so you do have some leverage before they are all instantiated to type-safe code, but regardless, testability is hard. If a class of yours uses vendor software that you can’t really run in your test environment, well, you need an adapter to mock it out. If you didn’t build one in, you’re left with the task of refactoring one in.
In the Java community, dependency
injection has evolved as a way to solve this problem. The core idea of dependency injection is
simple: object creation is a separate concern. If you push object creation into a separate area: an über-factory, you
can make your code more flexible and more testable. Most descriptions of DI dwell on XML configuration,
but it’s really simpler than that. Essentially, a DI system has a big bag of types and you go to that bag
(factory) and tell it to make you an object of a particular type. The bag looks at the types and sees if it can
create the object you want. It uses reflection to examine constructor
arguments, setters on classes, etc. If
it finds that it can, it will give you the object you asked for. If you want an instance set up for testing,
you alter the types in the bag.
C++ makes this a bit difficult. There’s no general way to determine the arity or arguments of a constructor at compile-time so that standard tricks for mimicking reflection with templates don’t work. There may be a way to do setter-based injection, using some of Andrei Alexandrescu’s hierarchy generation techniques, but I’m not sure yet.
In any case, it seems that to do DI in C++, you have to place constraints on the classes you create.. you have to make them inherit from some other class, use macro preregistration or a metaobject library. The one C++ DI framework I've heard of, QtIocContainer, seems to bring along some of those constraints. Maybe they are inevitable.
The thing that I do know is that it would be useful to have more awareness of DI in the C++ community. I may be overestimating it, after all, the C++ community has not had nearly as many widespread, crippled vendor APIs hoisted upon them.. APIs which make testing a real bear, but I’ve seen a few, and I suspect that DI could help.
QtIoCContainer is intrusive by mandating a container specific parent interface class. Therefore, it is not a POCO (Plain Old C++ Object) Ioc container. Besides, I recall it only supports property setter injection.... but not ctor and generic factories....
Pocomatic Software (www.pocomatic.com), is building a true non-intrusive IoC container for C++ at the moment, called Pococapsule/C++. And is to be alpha next month, and officially release by Q1 2007.
Besides being truely non-intrusive and supporting POCO, this container supports all 4 types of injections:
1. constructor injection
2. property setter injection (both method setter, as well as direct data field assign injection)
3. non-static method (factory) injection
4. static method injection (and even global function injection).
Other features include:
1. it is type safe (type error will be cought and reported)
2. life cycle management (for singleton bean)
3. small footprint and lowest compiler requirement
(we do not use RTTI, template, and minimumize
the usage of exception).
And most important of all, it supports so-called the zero-code customizability. One can easily customize and extend the container's deployment schema without writing C++ code. This feature is already available in Pococapsule/Java released last month, and is used by us to build our CORBA application framework (Pococapsule/CORBA).
Regards,
Ke
Posted by: Ke Jin | October 12, 2006 at 10:57 AM
Ke,
Thanks for the info.. I suspected that someone out there was doing something like this, but I hadn't found while asking around.
I tried writing an IoC container for C++ a while ago, but I wanted to support POCOs and I kept wondering whether it is really possible. I'm very curious about how pococapsule will do constructor-based injection without reflection. I pulled my hair out trying to figure out some way to do it with templates.
Thanks again for the heads up.
Posted by: Michael Feathers | October 14, 2006 at 08:52 AM
I checked www.pocomatic.com and it doesn't look like the IoC container for C++ is released yet. The time is Q4 of 2007. Do we know if this is going to happen?
Posted by: Xibin Zeng | September 28, 2007 at 09:57 AM
Please check the it again. It was released as an open source at:http://code.google.com/p/pococapsule
Ke
Posted by: Ke Jin | January 08, 2008 at 02:00 PM
I implemented yet another C++ dependency
injection framework, which recently was proposed for boost – https://github.com/krzysztof-jusiak/di –
library is macro less (free), header only, C++03/C++11/C++14 library providing type safe, compile time, macro free constructor dependency injection.
Posted by: Kris | July 25, 2014 at 05:00 AM