Inversion of control, dependency Injection, service oriented programming?
If you google this you and trying to make sense of it is a bit like jumping head first into the rabbit hole. There are so many explanations, so many odd ways of explaining this that you could mistake it as something extremely difficult, attainable only by the elite (that super secret liege of developers that run the world behind closed doors and invent all acronyms just to confuse you).
In short, DI (dependency injection), SO (Service orientation) and IOC (inversion of control) have become hype words. Us old-timers are used to this, namely that in order to justify a complete-rewrite of a product, developers and team leaders must regularly invent buzzwords to sell an idea to shareholders. The buzzwords must make just enough sense to feel familiar, but also be odd enough to be shrouded in mystery. Boys will be boys, and hype is a part of the game.
The terms Dependency Injection (DI) and Inversion of Control (IoC) are generally used interchangeably to describe the same design stuff. Hence some people says IoC Container and some people says DI container but both terms indicate the same thing.
I tend to look at IOC as the technique for writing your code, and dependency injection as the method for managing your implementation.
Just jump in with both feet, it’s fairly simple stuff once you get rid of the hype.
Right, dependency Injection, what is it? First of all, all these topics are techniques. There is no software to buy and no language is better or worse. So if you think this is just for the .net boys or Java, and that in order to deliver this you must somehow throw away your 20 year investment in Delphi – think again.
In fact, one of the finest and easiest explanations to DI in my view was penned by our very own Nick Hodges in his latest book “Coding in Delphi“. I’m not going to steal or re-publish his work here, but simply break it down to “what it is”. Get Nick’s book – it’s a good read and simplifies a lot of topics, way beyond IOC/DI.
A dependency in DI has nothing to do with dependencies in the common term, like a DLL or some library dependency (although it can be that, but not without getting inversion of control first). A dependency in DI terms is rather defined as “what does your class need in order to function?”. Most object hierarchies are hopelessly bound to its members, like TCollectionItem is to TCollection in Delphi. TCollectionItem depends on TCollection in order to compile, and TCollection is useless if you delete TCollectionItem from the unit.
If you analyze a large codebase with these glasses on, you will suddenly realize that your code is full of such invisible “dependencies”. Some have to be there of course, otherwise your application will become to abstract to work, but a lot of the code functionality of an application can be better made by de-coupling class A from class B.
So how do you do this? Well, this is where interfaces come in. And incidentally covers the basic idea behind “inversion of control”.
If all you had to do was to support ICollectionItem and your object could be used by TCollection out of the box – that would be a lot more elegant and maintainable than the present hard-coded model. Also, when interfaces controls access – the implementation can be shielded. Meaning that for the consumer code, meaning the code you write that accesses TCollection in my example here, doesn’t even have to reside on the same machine. As long as you provide an object which supports the correct interface, the meat of the code can be isolated in an RPC (remote procedure call) service or exported to a DLL file or whatever tickles your fancy.
That is an extremely simple explanation of inversion of control. To get the full low-down I urge you to get a good book on the subject, like the one I already mentioned 🙂
So if you think “inversion of control” has anything to do with classical dependencies, you can put that idea to rest. In many ways IOC/DI is the same as a plugin system — but for your whole application. And once you have architected your applications according to these principles – maintenance, isolation of code in your program, a DLL’s or as services is how you deal with your code in general.
Since we now know that Inversion of control is just a fancy way of abstracting your code, and that “dependency injection” has to do with limiting class and entity dependency on each other (or co-dependency), what is the most efficient way to handling variations of code?
Imagine you have a picture program which should read files from various sources. It should read from the file-system, it should read from FTP, it should read images from ZIP files and perhaps even directly from a website.
How would you solve this?
The classical approach is to create a custom-class, a base-class which you then derive local, ftp, zip and http “drivers” from. You would then have a second class, a controller, which would create the correct instance for you.
This means that the controller depends on the baseclass (or better explained: the baseclass is known to the controller) and visa-versa. Since we are talking about file-access over various protocols here, it’s unlikely that the various classes doesn’t know about the controller either – so voila, we have the same old co-dependency occurring. The whole infrastructure is hopelessly dependent on everything in it, you can’t de-couple anything or it breaks apart. You have a rigid, static structure. And the more complex the structure, the more dependencies occur and the harder it is to re-model the architecture.
A DI container (this is where the “injection” part comes in) is a special object into which you register interfaces and the classes that provide them. This means that all the filesystem classes doesn’t need to know about the controller, and the controller doesn’t need to know about the various file systems. Both sides of the coin only needs to know one thing: how to access the container to get the interfaces they need – and the interface declaration. The whole event-sink topology we are used to can be distributed elsewhere – and you can even drop handling events all together if you so chose.
This is incidentally why it’s called inversion of control, because your main program will also export interfaces for whatever child classes you have made, meaning that your child classes will now call into your main program – rather than your main program just creating instances and calling that. So suddenly your program becomes a mesh of non-dependent, self oriented services, breaking somewhat with the linear parent/child model of classical OOP programs.
Service oriented programming
When you reduce dependencies and rely solely on interfaces, as is the point of IOC/DI, your programming changes. Whenever you need to do something you get the interface, use it, then forget it. You begin to look at your program more as an environment of services more than a traditional cluster of units, classes and lose procedures.
Each interface (read: feature set) is more as a service which provides X number of features. Where these features are implemented, be it inside your program, a win32 service running in the background or some REST or RPC service half-way across the globe is insignificant.
Service oriented programming is more or less just that. You write your code as a series of services, accessing them in the same way as you would Amazon or Azure. It is of no concern if the features you use (or need) resides in your process, some other process or remotely. You focus on the features you deliver and utterly de-couple it from location.
When writing code meant to run on high-end servers you naturally want to spread your code over a series of services. Your database work would be isolated as a single service, exporting X number of interfaces for reading, writing, creating and updating data. A second service deals with staging data (preparing data for the database). Perhaps you have a zipcode service which deals exclusively with that as well — and so on.
That in effect is what SOP is about. It’s a lot more complex of course and you should get a book about it, but in essence it deals with software architecture.