Monday, April 6, 2015

Dependency Injection Pattern, Explained to a Novice

'Dependency Injection' (DI) or IOC (Inversion of Control) is a buzz word in high level programming languages like Java, C#, AngularJS e.t.c.

The basic principle in DI is,

You should (1) program to the interfaces and, The (2) caller should provide/inject the required dependencies to the calle.

Beginners having a tough time to understand the concept and implementing the same. So I’m planning to provide a basic introduction in conjunction with a real life example. DI made "design practices" close to real word, like what Object Oriented Programming (OOP) did for High Level Programming languages. As you would know, how the invention of C++, from C, made the programming revolutionary and this has lead to an invention of a plethora of new OOP based programming languages like Java, C#, Visual Basic.net to name a few. As computers have made by humans to assist with their real world needs, there is no wonder, a real world modeling of a programming language gave big advantages.

Ok now lets see a real world example that will better show DI in action.

Rewind the day, where you've allocated to your first Account in your Company. Most probably everything given to you, when you start with your project like your Desk, Computer, Project ID etc. In other words, these dependencies are injected to you, rather than you grab those yourself. So this a

DI in action, where your required dependencies are injected to you rather than you find it for yourself

So consider the advantages of this approach. Suppose your machine need be replaced, then a brand new machine will be again injected to you, without you worrying for it. Also suppose you're reallocated to a new project, you don't have to bother creating a new Project ID and tagging to the new Project by yourself. It will be done to you, by the process in the company (Framework we say).

So if you represent this scenario in a Java/C# class, we have an Account class (The account you belongs to) and Associate class (Represents you). See the below implementation.

As you can see in the 'AllocateNewAssociate(...)' function, 'Machine' and 'Project' are injected to you.

Code Sample1

void AssociateAllocationTest()
{
int yourEmployeeNumber = <your employee number>;
IAccount yourAccount = new Account();
yourAccount.AllocateNewAssociate(yourEmployeeNumber);
}
class Account : IAccount
{
public bool AllocateNewAssociate(int empNumber)
{
//Inject Machine and Project to Associate
IAssociate you = new Associate(empNumber, GetFreeMachine(), GetProjectID());
return you.Allocate();
}
public IMachine GetFreeMachine()
{
//Probably get the new machine from Infrastructure Team?
}
public IProject GetProjectID()
{
//Generate new ProjectID ?
}
}
class Associate : IAssociate
{
public Associate(int empNum, IMachine machine, IProject project)
{
//You got your dependencies
}
public bool Allocate()
{
return true;
}
}
Now consider the opposite of DI, the conventional way of programming. See the below, the same example rewritten. Here you need to grab your Machine and Project by yourself? You instantiate the dependencies as needed. Does this seems plausible? Obviously no. Will you go around and find a system, which is not already been allocated to someone else? What about Project? Are you able to create it by yourself? Most probably you will not even have access to that section in your company’s management portal, unless you are a Project Manager or Lead. 
And the most serious situation. You've concrete references to your dependencies. You're not programming to interfaces, instead you instantiate concrete types (ie. HPMachine, WebProject). If your HP machine, need to be replaced with a IBMMachine? How you can do that, unless you rewrite/recompile your class? Similarly for the WebProject case.

Code Sample2

void AssociateAllocationTest()
{
int yourEmployeeNumber = <your employee number>;
Account yourAccount = new Account();
yourAccount.AllocateNewAssociate(yourEmployeeNumber);
}
class Account
{
public bool AllocateNewAssociate(int empNumber)
{
//Let associate, get the dependencies himself/herself
Associate you = new Associate(empNumber);
return you.Allocate();
}
}
class Associate
{
public Associate(int empNum)
{
//Get your dependencies yourself
HPMachine machine = GetFreeHPMachine();
WebProject NewWebProject = GetNewWebProject();
}
public HPMachine GetFreeHPMachine()
{
//Does this really work out? No.
}
public WebProject GetNewWebProject()
{
//No way!
}
public bool Allocate()
{
return true;
}
}
So you've seen, how the DI model is helping us to inject dependencies, rather than you handle it yourself. This real life example clearly states how DI model is superior over our conventional way of programming (though it is easy to implement). In a long run, you can benefit from DI model, especially while unit testing.

To explain that, let's go to our DI example (Code Sample1) again. For unit testing the 'Allocate' method, you don't have to get a real Machine or Project. Instead get some dummy (Mock) implementation for IMachine or IProject and inject it. See the below example.

Code Sample3

void UnitTestAllocateMethod()
{
int yourEmpNum = <your emp number>;
IMachine machine = new Mock<IMachine>();
IProject project= new Mock<IProject>();
IAssociate you = new Associate(yourEmpNum, machine, project);
Verify you.Allocate();
}
This is how you do with your DI programs using Fake/Mock frameworks for unit testing it.

Now we've covered a real example with DI.

Still 'Code Sample1' does not fully adhere to DI principles. Because, in that example, we still instantiating concrete types in some places. The below statements are examples of those. (As you're using new keyword to instantiate Concrete types)

Code Sample4

IAccount yourAccount = new Account();
IAssociate you = new Associate(...);
As you can see, you've used concrete classes (Account, Associate), although you've stored them in interfaces. In real scenario you wont hard code class instances like this, instead these dependencies too, will be configured at a global level, during the startup of your program. Your program will only aware about interfaces types and request a special component to resolve to Concrete types at runtime. So there exists, a special component that contains the interface <--- to --->concrete class mapping and instantiate the appropriate concrete type , given an interface type.

These special components are called
'DI containers', where you will define the interface to concrete type mapping.
Examples of 'DI Containers' are

C#

1. Microsoft Unity
2. Spring.NET
3. NInject
4. Castle Windsor

Java
1. Spring
These DI containers, will make your life easy, so that you can define your interface to concrete class mappings. Also while instantiating a concrete type (based on a given interface type, it implements), and if it's constructor have arguments that are again depict dependencies, then DI Container will recursively resolves and instantiates each such dependencies, before it returns your object. That's the most coolest part of using a DI container.
Otherwise you've to write your own code to do that and it is called 'Poor man's DI'

So let's make our example more perfect with DI Containers (here we will be using Unity, but you can prefer another based on your choice)
Code Sample5
DIContainer diC;
RegisterTypes()
{
diC.Register<IAccount,Account>();
diC.Register<IAssociate,Associate>();
diC.Register<IMachine,HPMachine>();
diC.Register<IProject,WebProject>();
}
void Test()
{
RegisterTypes();
int yourEmpNum = <your emp number>;
IAccount yourAccount = diC.Resolve<IAccount>();
yourAccount.AllocateNewAssociate(yourEmpNum);
}
class Account : IAccount
{
public bool AllocateNewAssociate(int empNumber)
{
//Inject Machine and Project to Associate
IAssociate you = diC.Resolve<IAssociate>(new OvverideArgs[] {empNumber });
return you.Allocate();
}
}
class Associate : IAssociate
{
public Associate(int empNum, IMachine machine, IProject project)
{
//You got your dependencies
}
public bool Allocate()
{
return true;
}
}
As you can see, there is no more 'new' keywords in your program. The number of 'new' keywords will decide the complexity of your program and if you reduce it to a greater extend, your program is considered to have a good design.
As we've already said, the above code snippet shows, an example of resolving, interface types, that in turn have another dependencies with them. In our example the statement 'IAssociate you = diC.Resolve(...)', instructs the DIContainer, to look for both 'IMachine' and 'IProject' and resolved them first, as they are refereed as arguments in the 'Associate' class constructor. As every interfaces being used, in our context are registered with the container already, it wont raise any error and all resolves silently. Other wise the DI container would have thrown an error, if you've not registered, say 'IMachine' or 'IProject' with the container.
Now you've got a fair introduction to DI. So why wait, explore more on this like 'Cross Cutting Concerns', 'Ambient Context', 'Interception', 'Nested DI Containers', LifeTime of objects etc.

The below Ebooks will get you into depth of DI.


Dependency Injection With Unity - Microsoft

Dependency Injection in .NET - Mark SeeMann

No comments:

Post a Comment