Sunday, December 8, 2013

Dependency Injection best practices - lazy initialization

“You gotta know when to be lazy. Done correctly, it's an art form that benefits everyone.” Nicholas Sparks, The Choice

I admit this was taken out of context a bit - but we will see how this applies to dependency injection.

Identifying the problem


When dealing with dependency injection - and when I am saying dependency injection I am referring to the software design pattern - you are facing one problem pretty quickly. The first instance you create (or resolve using the container at the very root of your application) needs everything injected that you will ever need, either directly or something you inject takes that. This will result in tons of wire up code - and this is one reason why using a DI container might be a good idea for an application that you design with this pattern in mind - however a DI container might save you from writing tons of boilerplate code but it still does not solve the problem of instantiating the whole object graph at the start of the application on its own.

There are several ways on how not to do dependency injection - please read the linked article first as it will explain some important things that I felt would be redundant to repeat because they are very well explained (and the few C# code snippets are easy to understand).

...

Things to avoid


You are back? Good.

Let's talk about the service locator and the GlobalContainer - both things you might have seen in several Spring4D examples. If you are writing an application with DI in mind - don't use the service locator.

The service locator might be a nice way of introducing the DI container to an already existing application because you can plug it in at some place deep within the existing code and then kick off the container from there. But don't (ab)use it just to replace constructor calls with something else or to get around actually doing dependency injection. Using the service locator is not DI!

Another important thing to know about the use of the DI container - it does not serve to produce value objects - objects that only hold some values (think of TCustomer or TOrder) but for service objects - objects that actually do some work (like TCustomerValidator or TOrderProcessor). With that in mind you understand the possible problem of "I need to pass some data that is only known later in the application to the container" actually is not a problem. If you need to create customer or order objects then you either register a factory to the container that takes the necessary arguments and constructs an instance or you create that object in your code. No, this is not evil and there is no tight coupling you need to remove - if you follow some guidelines that Misko Hevery explains in one of his articles.

Now what about that GlobalContainer singleton we see in all the Spring4D examples? Actually if you want to make it 100% correct you should create your own TContainer instance - you remember you only need that at the start of your application to register all your types and then resolve the first instance and from there on it will never be seen again throughout your whole application.

If you ever have heard someone telling you that you should put your classes in your implementation part of the unit and then register them in the initialization part of that unit - never ever do that please!
First you are making these classes untestable (because not accessible from outside) without the DI container - always write your code in a way that it is testable without a container. Second you are tightly coupled to the GlobalContainer instance - what if you created your own one - you would be screwed.

Solving the problem


But now let's get back to our initial problem. Having things that might be needed later or even never throughout one run of the application. That is when we need lazy initialization.

Let's see how the example from the other article would look in Delphi:

container.RegisterType<IExampleService, TExampleService>('default').AsDefault;
container.RegisterType<IExampleService, TAnotherExampleService>('another');

container.RegisterInstance<TFunc<string, IExampleService>>(
  function(name: string): IExampleService
  begin
    Result := container.Resolve<IExampleService>(name);
  end);

container.Build;

Assert(container.Resolve<IExampleService> is TExampleService);
Assert(container.Resolve<TFunc<string, IExampleService>>
  .Invoke('another') is TAnotherExampleService);

So if we had another class that would take this factory as an argument on its constructor the container would inject this anonymous method there - keep in mind that we used RegisterInstance which returns the same anonymous method every time. In this example it is completely valid because the anonymous method has no state but pay attention when you use variable capturing.

You can imagine that this will be much code to write if you have many service types and you want to resolve many of them lazily. But just like other DI containers the Spring4D container has built-in support for that. Take a look at this code:

type
  THomeController = class
  private
    fService: IExampleService;
    fServiceFactory: TFunc<IExampleService>;
    function GetService: IExampleService;
  public
    constructor Create(const serviceFactory: TFunc<IExampleService>);
    property Service: IExampleService read GetService;
  end;

constructor THomeController.Create(const serviceFactory: TFunc<IExampleService>);
begin
  inherited Create;
  fServiceFactory := serviceFactory;
end;

function THomeController.GetService: IExampleService;
begin
  if not Assigned(fService) then
    fService := fServiceFactory();
  Result := fService;
end;

container.RegisterType<IExampleService, TExampleService>('default').AsDefault;
container.RegisterType<IExampleService, TAnotherExampleService>('another');
container.RegisterType<THomeController>;
container.Build;

Assert(container.Resolve<THomeController>.Service is TExampleService);

As you can see we did not register the factory method anywhere. The container took care of that and passed it to the constructor.

We now have the lazy initialization logic inside the getter because the container did just give us a factory method. Every time we would call it the container would run its logic and create a new service (unless we registered it as singleton of course). But Spring4D contains the lazy type - so we can reduce this code a bit and make use of that:

type
  THomeController = class
  private
    fService: Lazy<IExampleService>;
    function GetService: IExampleService;
  public
    constructor Create(const service: Lazy<IExampleService>);
    property Service: IExampleService read GetService;
  end;

constructor THomeController.Create(const service: Lazy<IExampleService>);
begin
  inherited Create;
  fservice := service;
end;

function THomeController.GetService: IExampleService;
begin
  Result := fService;
end;

The rest of the code is pretty much the same. The Spring4D container has built-in support to TFunc<T>, Lazy<T> and ILazy<T> where T needs to be a registered service type that can be resolved without a name - either by only having one implementor or having specified AsDefault on any.

So this was the first article on dependency injection best practices - more will follow. As always your feedback is very much appreciated.

By the way - in case you missed this - Spring4D is now hosted on Bitbucket.

Sunday, December 1, 2013

Future plans for Spring4D and DSharp

Some of you may have read the public letter about Spring4D project two weeks ago. So this is the promised post about the roadmap (well more of some plans that are not set in stone yet but in our minds) for the future.

First of all I am really happy when I hear that people are using Spring4D in their projects and that it is not just an experimental thing to bring some Java or .Net flavor into the Delphi world. And as always software only becomes better when it gets used. In the past there were many features added because you as the users needed them.

However communication and sharing experiences between you as users and us as the development team is still not as good as I wished. In the past there were many channels used to share experiences or ask for help. Getting them focused more in one place will help to share and build knowledge - so for everyone that is not following us please join us on groups.google.com/forum/#!forum/spring4d.

The project is now hosted on Bitbucket in a Git repository which will make the workflow easier than it was with Subversion. We will follow the Gitflow Workflow which might look confusing first but is really easy. For you as user it means, clone from the master if you want the stable and thoroughly tested source. For stuff currently in development either clone the develop branch or one of the possible feature branches.

Some changes have been made to the collection types recently which are important things I will talk about in a few. These are mostly non breaking changes but there were some small API changes which are easy to apply after you got the latest version.

The DI container got some really nice features in the past months which will be subject of an extra blog post that will follow soon.

Ok, but what about the future?

One thing that is often criticized about the project is the poor documentation - apart from some blog posts here and there - this is something we want to change.We will improve the source documentation (using DocumentInsight actually makes this fun!) and the general documentation about the different features of the framework as well as best practices for dependency injection.

Another goal will be to improve unit tests as some parts are not as well tested as they should be. This will also help adding new features in the future and/or refactor existing ones.

Some other projects will work more closely with Spring4D - one being about ORM - more about that when we have more details.

We want to make Spring4D a de facto standard for Delphi developers.

There are also some interesting things about Spring4D in Nicks upcoming book - so you might to take a look.


Another project that closely works with Spring4D is DSharp. Currently there are some redundant parts in both frameworks and if you are using both it sometimes is hard to decide which one to use. Also this might cause incompatibilities. We are working on reducing and finally removing these.

DSharp had a very simple but powerful MVVM implementation for some while. This was very basic and more of a proof of concept than something you can use for bigger applications but I am happy to tell you that we are bringing you a MVVM solution for Delphi that is based on Caliburn Micro. Some people might have seen some previews by Jeroen Pluimers on the ITDevCon or the BE Delphi this year. Currently we are aiming for a beta in next spring and more details on that project will follow.


Are you interested in helping in one of the projects, have questions or just want to share your experience?Please let us know!