Going off the Reservation with Constructor Logic, Part 2


First I want to say thanks to Alex for the feedback on my previous post. I did eventually manage to clean up my design quite a bit, but couldn't really put my finger on why it was so hard. After reading Alex's comment it occured to me that I hadn't really thought very hard on where the layer boundaries are. I had (and maybe still have) my persistence, my service, and my infrastructure layers somewhat intertwined. I'm ashamed to have been bitten by this considering how much of a proponent of intentional design and layering as I've been.  But I was on a spike to tackle some unfamiliar territory, as well as fighting with a bit of an uncooperative helper framework, so it seems I bit off more than I could chew.

The problem I was trying to deal with was a multi-threaded service, with some threads producing data, and others consuming it to store to a DB. Between device sessions, threads, DB sessions, and domain transactions, I had a lot of "resources" and "lifetimes" that needed very careful managing. It seemed like the perfect opportunity to test the limits of the pattern I've been fond of lately, of creating objects whose primary responsibility is managing lifetime. All services which operate within the context of such a lifetime must then take an instance of the lifetime object.  This is all well and good, until you start confusing the context scoping rules.

Below is a sample of my code. I'd have to post the whole project to really give a picture of the concentric scopes, and that would be at least overwhelming and at worst a violation of my company's IP policies. So this contains just the skeleton of the persistence bits.



The important part of this picture is the following dependency chain (from dependent to dependency): Repository->DataContext->SessionProvider->UnitOfWork. What this would indicate is that before you can get a Repository object, you must have a Unit Of Work first. But it's common in our web apps to basically just make the UoW a singleton, created at the beginning of a request, and disposed at the end. Whereas in a service or desktop app the most obvious/direct implementation path is to have different transactions occurring all over the place, with no such implicit static state to indicate where one ends and the next begins. You get a common workflow that looks like this: Create UoW, save data to Repo, Commit UoW. This doesn't work nicely with a naive IoC setup because the UoW, being a per-dependency object now, is created after the Repo, which already has its own UoW. The changes are in the latter, but it's the former that gets committed. So either the UoW must be created at a higher scope, or the Repo must be created at a lower scope, such as via a separate factory taking a UoW as an argument. I'm not super fond of this because it causes the UoW to sort of vanish from the code where it is most relevant.

One final option is that the dependency chain must change. In my case, I realized that what I really had was an implicit Domain Transaction or Domain Command that wasn't following the pattern of having an object to manage lifetime scope. The fact that this transaction scope was entirely implicit, and its state split across multiple levels of the existing scope hierarchy, was one of the things that was causing me so much confusion. So I solved the issue by setting up my IoC to allow one UoW and one Repo per "lifetime scope" (Autofac's term for child container). Then I created a new domain command object for the operation which would take those two as dependencies. Finally the key: I configured Autofac to spawn a new "lifetime scope" each time one of these domain command objects is created.

Again this illustration is a bit simplified because I was also working with context objects for threads and device sessions as well, all nested in a very particular way to ensure that data flows properly at precise timings. Building disposable scopes upon disposable scopes upon disposable scopes is what got me confused.

I have to say that at this point, I feel like the composability of the model is good, now that I've got layer responsibilities separated. But that it feels like a lot is still too implicit. There is behavior that has moved from being explicit, if complex, code within one object, to being emergent from the composition of multiple objects. I'm not convinced yet that this is an inherently bad thing, but one thing is for certain: it's not going to be covered properly with just unit tests. If this is a pattern I want to continue to follow, I need to get serious about behavioral/integration testing.

Going off the Reservation with Constructor Logic

I'm noticing a strange thing happening as I make classes more composable and immutable. Especially as I allow object lifetime to carry more meaning, in the form of context or transaction objects. This shift has made object initialization involve a lot of "real" computation, querying, etc. Combined with a desire to avoid explicit factories where possible, to capitalize on the power of my IoC container, this has led to an accumulation of logic in and around constructors.

I'm not sure how I feel about so much logic in constructors. I remember being told, I can't remember when or where, that constructors should not contain complex logic. And while I wouldn't call this complex, it certainly is crucial, core logic, such as querying the database or spinning up threads. It feels like maybe the wrong place for the work to happen, but I can't put my finger on why.

It's important to me to be deliberate, and I do have a definite reason for heading down this path. So I don't want to turn away from it without a definite reason. Plus, pulling the logic out into a factory almost certainly means writing a lot more code, as it steps in between my constructors and the IoC container, requiring manual pass-through of dependencies.

I'm not certain what the alternative is. I like the idea of object lifetimes being meaningful and bestowing context to the things below them in the object graph. Especially if it can be done via child containers and lifetime scoping as supported by the IoC container. But it is really causing me some headaches right now.

My guess at this point is that I am doing too much "asking" in my constructors, and not enough telling. I've done this because to do the telling in a factory would mean I need to explicitly provide some of the constructor parameters. But I don't want to lose the IoC's help for providing the remainder. So I think I need to start figuring out what my IoC can really do as far as currying the constructor parameters not involved in the logic, so that I can have the best of both worlds.

Maybe it will bite me in the end and I'll pull back to a more traditional, less composable strategy. Maybe the headaches are a necessary consequence of my strategy. But I think it's worth trying. At least if I fail I will know exactly why not to do this, and I can move on to wholeheartedly looking for alternatives.

Thoughts, suggestions, criticisms? Condemnations?

Satisfying A Pair of Same-Typed Dependencies with Autofac

We'll take a break from the series on Windows services this week and cover some more Autofac / IoC / DI material. I hope to finish the services series with the final part next week.

Back in December I wrote a rather long post about the different Autofac relationship types. I covered what I considered to be the big ones, but there were a few that I didn't cover: IIndexed, and Keyed. I had an objection to these types that prevented me from examining them any further.

My Initial Objection

It's pretty simple. I don't want to have to reference the the IoC container framework in my classes. Accepted wisdom on IoC container usage is that you shouldn't reference the container, and I viewed this as an extension of that. Indeed I prefer to avoid referencing such infrastructure frameworks in core code wherever possible.

I feel the same way about the BCL's TypeConverterAttribute, and the XML serialization attributes, for example. It's an insidious form of coupling, and I really prefer to avoid having these little signposts sprinkled throughout the code of what framework I'm working with. Especially if they represent things that I can't sub out for testing, as is usually the case with the BCL.

In addition to the framework reference objection, I felt that this was just not a responsibility that belonged to the subject class. Using special parameter types or the like to denote such information was "cheating", akin to service location, and undermined the principle of Inversion of Control.

The purist in me had dug in on two separate fronts, and was ready for a fight. But recently I had an experience that taught me the value of these relationship types: I found I needed to inject two different implementations of the same service in the same place. I initially shied away from these relationship types. Instead, I decided I could solve the problem with a clever registration/configuration. After all, deciding who gets what implementations is what that's all about, though typically in a more generalized sense.

The Problem

My situation was that I had needed two different runtime instances of an image cache. One for full-size images, and one for thumbnails. And most commonly I needed to reference both of them in the same scope. If the two use cases existed in different contexts, I could possible use Autofac's nested container support to identify each one appropriately when needed. But in my scenario, I actually had a couple of classes that needed to make use of both caches. I gave the constructor for that class two parameters for injection, both having a datatype of the cache interface type. Then I went to work setting up the registration.

Without a major redesign, the solution has to involve attaching some metadata to each of two separate instances registered with the container. The container needs some way to differentiate between the instances. Since Autofac provides it, there's really no reason at all not to use the keying facility for registration. Given an interface ICache and an implementor Cache, the registration would look as below.


Now let's introduce another class that needs to use both of these caches.


Again, my instinct is to say that the class shouldn't have to say anything else. It's the container's job to figure out how to fill those dependencies. But what information does the ImageBrowser class expose that the container registration could use to determine which argument gets which instance of ICache? Well right now, there's not much there. Pretty much just the argument names. Can we use those to assign the ICache instances? Yes, but it ain't pretty.

OnPreparing1

The way to access the parameter names for resolution is to hook the OnPreparing event, as seen here:


Our implementation of OnPreparingImageBrowser then looks like this:


This looks harmless enough, if a bit verbose. But is a problems. We have encoded parameter names in strings in our registration code. If we ever have to change those parameter names, or add more dependencies to the constructor, this registration code for ImageBrowser will be broken, but it will still compile. So unless you have some pretty magnificent tests for your IoC registration (which it seems is not easy to do), this is a regression bug waiting to happen. Furthermore, this code is very likely useless even if we have another class with these same dependencies. If the constructor arguments are named differently, we'll need another delegate for that set of constructor arguments.

So obviously argument names aren't the ideal way for the subject to communicate information about multiple dependencies of the same service type. And even using the argument names undermines my objection in spirit. It just does it implicitly, rather than explicitly. So let's just accept that we've already taken the first step and go the rest of the way. How can we communicate the necessary information in a sustainable way, that doesn't require us to go mucking around in the registration code if we shuffle things around a bit in ImageBrowser?

Three options spring to mind. One would be to use an attribute applied to the arguments of the constructor. But there's no native support for recognizing these in Autofac, so we'd have to write our own registration and resolution conventions. While it would be more resistant to change than the named parameter mechanism, it would require even more code on the registration side of things, to set up a convention-based registration that keys on the attributes. Not to mention having to define the attributes. This actually sounds like a fun exploration for another day. But today, we just want to get this working with a small amount of intuitive code.

Autofac has two mechanisms which we can use to reduce the amount of code we need here: IIndexed and Meta.

IIndexed<TKey, TComponent>2

Using Autofac's IIndexed mechanism is a simple change from where we are now. It involves a small change to the constructor of ImageBrowser, and removing code from the bootstrapper. That's right, a net reduction in code, without losing functionality. And there's nothing better than a good codectomy. So grab the scalpel and sculpt our new bootstrapper.


Note the removal of the OnPreparingImageBrowser method, and the reference to it in the ImageBrowser registration. That's the only change here. It's completely unnecessary code. The cache registries don't need to change because the IIndexed mechanism hooks right into the keyed registration just like our old strategy did.

The ImageBrowser constructor needs to change a bit to trigger resolution using the keyed registration. Here's the updated class:


The only change here is that we consolidated the separate cache arguments into one dictionary-style argument.

Meta<TComponent>3

Autofac's Meta mechanism works a little differently in that it allows you to attach data to a registration, and then to express a dependency on that metadata, in the subject class. The data takes the form of name/value pairs. If we wanted to use this, it would change our registration as follows:


We've replaced the call to Keyed with a call to WithMetadata. We also are essentially passing a name-value pair. There's also the option to attach an actual custom metadata object, and use the property names and values as the name/value pairs. Since we only need the one value, and it's not going to be changing at runtime, we can just directly assign the name and value easily.

Once again our constructor will need to change, of course. Here's the version that uses the metadata:


Here we're using the IEnumerable relationship type to get all the metadata objects, and then explicitly picking out the ones with the two with the values we're looking for. The CacheTypeChecker method is just a little comparison delegate generator that saves a bit of repeated code in the constructor.

The Lesser of Two Evils

Now this isn't necessarily the problem that Meta or IIndexed are meant to solve. It's really more meant for cases where the needed component is going to depend on runtime conditions. In that case, a simple service finder/locator is sometimes exactly what you want. There are often other ways to get the job done even then however, for example using lifetime contexts and contextual state objects to give the container all the information it needs.

In our case though, the dependency that's actually being injected bothers me a bit. It's sort of a limited service locator. The problem with that is that the specific dependencies aren't explicit. ImageBrowser is basically saying, "Er, I can't tell you exactly what I want, but if you give me everything like this, I'll pick out the ones I want". That is definitely not a pure inversion of control in this case, because we need exactly 2 instances of a very particular type.

We're basically limited to choosing the lesser of two evils. Do we couple to constructor argument names, or take a dependency on a service locator? I'm not sure I feel more strongly about either one. But the IIndexed option is definitely the least code, so that's the one I'll go with. And you can bet that if I run across a situation where the decision of which instance I need is made at runtime, I'll look to these solutions first.

Somewhere down the line I'll investigate that attribute convention option I mentioned in passing. I tend to dislike attributes, but if it's our code (rather than framework code) that does both the defining and the consuming... then maybe I can live with it.



GitHub Source Code References
  1. Keyed registration with OnPreparing resolution
  2. Keyed registration with IIndexed<TKey, TComponent> dependency
  3. Metadata registration with Meta<TComponent> dependency


Dependency Relationships and Injection Modes: Part 2

Last time, I wrote about primal dependencies and the constructor injection mode. I also mentioned that in Part 2 I would cover "the other mode". In contemplating this other mode, however, I came to the conclusion that there are in fact two other modes. I'll cover both of them here in Part 2, but first we'll tackle mutator injection and optional dependencies.

Mutator Injection

Let's get the terminology out of the way first. By mutator, I mean a property or method on a class or object that is used to change some bit of state in that class or object. By optional dependency, I simply mean one which is not required in order for the object to accomplish its primary purpose.

In most code you'll read, mutator injection is ubiquitous. However, I would argue that most are misused because the usage, the need, or both, do not fit the above description of an optional dependency. So what are people doing with dependency mutators that they shouldn't be? And what should they be doing instead? Most people use mutation when they are presented with an apparent hurdle to using another, preferable injection mode. Often this comes down to an inconvenient design choice external to the class that creates an environment where it is hard to do the right thing. The appropriate response is of course to fix the context, whenever possible.

Why You Should Prefer Alternatives

Often, a dependency mutator is used to handle post-construction initialization of a primal dependency, where the appropriate dependency instantce is not known or available when the consumer is constructed. I would argue that this is very rarely an inevitable state of affairs, and is commonly due to a dependency cycle between two layers of the architecture. (I.e. an object in one layer depends on an object in the layer below it, and another object in that layer depends on an object in the first layer.)

Intra-layer dependency cycles are almost always a bad idea, not just because it makes it tough to avoid mutator injection. Maintaining a single direction of intra-layer knowledge also helps to prevent unnecessary coupling, and it aids in keeping each layer cohesive. But an extra benefit of fixing this situation is that it will typically allow for the primal dependency to be created or retrieved when it is needed for the constructor injection, rather than by the consumer or a manager object.

Why does this matter so much? Most simply, because mutator injection is a state change. And state changes are big potential points of failure. It's also well-established that it's easier to reason about immutable data structures. I've found this to be true in my own experience as well. It's easier to compose behavior out of pieces that exhibit immutability because it simplifies the interaction graph. Furthermore, when things go wrong fewer state changes means a shorter list of possible places where the bad state may have been triggered. So when designing my classes, I avoid mutators wherever I can, and that means preferring constructor injection and site injection over mutator injection whenever possible.

The other way that mutator injection is mis-used is in a situation I briefly mentioned in Part 1: when only a subset of the operations on a class actually make use of the dependency. Mutators are often seen as convenient in this situation because they cut down long constructor argument lists, which are seen as messy or complex. The fact that the object has at least a limited use without the dependency makes it possible to get away with setting it later.

In Part 1 I said that the situation itself is often due to a violation of the Single Responsibility Principle. It would be facile to cite this reason for all instances of mutator injection. Sometimes it's true and sometimes not. When it really isn't true, there are a couple of other options available before you have to resort to mutator injection.

The first option is again to drop back to constructor injection, but to do so with a sort of lazy proxy in its place. The lazy proxy exists for the sole purpose of deferring the resolution of the actual service dependency until it's needed. This is its Single Responsibility. It can then either provide an instance on demand, or it can be more transparent and just implement the same interface and delegate to the underlying object.

In a static language like C#, this isn't always possible either. Sometimes there's no interface, and some of the members are not virtual, so they can't be overridden in a derived class. If you control the code of this object, I highly recommend refactoring to an interface to resolve this problem. But if you don't, it might be time to look at the third injection mode: site injection.

Temporal Dependencies and Site Injection

Site injection is a fancy name for a method argument. It describes the use of a service as an argument to the operation for which it will be used. Such a dependency, that is passed directly to an operation, and for which no reference is maintained after that operation completes, is called a "temporal dependency". The reference is fleeting, and not actually part of the state of the object that depends on it.

There are a couple consequences of this type of injection. First is that the calling object or objects become the primary dependents of the service. It may or may not be easier to manage the dependency there. Hopefully it is, but sometimes it isn't, especially if there are many different objects that may call on this operation.

The other consequence of site injection is that it can add noise to the interface/API. If there are multiple operations in the subset of the dependent object that make use of the service, the repeated passing of the service into the objects can feel like unnecessary overhead. Not performance-wise, but in terms of keeping the code clean and readable. Expression of intent is paramount here. If the extra arguments communicate the true relationship between these two pieces of your architecture, then it's not truly noise. Instead it's a signal to readers of what's going on, and who's doing what.

There are lots of places where site injection and temporal dependencies are very natural. So many that you probably use them without even thinking about it, and it's often the most appropriate thing to do.

Truly Optional Dependencies

That's probably enough about what isn't an optional dependency. So what is? I would argue very few things are. Usually an optional dependency crops up as something that can be null when you want to do nothing, or can have an instance provided when you want to do something. For example, one step of an algorithm template, or a logging or alert solution with a silent mode. Often, even these can be treated as primal dependencies from the consumer's perspective, with a bonus of avoiding null-check noise. Just provide a Null Object by default, and make a setter available to swap the instance out as necessary. If you can say with certainty that this is not appropriate or feasible, then you may have a truly optional dependency.

A Good Start

I believe these three dependency relationships, and the injection modes associated with them, cover most of the scenarios that you'll encounter. And I've found that the advice I've included for normalizing to these modes has helped improve the design of my code in a very real and tangible way. But I'm certain my coverage isn't complete. There are surely more dependency relationships that I haven't identified here, especially if you dig into the nuances. I'd love to hear about other types of dependency relationships you've encountered if you're willing to share them in the comments.

Dependency Relationships and Injection Modes: Part 1

This week I'm going to continue my trend of adding to the cacophony of people talking about IoC and DI. There's a lot of talking, and a lot of it is noise. Not inaccuracy, mind you. Just an awful lot of shallow coverage, one step beyond assumptions and first principles, with not a lot of real analysis. So let me bring a bit of deliberate consideration and analysis to the table, and hopefully improve the signal to noise ratio.

What's different this week from the recent past is that I am specifically going to talk about DI for once, rather than IoC in general. The particular topic I want to address is something that I've seen addressed a few times, but usually in passing reference in the context of some other argument. And most often it's being both taken for granted and dismissed out of hand, by the respective debaters.

In most languages there are essentially two injection modes available: via a constructor argument, or via a mutator such as a property setter or method. I've found that each option is most appropriate in different situations. A constructor argument dependency expresses a relationship that is very different than that expressed by a mutator.

Conveniently, there are also two broad types of dependencies that map fairly well to these two modes. The first is sometimes termed a "primal dependency". (I'd love to credit the inventor of this term, but all i can find in a Google search is Jimmy Bogard, Tim Barcz, and Steve Harman all using the term as if it already existed.) The second type of relationship is most often called an "optional dependency", which is a much less evocative term, but it's a descriptive one nonetheless.

The relationship that is being evoked by the term "primal dependency" is one of raw, fundamental need. A primal dependency is one that must be satisfied in order for the class to even begin to do its duty. When a primal dependency is unfilled, the dependent object is essentially incomplete and nonfunctional. It's in an invalid state and can't properly be used.... At least not if the SRP, or Single Responsibility Principle (PDF link), is being obeyed.

The SRP is one reason why I advocate using constructor injection for primal dependencies. Constructor injection makes it explicit and unavoidable that a given dependency is a requirement for proper functioning of the object. If a dependency could be provided via a mutator without affecting the post-construction usefulness of the object, then really you have one or both of two situations. Either it's not really a primal dependency, or your object is responsible for more than one thing and this dependency is only required for some of those things. Using constructor injection avoids the possibility of this signal being hidden behind the guise of post-construction initialization.

When people oppose constructor injection, it's often on the claim that it puts an undue burden on the object performing the instantiation. While it's true that a burden is being transferred, I'd argue that it's not undue. Construction and initialization of an object into a fully valid state should be considered to be two parts of the same operation, the same responsibility. Furthermore, this responsibility is separate from the primary purpose for the existence of the object itself, and so it doesn't belong to the object itself. This is what DI is meant to resolve. Yet, the logic must be taken a step further.

If construction and initialization is truly a multi-step process pulling from different domains, and/or which can't cleanly be handled in one place, then it's a responsibility that's complex enough to base on entire object around. In short, you should strongly consider setting up a factory or builder object to handle this task. The only extra burden this leaves is on the brain of the programmer who is unfamiliar with the pattern. But trust me: just like with any exercise, the burden gets lighter with repetition.

I have a confession to make: I had never actually used the builder pattern until I came to this revelation. I didn't really understand what the benefit was over a factory. And I'd only taken the most rudimentary advantage of factories, for implementing concrete implementations of abstract base classes. But now each is as clear, distinct, and obvious of purpose to me as a screwdriver and a hammer. You'll find they come in quite handy, and really do clean up the consuming code, once you acknowledge that construction and initialization should often be a proper object responsibility all on its own.

In Part 2 of this topic, I'll address optional dependencies and the mutator injection mode. Like today's topic, they're deceptively simple to describe. But there is just as much, if not more, nuance to be found in the manner and purpose of their implementation.

What Your IoC Container Won't Tell You About Inversion of Control

As I've written about recently, the term "Inversion of Control" has come to be closely associated with "Dependency Injection". Indeed many people tend to use the two terms interchangeably. The reality is that DI is just one way of achieving one kind of limited IoC.

It's worth considering that something cannot be inverted without there being an original, un-inverted state. So what is that state, and why did it become so important to invert it? According to Martin Fowler's Bliki post on IoC, the state in question is which code is in control of the flow of the program within a particular scope. Fowler credits Ralph Johnson and Brian Foote's 1988 paper Designing Reusable Classes, with originally identifying the boundaries between system layers, or between a framework and the consumer of that framework, as being particularly valuable places to invert control.

The goal of the inversion, as stated by Fowler, Johnson, and Foote, is essentially to let a service remain in control of the pieces of its execution, rather than to micromanage it from the outside, like a boss who insists on being kept "in the loop". I would say this is dramatically different from what IoC has come to mean in the common parlance today.

IoC in its common usage has become divorced from the Hollywood Principle, which was about allowing a service to retain control of its own execution. Instead it has been married to DI, which is about a service divesting responsibility for ancillary concerns. The latter is equally important. But only equally. When they are brought together, they enhance each other and the resulting clarity of the design is more than the sum of its parts.

There is a duality here that is important to keep in mind when designing classes and interfaces. A duality of scope, a duality of perspective, a duality of responsibility, a duality of control. There is both give and take. By giving one thing, we take another. IoC is not just about giving up control and responsibility for choosing and creating dependency implementations. It's also about taking control and responsibility for the cohesion of the solution, the algorithm, and the facade that's offered by a service, a framework, or a layer.

It is far too easy, when one first delves into DI, especially aided by the power tool that is an IoC container, to forget this other side of things. We become satisfied that as long as we don't have a "new" in our constructor, we must be on the right track. But sooner or later you will end up in a situation where the discipline of DI becomes very difficult to maintain. Without the context of where DI came from, the limits of its purpose, and the parallel concerns that were meant to be addressed alongside, it won't be clear what is the proper way to proceed. You may realize that it's time to "break the rules", but you won't know what new rules then take over.

Speaking from experience I can tell you that this way lies madness. Or at least messiness. Potentially maddening messiness. Far too many people simply shed the rules as they pass this boundary and revert back to wild and woolly frontier-style programming. But the truth is that you aren't passing from civilization into the wilderness. You may be leaving one regime, but you're also entering another. And the guiding light of this new regime isn't just "whatever works". Most likely it's simply time to broaden your perspective beyond the issue of class dependencies and Separation of Concerns.

Start to look at the surface of the layer, model, framework, or module that the problem classes are a part of. Consider all of its responsibilities, dependencies, entry points, hooks, and outputs. If you are encountering problems making DI work, it's very possible that a mess has begun to accrete in one of these other aspects. If you step back to get the broader perspective, it may be easier to identify the problem as a flaw in the cohesion of it as a whole.

In particular, look at the ways your objects are working together, and the way the whole layer interacts with its consumers. A clear story should show up somewhere. Yes you may have a hundred small classes running around taking care of little chunks of the work. But someone should be "conducting" these bits as they work together to accomplish the goal, and that someone should be chosen and designed deliberately.

It's a common mistake to break responsibilities down into bits and then just toss them all together with no real clear roadmap emerging from the noise. This is a real problem, and the cause is a proliferation of delegation in the interest of decoupling, combined with a failure to take the reigns of regional control that ensures cohesion. Weaving together the dual needs of decoupling and cohesion is what Inversion of Control is really about.

Taking IoC beyond DI with Autofac Part 2: Relationships

In my last post I began to discuss the applications of Autofac as a tool for accomplishing true Inversion of Control, beyond just simple Dependency Injection. Specifically, last time I focused on creation strategies and lifetime control.

This week I want to talk a little more about lifetime control, and a lot more about categories of dependency, also known as relationship types. Nicholas Blumhardt, the principal author of Autofac, has a great blog post on what he calls “the relationship zoo” which I think goes a long way toward covering this space. I was originally going to do something similar, but his post is far more authoritative, and I’m quite certain I couldn’t do better. So instead, I'll abstain from the explanation and code samples and stick to analysis and rumination. So go read his post, then please do come back here and I’ll expand on it with some of my own thoughts.



The reality is that I take issue with some of the dependency abstractions provided by Autofac. It can be quite dangerous to your design to rely on some of them without very good reason. Used properly and prudently, they can absolutely address some particularly painful problems, especially when the dependencies consist of code you don't own and can't change. But it’s also easy to let them creep in wherever they appear to be convenient, and severely corrupt your design and architecture by doing so.

Let me start with the warnings, and then I’ll move on to extoll some virtues that I think Nicholas neglected to identify.

The first relationship type to be wary of is Lazy<T>. The intended purpose, as Nicholas explains, is to avoid expensive operations or construction until or unless it’s necessary. The idea of a lazy object is an old one. It’s a pattern that has been around for a while. My opposition to the usage of this relationship type is primarily that the need for laziness is usually a function not of the usage by the dependent class, but rather of the implementation of the module that is depended upon. Where possible, the consumer should be ignorant of implementation details of its dependencies. Let’s recognize that expensive operations are rarely truly transparent or ignorable, but the fact remains that the responsibility for this situation lies with the module being depended on, not on the consumer.

I strongly believe that if the code of the module that will be resolved for this dependency is under your control, then it behooves you to wrap the laziness around this functionality elsewhere... either building it into the implementation, or wrapping it with some sort of facade. Where Lazy<T> comes in handy is when you don’t have control over this code, and the class poorly encapsulates its functionality such that it can’t sufficiently be wrapped in a facade. At that point the consumer cannot pretend to ignore the situation, and may benefit from delegating the responsibility for the laziness to the container.

I’ll attach my second warning to the Func<T> relationship. I’m wary of the plain Func<T> because it overlaps a great deal with both Lazy<T>. It shares the same issues as Lazy<T> while adding the sin of looking suspiciously like a service locator. Service locators can be dangerous because they subvert the goal of inverting control. A service locator hands control back to the consumer by saying, “just call when you need X”, rather than handing off the dependency and saying “I know you need X so here, use this for that”. This is very rarely the appropriate way of expressing the relationship. The exception would be in the case that the consumer knows for certain that it will require multiple instances of the service it depends on.

Let’s spin things back to the positive by looking at Func and the like. How does adding the extra generic arguments change this from a smell to proper IoC? It expresses a very particular type of dependency. Specifically, it says that this class depends on at least one instance of T, but which instance or instances are needed is a function of a few arguments which won’t be known until each instance is actually needed. This is useful if you have a service which must be constructed for each use and requires some primitive types to guide its behavior, such as an encryption object which requires a key at construction. Or if you have a few different implementations of the a service which are mapped to different run-time states, such as a set of logging mechanisms for different error severities.

The IEnumerable<T> relationship is similar to this last scenario in that it offers a way to say “I depend on all implementations of T, no matter what they are”. This is probably a rarer scenario. Usually a service will have one key implementation, or a couple with very specific and differing purposes which will be used separately in different places. The most likely way for an inclusive but generalized need like this to arise is in an add-on or plug-in scenario. And in that case, you’re likely going to need some up-front processing to get things loaded up before the implementations can be passed off as dependencies to other objects.

I should note that it is probably not all that unusual for IEnumerable arguments to show up in constructors. But more often than not, this will be in data classes which will be instantiated directly, or a single step removed via a factory method, rather than resolved by the container. These aren’t truly “services” and are very unlikely to be registered with the IoC container. The factory may be a service, but what it creates in this case is more of a data structure than anything. Data structures mean state, and usually highly contextual ones at that. Autofac more context-sensitive than many IoC containers, but even it has its limits. With data structures, usually the best solution is either a direct constructor call, or a light factory.

One more small step along the path is Meta<T, M>. This is relationship type that specifies a dependency not only on a service of type T, but on some piece of metadata of type M about the module that will be provided at runtime. This metadata may be used to decide whether or not to go through with making use of the service, or how to do it. In fact, metadata is a great way to handle the special considerations a consuming object may need to make for a lazy service implementation involving a long-running operation. Maybe 90% of the time, the app can simply halt for an operation, but for certain implementations of the service, it’s more prudent to display a friendly “please wait” message and a progress bar. Attaching metadata at registration is a great way to enable these types of decisions intelligently without hard-coding a universal expectation one way or the other.

The final relationship type to address is Owned<T>. This one can be quite handy. At first blush it seems like this might violate the same principles as Lazy<T>, but if you think about it, they are actually quite different. Owned<T> indicates that the object expects to be solely responsible for the fate of the dependency passed to it. This tells the programmer, “I’m going to use this up, and it won’t be any good when I’m done with it, so just clean it up afterward.” Believe it or not, this fits in perfectly with the recommended implementation pattern for the .NET IDisposable interface. That is, that at some point, some object takes ownership of the resources, and responsibility for calling IDisposable, absolving all other transient handlers of the same. Ownership is sort of the dual, or inverse, of a constructor dependency. The constructor dependency says “I know I’m going to need this object”, and the ownership claim says “when I’m done with it, it can be tossed out.” And Autofac happily obliges, releasing the dependencies when the consumer itself is released, calling IDisposable.Dispose as appropriate.

After a twitter conversation with Nicholas himself, it became obvious to me that Owned<T> is probably the better solution to my qualms about InstancePerLifetimeScope. By establishing that the consumer “owns” its dependencies, we have essentially established exactly the limited and definite lifetime context that I was asking for! Behind the scenes, a lifetime scope is spun up when the object is instantiated, with nested resolution rules being applied as a matter of course. And when the object is released, then so is the lifetime scope and anything that was resolved as a new instance in that scope. However, we do have a symmetrical limitation here. Both the creation and the destruction of the context are tied to this object. Once the context is created, it can’t and/or shouldn’t be shared with anything either above or adjacent to this object in the dependency graph, or the deterministic disposal Autofac prides itself on will subverted and become unreliable.

In these past two posts, I’ve covered the whole continuum of dependency creation, lifecycle, and relationship strategies that go beyond simple Dependency Injection to fill out the breadth of what Inversion of Control really means. And they’re all available via Autofac to be handled (for the most part) separate from the implementation of the consumer, and without writing boilerplate factory classes or resource management classes to make it work. I hope that in reading these posts some people may see that IoC is a broad space of patterns and solutions, and that IoC containers are powerful and useful and far beyond the naive use and even abuse that people put them to for simple DI.

Clean Injection of Individual Settings Values

The Setup

Today I again encountered a challenge that I have dealt with numerous times while working on the product I develop for my employer. It's not insurmountable an insurmountable challenge. Honestly, it's not even all that challenging. But it has been an irritant to me in the past because all the solutions that I have come up with felt unsatisfactory in some way.

That challenge is the injection of simple settings values into the classes that need to refer to them. By simple I mean single-value settings embodied by an integer, a string, or a floating-point, for example. This seems like a simple problem. And honestly, I thought this was going to be a short and sweet post, until I realized that there is value in delineating all the dead ends I've followed on the road to my current favored solution. As you'll see, I've put a fair amount of thought and analysis into it.

Being a hip programmer, I use an IoC container to constructor-inject all my complex dependencies. And my IoC container of choice, Autofac, is only too happy to auto-wire these so I don't have to worry about them. But mixed in among these are the simple settings values that guide the functionality of certain classes. A component/service model doesn't really apply to these values. No one string value is implementing the "string" service. The values can't be easily auto-wired because unlike the complex classes there is certain to be more than one important value floating around for the primitive type in question.

Our app processes image. Large files, and large volume. And worse, the working sets are very large, so we can't handle things piecemeal. We have a serious need in a few different places for disk caching of "active" entities that are still very much in flux. Having multiple caching points necessarily means that there are several parameters that may need to be tweaked to keep things optimized. For each cache we want to be able to set the disk location for the cache and the in-memory entity limit, just to start.

Taking a simple case with two cache points, we have two string settings and two integer settings. So already we are in a position where in order to inject the values, we'll need to do some sort of "switching". Some run-time decision of which string and which integer go where.

Pitfalls and Red Herrings

As I noted in my opening, I have solved this in several ways in the past. One is to hook into the IoC via Autofac's "OnPreparing" event, where I can supply values for particular constructor parameters. This is nice, because it means I can avoid setter injection. But it complicates the IoC bootstrapper by adding exceptions and special handling for particular classes. Just as undesirable, it couples the IoC bootstrapper directly to the settings mechanism.

What about setter injection? Autofac provides a post-construction OnActivated event that is perfect for setter injection, but this is subject to the exact same disadvantages as the pre-construction event. We could leave the setters alone and let some other object fill them in, but that leaves us with a couple different problems. First, there's just as much coupling, it's just outside the IoC, which may or may not be a marginal improvement depending on how it's implemented. If you end up with some class that must be aware of both the app settings mechanism and the class(es) that receive those settings then this is really not much of an improvement.

But beyond that, refraining from providing the values until after the components are obtained is undesirable for yet a few more reasons. First and foremost, it means that your services will exist in a state of incomplete initialization. The risk of getting hold of an incompletely initialized service makes calling code more brittle. And protecting against the possibility makes it more complex. Furthermore, setter injection for these particular types of values is undesirable because it implies they are variants. The truth is that the last thing you want is for some errant code to change the cache location on disk after a bunch of files have been stored there. And putting in protection against such post-initialization changes is pathologically unintuitive: it subverts the very nature and purpose of a setter.

So we've established that these direct injection routes are problematic in a number of ways. Let's move on to indirect injection. What does that mean? Basically it means putting a provider object in the middle. Our classes can take a dependency on the setting provider, which can wrap the settings mechanism itself, or act as a facade for a bundle of different mechanisms.

The option that at first appears simplest is to have a single settings provider object through which all the app's settings can be accessed. The classes can all depend on this object, which the IoC can provide with a singleton lifecycle if we desire, for maximum consistency. But now what we have essentially done is created a service locator for settings. This is another thing that's good to avoid for two reasons. For one, it creates a huge common coupling point, and for two, it violates "tell, don't ask". Why should my dependent class have to depend on a generic interface and worry about asking for the appropriate thing, when all it cares about is just that one thing?

This is especially dangerous if the app-side interface to your settings keeps them grouped just as they are in the user-side (i.e. the config file), as the build in .NET config mechanism is wont to do. The needs of the user for the purpose of managing settings individually or en masse are vastly different than the needs of the application whose behavior is driven by those settings. While a user likely thinks the most intuitive arrangement is for all the 15 of the paths to be bundled together, it's highly unlikely that any particular class in the application is going to care about more than one or two individual paths. And if the class doesn't need them, then they shouldn't be offered to it.

A Light in the Dark

So where do we go from here? If you can believe it after all this meandering and rambling, we're very close. From here we take a little tip from the DDD community: eschew primitives. If you think back to the beginning, the whole problem centers on the fact that primitives are just too darn generic. The type doesn't mean something specific enough for it to be an indicator of what exactly the dependency is. How do we fix this? Encapsulate the individual setting in a type specific to that need. Given that the explicit purpose of these classes will be to provide particular settings to the classes that need them, it is appropriate for these to couple to the configuration mechanism, whatever that may be, and more importantly, encapsulate it in useful bite-size chunks. And because the providers will themselves be injected where needed, the coupling is one-way, one level, down the layer hierarchy, which is arguably the best kind of coupling.

Show Me The Code

Enough talking. Now that I've set the stage, here's some code to furnish and light it.

First, the setting providers. As you can see, they tend to be nice and short and sweet.

Next, the caches that depend on them. Note how the setting providers are used in the constructors.

Finally, I'll show just how easy it can be to wire these up. If you bundle all your setting providers in one namespace, you can even safely auto-register them all in one fell swoop!

Objections?

There are a few things that I can anticipate people would object to. One is the potential for proliferation of tiny classes. I don't see this as a bad thing at all. I think it's fairly well established that small classes, and methods, with laser-focused responsibilities are far easier to maintain, evolve, and comprehend. I can say from personal experience that I am utterly convinced of this. And if anecdote isn't good enough for you, I'll add an appeal to authority to it =) Go read up on what the most respected programmers out there today are saying, and you'll see them express the same sentiment, and justify it very well.

Another thing I expect people to object to is that when taken as a whole, this pile of small classes looks like a bit of a heavy solution. And it is heavy in this context, where none of the actual app code is surrounding it. But nestle it inside a 50K line desktop app with hundreds of classes and it will start to look a lot better. For one, those classes and their namespace create sort of a bubble. It's a codespace that has boundaries and purpose. You know what's inside it, and you know what's not. It's a goal-oriented mental anchor to latch onto while you code, and that's a darn useful thing.