How is the GlobalContainer intended to be used? Are there important don'ts?

723 views
Skip to first unread message

Al eks

unread,
Aug 3, 2014, 9:22:54 AM8/3/14
to spri...@googlegroups.com
Hi there,

I just started playing around with the Spring4D Framework and was wondering how the GlobalContainer is intended to be used or not to be used. I would appreciate some stories of ur experience with the use of GlobalContainer, especially some Don'ts :P.
For example I am interested in where you guys store the container-registration in source code (do you spread the registrations or do you put it in a central place?). I found it pretty comfortable to stick the registration into the initialization part of the class i want to register.


Kind Regards,
Al

Stefan Glienke

unread,
Aug 3, 2014, 10:16:58 AM8/3/14
to spri...@googlegroups.com
Hi Al,

my recommendation as best practice is to not use the GlobalContainer.
I know people are using it in the initialization part of their unit (and there using a global is the only way to do) but here are my point against this:

First question would be: why are you using a DI container in the first place?
Most likely because you are following some principles and patterns (like SOLID) and want to have loosely coupled code.

What happens if you put the container unit in the uses of the units all over the place and call the registration code in the initialization part of these units?
You create dependencies to the container in all these units.

One of the most important rules when using a DI container:
Design your code in a way that lets you do DI without a container (Mark Seemann calls this "poor man's dependency injection")

This leaves us with only one possible way (with exception of external container configuration):
Have one or more units with just registration code. They will most likely have a fairly long uses list of all your interfaces and implementations you are going to register.
The good thing as we learned now: you are practicing the single responsibility principle which does not only apply to methods or classes but also to other software modules 
like units. You have your units with the implementation and you have units to register things in the container. Also you can reuse your implementations in other software that might not 
use a dependency container because they don't have it specified in their uses.

Regards
Stefan

Al eks

unread,
Aug 3, 2014, 10:36:32 AM8/3/14
to spri...@googlegroups.com
Hi Stefan,

thanks for ur reply.

Loose coupling and the reuse of code are good points I agree with, thank you.
I thought of the container like a kind of global factory implementation, so i dont need to write down factory after factory on my own (especially singleton implementations), which i found very usefull. I am quite confused about the fact that you would not recommend the users to use the GlobalContainer (as it is part of the framework)


Kind Regards,
Al

Stefan Glienke

unread,
Aug 3, 2014, 11:01:21 AM8/3/14
to spri...@googlegroups.com
It is. So is the service locator. And they both have been there before I joined the project and have been used by people.
If they weren't I would have removed them by now to make clear that this is not the supposed way of doing things.

Still my opinions and advice remain.
And no matter the place of the registration the result is the same for using the container as a global factory.
But without forcing dependencies on your implementation units if you are using separate units for registration.

If you have a unit like this:

unit SomeService;

interface

implementation

uses
 
Spring.Container,
 
SomeServiceIntf;

type
 
TSomeService =  class(TInterfacedObject, ISomeService)
 
public
    procedure
DoSomething;
 
end;

procedure
TSomeService.DoSomething;
begin
end;

initialization
 
GlobalContainer.RegisterType<ISomeService, TSomeService>;

end.

as has been suggested by people in the past you are facing two problems here:

The class is not accessible directly in any way which makes testing it directly impossible.
I kept it simple for this example but it might require some dependencies on the constructor which would be injected by the container.
So you would need a container only for testing purpose which is also not recommended.
Test code should not require a container at all

Even if the class would have been declared in the interface part this unit would require the Spring.Container unit.
This would force its usage into any project that might use SomeService.
It will cause problems especially when you are using different modules and not one monolithic application 
as every module would need to know that one global instance which you can solve different ways which would not be required at all 
if you would not have put the Spring.Container unit into that uses.

Al eks

unread,
Aug 3, 2014, 11:15:24 AM8/3/14
to spri...@googlegroups.com
Hi Stefan,

I totally agree with you on the place of registration. I might have had figured it out by myself later (especially that you kill the testability). Til now I did not hide the class under implementation section (its still public), but the result would be the same - everyone would need the globalcontainer to use this class.

So thanks again for your explanation. I will continue to use the GlobalContainer in a project for testing purposes to gain some experience on it (but now, with central places for registration).


Kind Regards,
Al

Nick Hodges

unread,
Aug 3, 2014, 2:46:54 PM8/3/14
to spri...@googlegroups.com
My $0.02.

In my book, I argue that the GlobalContainer/Service Locator should be called once, at the very root of your application.  That's the place where all the constructor injection will end up anyway.  In other words, use constructor/method injection everywhere, until thing are "pushed" back to the root of your application, which in Delphi's case is the DPR file, or a method called by the DPR file.

To put things concisely:  Use constructor injection everywhere, and suddenly you'll get to the point there you'll need the container.

Nick


--
You received this message because you are subscribed to the Google Groups "Spring4D" group.
To unsubscribe from this group and stop receiving emails from it, send an email to spring4d+u...@googlegroups.com.
To post to this group, send email to spri...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/spring4d/290f8635-098a-42c6-934e-296124975b23%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Stefan Glienke

unread,
Aug 3, 2014, 3:24:05 PM8/3/14
to spri...@googlegroups.com
In my book, I argue that the GlobalContainer/Service Locator should be called once, at the very root of your application.  That's the place where all the constructor injection will end up anyway.  In other words, use constructor/method injection everywhere, until thing are "pushed" back to the root of your application, which in Delphi's case is the DPR file, or a method called by the DPR file.

To put things concisely:  Use constructor injection everywhere, and suddenly you'll get to the point there you'll need the container.
 
Agreed about the injection thing. However I might add that calling the service locator should be avoided in any case even if you are only calling it once at the composition root.

Consider this main procedure (not a typical VCL application):

var
  container
: TContainer;
  application
: IApplication;
begin
  container
:= TContainer.Create;
 
try
   
RegisterComponents(container);
    application
:= container.Resolve<IApplication>;
    application
.Run;
 
finally
    container
.Free;
 
end;
end.

Using GlobalContainer here instead of instantiating the container on your own is just fine here. It might even make the code shorter because you don't need to clean up this instance.

However I would go with injecting it into the RegisterComponents routine instead of using GlobalContainer there aswell. 
That way you are following the dependency inversion principle and you are not coupling your registration to that one global instance but to that one getting passed to you. 
It might sound unreasonable for now but thing about the possibility to inherit your own container class and 
modifying or extending it at some point and then you want to instantiate that specific container and pass it around. 
If you were using the GlobalContainer that would not work. Again this may sound like a very unlikely case but I have seen these 
assumptions ("oh that will never happen..." guess what happened a week or month or year later) way to often to not point it out. 

This does not fall into YAGNI (because it does not involve any more effort) so respecting the DIP here is fine imho.

Al eks

unread,
Aug 4, 2014, 6:35:40 AM8/4/14
to spri...@googlegroups.com
Thanks for all your effort guys. 

@Nick: didnt know you released a book. I did not read a delphi book for ages, I will definately have a look at it, thanks.

Nick Hodges

unread,
Aug 4, 2014, 10:20:03 AM8/4/14
to spri...@googlegroups.com
You can find out more at


All purchases are humbly appreciated.  ;-)

Nick


--
You received this message because you are subscribed to the Google Groups "Spring4D" group.
To unsubscribe from this group and stop receiving emails from it, send an email to spring4d+u...@googlegroups.com.
To post to this group, send email to spri...@googlegroups.com.

Al eks

unread,
Aug 4, 2014, 10:23:45 AM8/4/14
to spri...@googlegroups.com
Already bought it, even though its not available as eBook :-(

Al

Nick Hodges

unread,
Aug 4, 2014, 10:27:42 AM8/4/14
to spri...@googlegroups.com
Alas - it is -- 


Send my your email, and I'll send you your preferred format:  PDF, MOBI, or ePUB.

NIck


Reply all
Reply to author
Forward
0 new messages