Home > Delphi > Inversion of control, dependency Injection, service oriented programming?

Inversion of control, dependency Injection, service oriented programming?

January 13, 2015 Leave a comment Go to comments

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.

Jumping in

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.

IOC/DI example

IOC/DI example

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.

DI containers

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.

Injection isolation

Injection isolation

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.

Advertisements
  1. abouchez
    January 13, 2015 at 11:11 am

    About DI, SOLID principles, and SOA, take a look at our little mORMot.
    It is the single framework in Delphi (and FPC) containing everything you need to achieve such projects, from ORM, SOA, DI, stubing/mocking. It is Open Source, runs on Linux, and has premium support with SmartMobileStudio clients.
    The documentation is worth reading, for integrating all the concepts you quote in your blog post. See http://synopse.info/files/html/Synopse%20mORMot%20Framework%20SAD%201.18.html
    IMHO this documentation has more material than Nick’s book, especially about SOLID principles and Domain Driven Design.
    Also a set of slides – used in training I did for Delphi developers – on all those subjects: https://drive.google.com/folderview?id=0B0r8u-FwvxWdeVJVZnBhSEpKYkE

  2. sglienke
    January 13, 2015 at 11:41 am

    Best explanation of DI ever made:
    http://stackoverflow.com/a/1638961/587106

  3. January 13, 2015 at 10:20 pm

    The flip side is that error handling becomes more complex and you gain a lot of new error conditions. Start with “dependency not found” and progress through “service unavailable” to “result corrupted in transit”. You have to at least be aware that all those things might happen, even if you choose just to crash your program when one happens to you.

    There are times and places where that approach is worth the pain, and it can often reduce the total pain in the system. But an awful lot of the smaller projects seem to use DI and SOA mostly as a way to turn compile-time errors into runtime ones. Which is bad.

    Too many programmers forget to think about dependency versioning at the start, so you end up with multiple similarly-named dependencies when people need to change or remove features. ICollection, sure, but ICollectionForwardIteratorOnly that isn’t descended from ICollection because it doesn’t implement some of the interface? Or worse, it does but throws ENotImplemented when you call them! Over time it all becomes a mess, and the worst features of DLL hell tend to be reproduced in the shiny new IOC setup. Or you end up with major versions that are not backward compatible, requiring big chunks of code to be re-written every time.

    And SOA… sure, with larger systems it might be worth the significant overhead of defining IService and implementing it on every significant interface you define, but you really need to justify that overhead. I’ve worked with SOA languages like Jade and Forte and there are such a large number of traps for young players that I’m hesitant to suggest anyone go down that path without expert supervision. I’ve given an hour-ish talk purely on “how to pass parameters” in Forte, because we had a team of architects and developers who were consistently doing it wrong (in essence, passing a service by value is ridiculously expensive but when you absolutely must have the same instance of the service at both ends, sometimes that’s what you have to do. It’s the designers fault in that case, but it’s very easy to blame the programmer). And lots of “SOA” architectures have not even got to the point where they can think about questions like that.

    I’d summarise each of those as as: easy to do a trivial example, and easy to do badly once it’s not trivial any more.

    • abouchez
      January 18, 2015 at 2:47 pm

      @MozLe
      Defining interfaces is a very small overhead, and the benefits are huge, in particular with client-server applications: you have a single access point for every kind of clients, which may be Delphi clients, but also AJAX/HTML5 or even Java/C#.
      I agree about the fact that defining proper SOA is not trivial.
      You need to follow some rules, and this is where Domain Driven Design comes in. DDD is a set of principles, based on SOLID and good practice patterns found pragmatically by developers working on huge projects. DDD is great to modelize the business model you are working on, and which will give you your money.
      It is more or less the same for SOA frameworks: an “addition calculator service” is pretty easy to write. But for real work, you would eventually need a catalog, automatic routing and configuration, authentication, authorization, sessions, mocking, caching, threading, server-side implementation instance life time, integration with an ORM, statistics, exception handing, logging…
      Like always, what sounds easy at first opens new world of possibilities… and dead ends…
      But even for small projects, even for a local application, SOA has benefits…

  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s

%d bloggers like this: