The Adventures of Dependency Injection and Inversion of Control.

I like to think my first words were ‘std::cout << “Hello World” << std::endl;’. The canonical C++ Hello World program. But alas, they weren’t. I cut my teeth on QBasic (Quick Beginners All purpose Symbolic Instruction Code, not to be confused with QuickBASIC). I did my time in QBasic, writing ‘viruses’ that would show download progress bars, and print ‘Ha Ha’ infinitely (sorry Dan).

Oh look, I’ve digressed; Back on topic — My first C++ experience was in CMPUT101. That’s when I fell in-love with the language. It was the :: that did it. Also, I always liked the simplicity of the language (Say what?). Anyways, as a young (and full of vigor, I might add) C++ software developer fresh out of school, I often found my code tangled and tightly coupled. Class design in C++ is hard. For me, often my class designs consisted of a lot of value members, and a lot of  concerns fused together.

A value member, is a instance of a class (or POD) as a member variable, of another class. In C++, value members are laid out in memory as they’re declared in the class.

class foo
{
public:
   int A;
   int B;
};

class bar
{
public:
   foo fooA;
   foo fooB;
};

If sizeof(int) == 4, then sizeof(foo) == 8 and sizeof(bar) == 16; Hopefully this makes sense.

[I’m getting there!]

So the thing about value members and call by value in C++, is that there is no polymorphism. You only get polymorphism, or virtual function calls, when you call on a reference or a pointer. Which means, when your class is full of value members, you’re EXTREMELY tightly coupled to the implementation of those members.

Here’s an example to illustrate what I’m talking about.

class file_to_database
{
private:
    file file_;
    database database_;
public:
    file_to_database(const std::string &filename, 
                    const std::string &connect_s)
    {
    }

    void parse()
    {
         std::string line;
         while(file_.read_line(line))
         {
              std::string tablename;
              std::string v1, v2;
              // do some parse work
              database_.insert(tablename, v1, v2);
         }
    }
};

int main(int argc, const char** argv)
{
    file_to_database ftdb(argv[0], argv[1]);
    ftdb.parse();
}

As you can see. We’re very very coupled to both the implementation of the file and database.

When you start delivering code for realz, and have to debug in the field. That’s about the time you remember back to school, and this thing called a ‘Unit Test’. Then it dawns on you, *that might not have just been a ploy to get me to do more homework, but actually useful!!!* So you think to yourself, *Self — I should probably unit test my code*. So you trudge down that road. Hi! Ho! Hi! Ho!

There’s only one problem with that. Everything in your class is a value member. Meaning no polymorphism. Meaning you’re stuck with the implementation you wrote, coupled to a database and all. *Shit.*

I headed on a path of discovery. I was going to solve this problem. How can I make my classes more testable and less coupled to implementation details?

If I boil down my research (and years of experience after). It comes down to 3 rules.

  1. Favour composition over inheritance – inheritance is the tightest coupling you can get. Unless you need it, don’t use it.
  2. Develop to an interface – use well designed interfaces to separate implementation from algorithms.
  3. Use Dependency Injection – dun. dun. dun.

Let’s see where I went wrong.

  1. Check. My classes were generally composed of other types, as value members.
  2. No polymorphism, no interfaces.
  3. What is this even??

Now, at this point I was part of the all mighty C++ development crew!! The language coursed through my veins. Oooh Rah. I had a major hate-on for Enterprise Developers and any type of managed languages. (I still hate JAVA, so if you’re a JAVA developer stop reading right now and go learn a real programming language. Just kidding! 🙂 No but seriously, my language compiles your language.) However, I had heard about this thing called ‘Dependency Injection’ from the Enterprise team at work. I also had read about it on the internet. I took a look at some ‘Dependency Injection’ code examples on the internet. Uhhh. Okay Mr.C-Sharp, where the heck does anything begin, who owns what? Wow. I’m going to stay as far from ‘Dependency Injection’ as I can.

By this time, I had solved my unit testing woes. I started using reference members to pure virtual classes (interfaces). Lastly I started taking all the implementations of the classes in my constructors. This allowed me to write tests against my classes, make sure they functioned correctly using mock implementations. Then in production, supply the real-world implementation. I could now mock out my databases and files, supply those in the constructor and test my classes. This also, really simplified my ownership models. I won. Check and mate, Mr. C-Sharp. No ‘Dependency Injection’ here.

  1. Check.
  2. Check.
  3. Hell no. Who needs that? I’ll control where things are created, destroyed and owned. Thank you very much.

It didn’t matter, because I was now cooking with dynamite, I could unit test! Hizuh! I don’t need your silly ‘Dependency Injection’ where I have no idea who made what, when or who owns anything.

Here’s the example above, re-imagined to suit my testing needs.

class ifile
{
public:
   virtual ~ifile() = default;
   virtual bool read_line(std::string &line)=0;
};

class idatabase
{
public:
   virtual ~idatabase() = default;
   virtual void insert(const std::string &tablename,
                       const std::string &value1,
                       const std::string &value2)=0;
};

class file_to_database
{
private:
     ifile &file_;
     idatabase &database_;
public:
     file_to_database(ifile &file, idatabase &database)
     :file_(file), database_(database)
     {
     }

     void parse()
     {
         std::string line;
         while(file_.read_line(line))
         {
              std::string tablename;
              std::string v1, v2;
              // do some parse work
              database_.insert(tablename, v1, v2);
         }
     }
};
class file : public ifile
{
public:
    file(const std::string &filename)
    {
    }
    virtual bool read_line(std::string &line) override
    {
        // implementation
    }
};

class database : public idatabase
{
public:
   database(const std::string &connect_s)
   {
   }
   virtual void insert(const std::string &tablename,
                       const std::string &value1,
                       const std::string &value2)
   {
        // implement
   }
};

int main(int argc, const char** argv)
{
    file f(argv[0]);
    database(argv[1]);

    file_to_database ftdb(file, database);
    ftdb.parse();
}

As you can see, this refactor takes the parsing code from near impossible to test without a file and a database. To extremely easy to test, by mocking out our inputs (ifile) and our outputs (idatabase). The awesome thing, I didn’t even touch the parsing algorithm. Just a couple smart interfaces, and introduce the dependencies in the constructor. Bingo. Bango.

So — a little while later, I’m attending CPPCON and I’m having a couple wobblies with a friend. He’s a C++ Guru and did some time at a C# shop. We got onto this topic. I tell him “Man, have you heard of this ‘Dependency Injection’ thing? What a nightmare. How do you even know when things are constructed? Who even owns what?”

He pauses. Then he delivers a mind-bottling statement. “Dependency Injection IS NOT Inversion of Control.” I said, “What?!?” He pauses again. “Dependency Injection IS NOT Inversion of Control. Dependency Injection is simple — just make your classes take what they depend on in the constructor…. When you use interfaces it makes it so you can replace the implementation of the dependencies, without modifying the class.” I think I almost fell off my stool (and it wasn’t the amount of wobblies I had). “No. No. No. Dependency Injection is this crazy-ass thing that obfuscates where objects get created and requires that everything on the planet be an interface, even simple things.” I cried.

He smiled, took a sip of his water — “You’re wrong. That’s an Inversion of Control container.” I take a sip of my beer. “Well. What’s an Inversion of Control container?”. He looked at me smugly, “What you just described. That is.”

It was this moment, when I learned the difference between ‘Dependency Injection’ and ‘Inversion of Control’. Dependency Injection is that simple, make your classes take their dependencies in the constructor. If those dependencies happen to be interfaces, you can swap out implementations as needed and your class won’t change. This is sometimes referred to as the ‘Hollywood Principle’ — Don’t call us. We’ll call you.

Inversion of Control, is succeeding control of object creation, and ownership to a framework. It utilizes ‘Dependency Injection’ in order to build up objects in a hierarchical fashion.  In my opinion, these were frameworks created because some developer had nothing better to do with his/her time. Enterprise developers, amirite!?! 😀 But in all seriousness, they really obfuscate ownership and creation. Which is my opinion are fundamental to software design. This is done in the name of modularity, so I understand. However, I’m not a fan. They do have their usage in large applications that need extremely customizable and modular foundations. Although, I’d argue these are few and far between.

Lastly, neither of these are to be confused with ‘Dependency Inversion’. Sometimes, people will confuse ‘Inversion of Control’ and ‘Dependency Injection’ and call it by some ugly step child name of ‘Dependency Inversion’. ‘Inversion of Control’, uses ‘Dependency Inversion’, so does ‘Dependency Injection’. Essentially, ‘Dependency Inversion’ is ensuring that your higher level components, don’t depend on your lower level components. The term though, is generally used to refer to architecture design, at the module level. By making both high and low level modules depend on a shared interface i.e. one caller and one implementer, the direct dependency is now ‘inverted’.

In summary, ‘Dependency Injection’ is the act of taking all class dependencies via the constructor. ‘Inversion of Control’ also called ‘Inversion of Sanity’, is the act of allowing a framework to control all of the important decisions of your program, and you pretending to control it via XML. ‘Dependency Inversion’ is neither of these, but an architectural pattern that helps to decouple modules within a system, by having high and low level components work through interfaces.

Happy Coding!

“Be yourself, because everyone else is already taken.” — Oscar Wilde

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s