Amazon.com Widgets Getting Giddy with Dependency Injection and Delphi Spring #8 – Miscellanea

Getting Giddy with Dependency Injection and Delphi Spring #8 – Miscellanea

By Nick at November 05, 2011 14:03
Filed Under: Delphi, Software Development

So far I’ve covered a much of the basics of Dependency Injection.  There’s a lot more to it, and plenty more to discuss, but for this article, I want to stop and discuss a few items that I have kind of glossed over.  So without further ado, here they are in my beloved bullet form:

  • I have been, as you’ve likely noticed, encouraging you to use interfaces when coding, and registering classes as implementing those interfaces with the framework.  What I think I failed to mention explicitly is that all interfaces registered with the Spring Framework have to have a GUID associated with them.  You can add a GUID any time you want into your code by pressing CTRL+SHIFT+G.  If you try to use an interface that doesn’t have a GUID, you’ll get this error:  “Project <projectname>.exe raised exception class ERegistrationException with message 'Non-Guid Interface Services are not supported.
  • If you’ve looked closely at the code in the demos, you might have noticed that before you can do anything with the Spring Container, you need to call GlobalContainer.Build;  This method needs to be called before you can get anything out of the ServiceLocator.  The Build method is the code that gathers up all the registered classes and either creates them or enable them to be created on demand, depending on the lifetime type that you have selected.  If you get the error 'LifetimeTypeManager was expected.' when you run your app, it likely means that you have faced to call Build on your container.  And in fact, the Build method is really the main purpose of your DI Container.  You should call Build once, and at the root of your application.  For Delphi developers, this means that it probably ought to be called as one of the very first things in the DPR file. This also means that you need to register your classes as early as possible as well.
  • You don’t have to use the Global Container and the Service Locator provided by the framework.  You are more than welcome to create your own and expose the functionality as you want.  What we have done here at Gateway Ticketing is to declare an interface that is a complete abstraction of the notion of a DI Container, and then implement the interface ourselves using a TContainer descendant from the Delphi Spring Framework.  That way, if the framework changes (and it has since we started) or if we even decide to use a different container, our code is completely decoupled from any particular implementation.  Just another great example of “Code against abstractions, not implementations.” Smile
  • I feel compelled to point out that the whole concept of a Service Locator is considered an “anti-pattern” by some. I haven’t come to a firm conclusion on this issue myself.  Yes, a Service Locator is almost always a Singleton, but I personally don’t view read-only singletons to be bad as do some.  (A read-write singleton is really a global variable, and I think we can all agree that global variables are the Spawn of Satan.) However, there appears to be some dispute as to whether the use of a container is indeed a Service Locator. Also, if all of your dependencies are defined before execution is available to the user, then is a Container really a variable at all?  It remains a matter of debate. Ultimately, I guess I view a Service Locator as so valuable and useful so as to out-weigh any of the drawbacks they might have. 
  • There is a weakness here -- and which gets to the previous point – in that things are actually so decoupled and late-binding is so explicit that it is indeed possible to get a successful build and not know that you forgot to register a needed implementing class until runtime.  And, in a complex system, it might be a long time before anyone notices that the implementing class for a seldom used interface is missing.  If you follow the pattern that I have shown of registering an implementation in the initialization section of a unit, then you must use that unit somewhere in your app to actually have the registration take place. And as mentioned, if you forget to add it, and don’t actually include that unit in your app, the compiler won’t tell you and you will only find out at runtime.  This is a weakness and you need to be very careful to ensure that you don’t fall into this trap.  Strategies might include a single unit for doing all of your registration, or some type of static analysis that ensures that every call to GetService has a corresponding RegisterService call (or whatever your methods are called).  Something to be aware of.

Those are just a few things that you might want to consider as you integrate Dependency Injection into your coding techniques. I’ve said it before, and I’ll say it again:  If you aren’t doing Dependency Injection, you're doing it wrong. 

Comments (3) -

11/6/2011 7:20:55 PM #

David S

Shades of grey ...

If I'm not mistaken, the Service Locator is doing the same thing as the LoadDLL method does.

Only in the case of LoadDLL, there's a separate process used to "register" the DLL with the environment.

Indeed, you could hide DLLs inside of the Service Locator, which would give you environmental independence.

You've also got something similar in terms of the Windows Registry, which could also be hidden inside of the Service Locator.

DLL and Registry management are platform-specific services provided courtesy of Windows.

You could say they're "singletons", and while DLLs are read-only, the Registry looks like one huge global variable.

However, you don't need to bother instantiating either one of them.  So the argument is moot.

Anyway, I'm taking this all in while studying the new landscape being offered to us for cross-platform development, where the "theory" of having one UI and one back-end is nice, but the "practice" is that each platform really requires a different combination of pieces that all reflect the same underlying functions, just a bit differently.

For example, Windows and OS X can use the same FM-based UI, but will require three different back-ends (W32, W64, and OSX).

iOS can use FM as well for the GUIs, and the iPad may be able to use the same UI as Windows and OS X, but iPhone/iPod need something different.  If you're careful, the iOS back-ends can all be the same.

On the surface, this looks like it could be quite a configuration nightmare.  You'll either end up with a bunch of $IFDEF code throughout units, or separate units with $IFDEFs partitioning them in a configuration or project file.

I'm not sure this is any better than what Spring uses with its XML file for describing what's actually contained in the Storage Locator's "warehouse".

Aside from this configuration issue (which only presents itself when the app starts up), the overall DI paradigm looks as if it could effectively minimize the code differences between the different platforms with very little use of $IFDEFs in the main code.

Any thoughts on this?

David S United States |

11/8/2011 7:22:27 AM #

Dean Hill

I don't buy the anti-pattern argument. Let me explain my comment in a little more detail.

It might make development a little bit more difficult as explained in the blog. The problem is that his blog interprets the service locater as an alternate method of construction. It's not that. It goes much deeper than that. It goes to the actual design and architecture of the software. You could easily replace the service locater with an extension method or static methods on a class and have it read a configuration every time from a file but that doesn't make sense. That's just being pedantic for the sake of it and creating slower code.

I am a big advocate of building flexible software and flexible software is about building something that can and probably will change in the future. There should be no reason for the developer to know how to construct object X. If they want to work with object X then they may as well throw the interface out of the window and create the object directly. They should code to an interface. The moment you let a developer get involved with pieces of code that fall outside of their domain then you are asking for trouble. I can't even count how many times I have seen a developer dive into someone else's code and "fix" something that they thought was broken just to end up causing havoc.

There is also another big plus to working this way. It's much easier for a developer to code against a "test" object then it is to code against the real macoy. For example, It is far easier to code a module when working with a dummy security object than it is to prepare a whole security database to facilitate testing. Letting the developer construct the object could easily end up the with a "test" object being left in the real software which could have far more serious consequences as this error may not be easily identified. I would rather get a KeyNotFound exception than have the software work but allow the wrong people to access the system because of some test code.

Lastly (others may prefer a different approach) I prefer the external XML configuration approach. This is something that Spring.NET does. It does have security implications but those can easily be overcome. Why, because this creates completely flexible and pluggable solutions. It allows you to create application frameworks rather than applications. While this may be overkill for a lot of developers who just want to push out a quick DB app for client x, it even has benefits for them. They could probably cut their development to a quarter by using shared security, configuration, etc systems. Think of a configuration system retrieves configuration locally or from a server in a transparent manor with just a single change of an XML setting. You can have configuration providers that work with different back ends, XML, SQL Server, etc. All of this would be totally transparent to the user AND the developer. They could just call a "GetSetting" method on some interface and know that the configuration of the system would handle the rest for them.

This does put more emphasis on your deployment and release process but, IMHO, it's well worth it.

Dean Hill South Africa |

11/8/2011 1:22:50 PM #

Nick Hodges

Great comment, Dean -- I couldn't agree more.  To me it comes down to the idea that the benefits gained far, far outweigh and "purity" lost by having a singleton Service Locator.

Nick Hodges United States |

Comments are closed

A Little About Me

Hey, I'm Nick.  I'm interested in Software Development, Leadership, and Basketball.  I'm a big fan of Delphi, but love all cool programming languages.

A Pithy Quote for You

"Never interrupt your enemy when he is making a mistake."    –  Napoleon Bonaparte

Little Buttons and Stuff

Nick Hodges

Create Your Badge
View Nick Hodges's profile on LinkedIn
profile for Nick Hodges on Stack Exchange, a network of free, community-driven Q&A sites
Powered by DiscountASP.net
Join Dropbox

General Disclaimer

The views I express here are entirely my own and not necessarily those of any other rational person or organization.  However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right.  Most of the time. Except when I'm not, in which case, you shouldn't agree with me.

Book Stuff

Earn Free Stuff

Search & Win