Friday, December 25, 2009

Introducing Hiro.Functors, and Making Hiro a Dynamic Container

One of the more salient criticisms that I've often heard about Hiro is the fact that for the most part, the containers that Hiro creates are static and cannot be modified once they have already been compiled and instantiated. There might even be cases where you might have to have a Hiro-compiled container return an existing service instance, and that service instance (in turn) might not be available when the container is first compiled. For example, let's assume that you have an existing service instance of class type Foo that implements the IFoo interface:

public interface IFoo
{
// ...
}

public class Foo : IFoo
{
// ...
}

Let's also assume that Foo is some sort of long running service that must be returned every time you ask for an IFoo instance from a Hiro-compiled container. In previous revisions of Hiro, you probably could have registered the IFoo service as a singleton using the following code:

var map = new DependencyMap();
map.AddSingletonService();

var container = map.CreateContainer();

// ..Use the container code here

The problem with the previous code above is that you can't use it if the Foo instance has already created before the container instance has been compiled. Since the hypothetical Foo service is a long-running service that already exists before each container is compiled, there doesn't seem to be any way to make a DependencyMap return an existing object instance--that is, until now. This is where Hiro.Functors comes to the rescue:

// For the sake of simplicity, let's assume that Foo has already been instantiated..
var existingFooInstance = new Foo();

// Define the factory functor
Func<IMicroContainer, object> makeFoo =>existingFooInstance;

var map = new DependencyMap();
map.AddService(typeof(IFoo), makeFoo);
var container = map.CreateContainer();

// Get the foo service; The makeFoo functor will be called here
var actualFoo = container.GetInstance();

// This will evaluate to true
Assert.AreSame(existingFooInstance, actualFoo);

As you can see from the code above, the Hiro.Functors library extends Hiro so that you can use C#'s native lambda syntax to add your own custom factory methods to any Hiro-compiled container. A single call to the additional DependencyMap.AddService(yourServiceType, yourFunctor) is all you need to convert Hiro from a static container to a dynamic container without sacrificing speed for flexibility. It's just that simple.

I prefer to call Hiro the "blue collar" IOC container framework, and Hiro.Functors is just another step in helping you (the end-user developer) get the job done with as little drama as possible in the fewest amount of steps possible. While there's definitely nothing revolutionary about this tiny release, I think there's plenty to be said about having an IOC container that gets in and does the job using the flattest learning curve possible, and that's exactly what Hiro offers.

While I can't promise my readers that I'll change the world with revolutionary tools, what I will promise them is that my tools will be the simplest tools that they can possibly use so that they'll be able to meet their deadlines on time and make it home early for holidays like today. Hiro is one such tool, and if you ever run into any problems with it, I'm only a patch and an email away. Happy holidays, everyone!


(Note: You can get Hiro.Functors here)

Thursday, September 10, 2009

Creating Per-Session Services with Hiro

Over the past week, I've had a few people ask me how they can use Hiro to create services that are instantiated once per web session. Ideally, Hiro should be able to do something like this:



// Instantiate the IFoo service
var context = HttpContext.Current;

if (context.Session["SomeFooKey"] == null)
context.Session["SomeFookey"] = container.GetInstance<IFoo>();

return (IFoo)context.Session["SomeFooKey"];



The code itself is pretty simple, but the problem is that this can get quite cumbersome if you have more than a few services that need to be stored in the Session object. There has to be some way to do this with Hiro using a single method call, and indeed, Hiro makes creating per-session services just as equally effortless:


// Register the Foo service into the DependencyMap
var map = new DependencyMap();
map.AddPerSessionService(typeof(IFoo), typeof(Foo));

// Compile the container
var container = map.CreateContainer();

var foo = container.GetInstance<IFoo>();

// ...use the IFoo per-session service here (just like any other service)


As you can see from the example above, Hiro abstracted away the details of having to deal with caching your services into a Session object. In fact, all you have to do to add per-session services to your dependency maps is to use the AddPerSessionService extension method, compile your container and use it like any other Hiro-compiled container. It's just that simple.

NOTE: You can download the Hiro.Web extensions (including the per-session service support extension method) here.

Tuesday, July 28, 2009

Introducing Hiro, the World's Fastest IOC Container, Part III: The Container Itself

Introduction


In this final installment of the Hiro series, I'll show you just how ridiculously simple it is to use Hiro in your own applications without sacrificing speed for simplicity. I'll also show you how you can use Hiro's registration conventions so that you will never have to worry about managing any external configuration files or declare any external attributes on your types just so you can get your types registered into a service container.

Simply Fast, and Simply Simple


As I mentioned in my previous posts, Hiro lacks many of the "fat" features that you would normally associate with other IOC containers (including LinFu). At first, that might seem like a disadvantage for potential Hiro users, but it also implies that you won't have to waste any time trying to understand any IOC container features that you probably will never use in most of your applications. Instead, Hiro focuses on doing three things:
  1. Determine the list of available services from any given assembly.
  2. Registering those services into a container
  3. Ensuring that the container can create the services that you registered.
Unlike other IOC containers, Hiro doesn't need you to use fluent interfaces or attributes to register your types into a container. You don't even need lambda functions or an external XML configuration file to get your services up and running with Hiro. Instead, Hiro uses Convention over Configuration semantics that let you register your services with only a few lines of code. Here's an example:


// Use the loader to scan the target assembly
// for services
var loader = new DependencyMapLoader();

// The loader will handle all the details of loading
// the services into the container for you
DependencyMap map = loader.LoadFromBaseDirectory("SampleDomain.dll");
var container = map.CreateContainer();

// (Do something useful with the container here)
var greeter = container.GetInstance<IGreeter>();

// ...

"Convention over...what?"


At first glance, it's hard to believe that Hiro can load all the services from a given assembly (or a set of assemblies) using only the code that was given in the previous example. After all, any given service can have nearly an infinite amount of constructor and property injection dependencies, and given the sheer complexity of this task, there must be a set of rules that Hiro follows that somehow makes the registration happen "automagically". At the same time, there might be some end-user developers out there that might want to have strict control over the actual services that will be registered into the compiled container. In other words, how does Hiro know exactly what to register and still be able let users control what gets registered into a compiled container?

A Few Rules Go A Long Way


Now the reason why Hiro can do so much in so few lines of code is because that it implements a few conventions that typical IOC container users would follow when registering their own types. As long as users follow those conventions, they will never have to worry about manually registering any of their service types with Hiro. For example, let's assume that you had this particular service type declared in a single assembly:

  
public interface IGreeter
{
void Greet(string name);
}


Let's also assume that you have three concrete classes that implement the same IGreeter interface:
  
public class GermanGreeter : IGreeter
{
public void Greet(string name)
{
Console.WriteLine("German: Hallo, {0}!!");
}
}

public class FrenchGreeter : IGreeter
{
public void Greet(string name)
{
Console.WriteLine("French: Bonjour, {0}!", name);
}
}

public class Greeter : IGreeter
{
public void Greet(string name)
{
Console.WriteLine("English: Hello, {0}!", name);
}
}



"Just give me the default service, please!"


Based on the examples above, it probably didn't take you very long to infer that the Greeter class is the default implementation for the IGreeter interface. Furthermore, it's probably safe to assume that a default implementation exists if you have an interface named IYourService and if you already have a concrete class named YourService that implements that particular service type. Hiro follows the same convention, so calling container.GetInstance on an IGreeter type will yield a Greeter instance:

  

// Load the sample assembly
var loader = new DependencyMapLoader();
DependencyMap map = loader.LoadFromBaseDirectory("SampleDomain.dll");
var container = map.CreateContainer();

// Get the default implementation
var greeter = container.GetInstance<IGreeter>();

// Determine the actual type that implements the IGreeter interface
var greeterType = greeter.GetType();

// This expression will return true
Console.WriteLine(greeterType == typeof(Greeter));


As you can see, the example above is fairly self-explanatory. The DependencyMapLoader class will automatically determine that the Greeter type is the default implementation for the IGreeter interface and register it into the DependencyMap. Of course, this approach assumes that you have a class with a type name that matches the service type name; however, there might be cases where you have multiple classes that implement the same interface but don't follow this naming convention. For example, if I have the FrenchGreeter and a GermanGreeter class but don't have a default Greeter class, how does Hiro determine which implementation should be used as the default implementation type?


When All Else Fails, Use the Alphabet


The answer is that by default, Hiro will pick the first implementation type from a list of service implementations that have been sorted alphabetically by type name. In this case, Hiro will choose the FrenchGreeter as the default IGreeter implementation since the FrenchGreeter class name alphabetically appears before the GermanGreeter class name:


// ...

// Get the default implementation
var greeter = container.GetInstance<IGreeter>();

// Determine the actual type that implements the IGreeter interface
var greeterType = greeter.GetType();

// This expression will return true since
// the FrenchGreeter type appears before the GermanGreeter type
Console.WriteLine(greeterType == typeof(FrenchGreeter));


While this approach might be useful for determining (and thus accessing) a default service implementation, there has to be a way to access the other concrete IGreeter implementations that reside in the compiled container. As it turns out, Hiro makes this process just as equally effortless:


// Get the French and German greeters
var frenchGreeter = container.GetInstance<IGreeter>("FrenchGreeter");
var germanGreeter = container.GetInstance<IGreeter>("GermanGreeter");


By default, Hiro registers each service implementation using the class name of each concrete service type. In order to access a particular service implementation, all you need to do is pass the name of the implementing type in the container.GetInstance<T> call, and the container will instantiate the corresponding type for you.

Using Constructor Injection and Property Injection


Now that we have an idea of how Hiro registers service types into a container, the next thing that you might be wondering about is exactly how Hiro injects dependencies into constructors and properties. For example, if I have a class named GreeterHost that takes one IGreeter dependency in its constructor, how do I tell Hiro to use that constructor instead of the default constructor? Let's take a look at the GreeterHost class:


public class GreeterHost
{
public GreeterHost ()
{
}
public GreeterHost(IGreeter greeter)
{
// Do something useful here
}

// ...
}


Let's also assume that I manually registered the GreeterHost class with the DependencyMap using the DependencyMap.AddService method. Here's how you get Hiro to perform constructor injection:



// Manually add the GreeterHost to the dependency map
var map = new DependencyMap();
map.AddService<GreeterHost, GreeterHost>();

// Manually add an IGreeter service so that Hiro uses the constructor
// with the IGreeter parameter
map.AddService<IGreeter, Greeter>();

// Compile the container
var container = map.CreateContainer();

// Create the GreeterHost. Hiro will automatically
// inject the IGreeter implementation into the constructor
var greeterHost = container.GetInstance<GreeterHost>();


As you can see from the example above, Hiro automatically used the contents of the dependency map to determine which constructor should be used for instantiating the GreeterHost type. The only thing that I needed to do to perform constructor injection was to make sure that the IGreeter service type was available in the dependency map once the container was compiled. The compiled container, in turn, used the IGreeter dependency to call the correct GreeterHost constructor.

Singletons Galore


NOTE: If you prefer to have your Greeter type registered as a singleton in the dependency map, however, here's how you do it:


// Manually add an IGreeter service so that Hiro uses the constructor
// with the IGreeter parameter
map.AddSingletonService<IGreeter, Greeter>();


Constructor, Inject Thyself


The best part about the constructor injection example with Hiro is the fact that it handles all the gory details of performing constructor injection for you in the most minimal lines of code possible. In this case, the only convention that you have to follow is to make sure that the dependency map contains all the necessary services for Hiro to call the appropriate constructor. What makes this even more interesting is that Hiro can perform automatic constructor injection with constructors that have any arbitrary number of constructor arguments. In other words, if the DependencyMap instance has the constructor dependency, then Hiro can handle the injection.


Property, Inject Thyself Too


For the most part, Hiro's property injection follows some of the same conventions as constructor injection. Much like constructor injection, the only thing you need to do to use property injection with Hiro is to make sure that services required by the target property are already registered with the dependency map once the container is compiled. For example, let's assume that GreeterHost class as an IGreeterProperty named CurrentGreeter:


public class GreeterHost
{
public IGreeter CurrentGreeter
{
get;set;
}
}


Here's how you set up Hiro's dependency map to perform property injection:


// Manually add the GreeterHost to the dependency map
var map = new DependencyMap();
map.AddService<GreeterHost, GreeterHost>();

// Manually add an IGreeter service so that Hiro uses the constructor
// with the IGreeter parameter
map.AddService<IGreeter, Greeter>();


The first thing that you might notice is that the setup code for property injection and constructor injection are both identical to each other. In fact, you could even say that I just "copy & pasted" the example from previous examples in this article. Indeed, that was intentional, and the point here is that are only two simple things that you need to do to make Hiro automatically perform property injection on your types:

  1. Ensure that the service types that your properties require are registered with the dependency map.
  2. Ensure that the properties that will be injected are not read-only properties.
In other words, Hiro's property injection conventions follow one of the most basic dependency injection conventions of all:

If you don't want Hiro to inject dependencies into your target property, then make sure the property is a read-only property or the property type doesn't exist in the container as a service type.


All you need to do to disable property injection for the GreeterHost is to prevent a default IGreeter service from ever being registered into the dependency map. You can do this by either constructing the dependency map by hand, or you can attach a service filter to the DependencyMapLoader so that it avoids loading a default IGreeter service into the resulting dependency map:


var loader = new DependencyMapLoader();

// Make sure that no default service is loaded for the IGreeter interface
loader.ServiceFilter = service=>service.ServiceType != typeof(IGreeter) && string.IsNullOrEmpty(service.ServiceName);


As you can see from the example above, all you need to do to prevent the DependencyMapLoader from registering services is use a simple lambda function, and it can't get any simpler than that.

Next, here's the call that will construct the GreeterHost and perform the property injection operation if you still have the required dependency inside the container:


// This is the only method call you need
// to do property injection
var greeterHost = container.GetInstance<GreeterHost>();

// ...


Fortunately for the end-user developer, the GetInstance method that performs the constructor injection is also the same method that will perform all property injection operations. Hiro uses these simple conventions to make developers' lives easier, and if it can help at least one person out there write better code, then I consider this project to be a success.

--

You can download Hiro from here.
You can also click here to download the Hiro example solution.

Friday, July 17, 2009

NDepend Review

The Quick & Dirty

There have been a lot of good reviews written for NDepend, so for the sake of efficiency, I'll get straight to the point: NDepend is an amazing tool. It lets you graphically inspect your assemblies and it lets you pinpoint the spots in your code base that need refactoring.

So would I recommend buying NDepend Professional? Yes.

Is there something that I didn't like about NDepend that I think the users should know about? Yes, and that's exactly what I'll talk about.

"So what's not to like about NDepend?"

My only problem with NDepend is that its CQL query engine can only be accessed from the Visual NDepend application. NDepend does let you embed CQL attributes in your applications, but the problem is that I shouldn't have to force each one of my applications to have a dependency on NDepend just because I want to have some code metrics calculations in my build process. Of course, there are a few ways that I can work around that limitation, but the point is that I shouldn't have to make a workaround for something that should have been there in the first place.

In other words, what NDepend sorely needs right now is a publicly-accessible CQL engine API. If NDepend is truly a tool built by developers for developers, then it should have an API that other developers can use to analyze their applications. It's not enough to throw them a rudimentary command-line tool that spits out code metrics in XML--that pretty much leaves developers to write code against the "shadow" of the CQL API rather than write against the CQL API itself, and for me, that just doesn't quite cut it.

Don't get me wrong--the Visual NDepend winforms application is an awesome app--but I'd rather be able to filter through all that information using a single API call rather than have to manually sift through several windows just to find the information I need.

Now the reason why I'm harping so much about the lack of a public CQL API is that my company uses NDepend Professional in its command line builds to ensure that our builds fail when the Cyclomatic Complexity score exceeds 2.5 in any of our projects. The problem is that we want our code quality inspections to be completely automated, and we can't do that unless we have access to the CQL API and can generate CQL queries at runtime. The maximum Cyclomatic Complexity score might prevent our developers from writing complicated code, but there's far more to code inspections than just looking at a single score. What we need is a way to look deeper into the quality of our code base using the hypothetical CQL API with the same ease that Visual NDepend users can browse through their code.

So in the end, I still recommend NDepend Pro as definite buy, but it still lacks a few key features that would make me give Patrick Smacchia's tool the gushing review that other bloggers have given it in their respective reviews. Overall, it's definitely a great tool, but it's not without a few shortcomings.

[Public Disclosure: Thanks to Patrick Smacchia for providing me with a free NDepend Pro license for this review.]

Thursday, April 16, 2009

Introducing Hiro, the World's Fastest IOC Container, Part II: The Little Feature Set That Could

The Art of Lean

Now that everyone knows just how fast Hiro can be, the next question you might be asking yourself is, "What features will it support?"

The simplest answer that I can give is that Hiro is that it will implement as little features as possible--in fact, Hiro will implement so little features that it might turn away your traditional "dynamic" IOC user. Here's the features that Hiro will implement:

-Named/Anonymous Static Component Registration. This means that you'll be able to register your services using a service name, service type, and the implementing type.

-Convention Over Configuration for Registration and Injection.. In addition to its support for programmatic registration, Hiro will be able to scan your assemblies and automatically infer:
  1. The list of available services
  2. The list of concrete types that implement those services
  3. The list of properties that can be injected
  4. The constructors that will be used for constructor injection
  5. The services that will be injected into each parameter during a constructor injection call.
The most interesting part about this is the amount of work that will take to do this sort of registration. Take a look at this example:


var loader = new DependencyMapLoader();
var map = loader.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "Yourlibrary.dll");

IContainerCompiler compiler = new ContainerCompiler();
var microContainer = compiler.Compile(map);

// Do something with the container here

Believe it or not, this is the only code that you need to use to configure the dependencies for any assembly of any given size. What makes this even more interesting is the fact that all of this is done statically at (container) compile time, not runtime. This means that unlike the current generation of IOC containers, Hiro will not waste any time trying to rediscover your configuration, and based on the benchmark results from my previous post, the performance numbers are nothing short of being dramatically one-sided.

-Transient/Singleton instances. Aside from performance, however, Hiro has to be able to create both Transient (that is, plain old object instances created with the New operator) and Singleton instances.

-Property/Constructor Injection. Hiro will implement both property and constructor injection by default. What makes this even more interesting is that like everything else with Hiro, all property and constructor injection calls will all be precompiled into IL, meaning that there will be no performance issues when using Hiro.

-Stateless. Each Hiro-compiled container instance will not have any private local data (or even shared data) that will distinguish it from another compiled container of the same type. This means that you can scale Hiro's compiled containers across multiple cores AND multiple threads without using a single semaphore, mutex, or lock statement (in C#).

"But wait, your container isn't a REAL container until you implement feature X!"

Some would argue that Hiro would have to implement a minimum "baseline" feature set in order to be considered a "commercial" quality IOC container. However, my counterargument there is that it's this same "fat feature" mindset that got these IOC containers (including LinFu) into this speed problem in the first place. Secondly, if you're experienced enough about IOC to understand the significance of what Hiro does, then it's safe to assume that you're a user that falls into at least one of the following categories:

  1. You've probably written at least one IOC container framework, or
  2. You already are comfortable with an existing IOC container framework (such as Castle, Ninject, AutoFac, Unity, StructureMap, LinFu, etc) and you know enough to customize it to your needs.


Assuming that you're an IOC container author, it would be pointless for me to implement something in Hiro that you've probably rolled into your own framework, and given that you're skilled enough to write your own framework, it would be practically trivial for you to plug Hiro into your own framework and reap the performance benefits, and there's clearly no reason to reinvent the wheel here if you somehow did a better job than I did in implementing "feature X".

Now, if you think you're a user that falls into the second category, there's a good chance that you've pretty much decided to stick to the favorite framework of your choice, and like the other IOC container authors, there's really nothing that I can do for you unless you decide to plug in Hiro into your favorite container.

So between these two types of users, who do you think Hiro is written for?

Here's my answer: Neither one of them. Hiro is written for the average developer who wants to get started with an IOC container and doesn't have time to "geek out" over the latest and greatest features of an IOC container framework. Given that there are probably far better IOC container developers than myself, I've pretty much decided to skip the "my container is better than your container" religious wars and focus on what really matters: the end users.

The Pareto Pleasure Principle

Hiro doesn't need to implement 80% of the expected features of an IOC container in order to be useful--instead, it only has to implement the other 20% of the overall features that (in my opinion) people will actually use. In the end, if I can help those people get their jobs done in the simplest possible way without forcing them to wade through the "awesomeness" of my framework, then I would call Hiro a success, and at the end of the day, that's really all that matters.

Wednesday, April 8, 2009

Introducing Hiro, the World's Fastest IOC Container, Part I: Design Diary

Introduction

Have you ever had one of those moments where someone told you that your work sucked, and it inspired you to create something better? About a month ago,Alex Simkin sent me a message on the CodeProject forums for one of my articles saying that LinFu ranked second to last in performance among all the other containers, and that he was willing to show me the benchmark code that produced those numbers.

Eating the Humble Pie

Unfortunately, Alex was correct. Despite all of its features, LinFu landed a spot near the bottom of the pack, and needless to say, there had to be a better way to design a container so that it wouldn't have these bottlenecks.

"But...but...my container is dynamic and it's flexible!"

As an IOC container author myself, I've probably given that same excuse a dozen times over whenever someone complained that my framework was too slow. I never realized that the flexibility that I so touted in all my IOC articles was the same cause for all my performance headaches. Indeed, there had to be some way to improve these numbers, and at first, I thought adding more dynamic IL generation would solve the problem. After all, Lightweight Code Generation with DynamicMethod seems to be the trend nowadays among the other frameworks like Ninject, and that makes their code run faster, right?

Once again, I was wrong. DynamicMethods didn't make much of a performance impact because Ninject (which reportedly uses a lot of LCG its code) was actually the slowest among all of the IOC containers tested in the benchmark (Sorry Nate). Of course, this doesn't mean that the DynamicMethod approach is the cause of the slowdown; what it does suggest, however, is that piling more and more reflection onto the speed problem is not the solution. In addition, there were other frameworks in that benchmark (such as Funq) that didn't use any reflection at all, and yet, they still were taking significant performance hits on that benchmark. In fact, even the fastest among all the other containers--StructureMap--was still running forty-four times slower than the Plain/No Dependency Injection use case!

So the principle question is this: "Where is this bottleneck coming from, and how do I eliminate it?"


The Real Problem


As it turns out, the answer was staring me in the face all along: "It's the configuration, stupid", I thought to myself. The problem is that every major IOC container at the time of this post (such as Ninject, StructureMap, Unity, AutoFac, Castle, LinFu, etc) essentially has to trawl through each one of its dependencies just to instantiate a single service instance on every call, and practically no amount of optimization will ever compensate for the fact that they still have to "rediscover" any given part of an application's configuration in order to instantiate that one service instance. Needless to say, this rediscovery process wastes a huge amount of resources because these containers are actually "rediscovering" a configuration that (for all practical purposes) will rarely change between two successive method calls.

In layman's terms, this is akin to stopping and asking for directions at every intersection every time you want to leave your home to go to some other destination. There has to be some way to see the "whole map" and plan the trip ahead of time without having to stop for directions at every intersection. If you could plan all the possible routes on that trip ahead of time, then all the time you would have wasted asking for directions immediately vanishes.

In essence, that is what I did with Hiro. Hiro is an IOC container framework that reads the dependencies in your application ahead of time and actually compiles a custom IOC container that knows how to create those dependencies from your application itself. It uses absolutely no runtime reflection or runtime code generation, and since all your dependencies are discovered at compile time (that is, when the Hiro compiler runs), Hiro suffers zero performance penalties at runtime when instantiating your types.

Yes, you read that right: Hiro runs at 1:1 speed with a Plain/No DI configuration. Here's the results of the IOC container benchmark:




As you can see from the results above, the current crop of IOC containers (including LinFu) can only reach 2% of the speed of an application that does not use an IOC container. Now, let's take a look at Hiro's results:



If you don't believe it, then you can download and run the benchmarks yourself.

Like LinFu, Hiro is licensed under the terms of the LGPL, and you can preview the source code at this site. I'll also be starting a Hiro-contrib project, so if you want to add your own extensions, just email me at marttub@hotmail.com and I'll be more than happy to anyone who is interested. Thanks! :)

Sunday, March 1, 2009

Common Service Locator Adapter for LinFu 2.0 Released!

Now that LinFu.IOC 2.0 is officially out, it's time to join the rest of the IOC container pack and let users try out LinFu without tying them to any specific IOC container API. The adapter for LinFu makes it possible to use the Common Service Locator interfaces to make your applications completely container-agnostic, so if you haven't tried LinFu yet, download the adapter, and give it a shot. :)

Ratings by outbrain