Wednesday, January 30, 2013

Dependency Injection and Leaky Abstractions

Over the years I've generally made use of three basic methods of dependency injection...
  • Constructor Injection
    public class Widget
    {
        private WidgetDependency _dependency;
    
        public Widget(WidgetDependency dependency)
        {
            _dependency = dependency;
        }
    }
    
  • Setter Injection
    public class Widget
    {
        public WidgetDependency Dependency { get; set; }
    }
    
  • Late-Bound Injection
    public class Widget
    {
        public WidgetDependency Dependency
        {
            get
            {
                return ServiceLocatorObject.Resolve<widgetdependency>();
            }
        }
    }
    
Equally, over the years, I've unilaterally preferred the third option. Though I've never really given it a whole lot of thought or attempted to articulate why. It was just a preference. To some (and indeed often to attendees of my What Is Dependency Injection presentation) it can certainly seem like the more complex choice. Sure, it does present a little more code and a little more round-about way if getting what you're looking for, but it carries benefits. And I've recently found a compelling benefit that previously had just sort of tagged along for the ride without explicitly being known to me.

I started thinking about it a couple days ago when I answered a question on Stack Overflow. While answering the question I have to admit that I may not have fully understood what was being asked. But now I think I do. Looking back, it seems to me now that the communications failure between the asker and myself was specifically in regard to the above dependency injection options.

The asker was most likely supplying his dependencies by means of either constructor injection or setter injection. And, since I generally stay clear of those methods, it just didn't occur to me. Instead, again, I prefer the Common Service Locator as a pattern where a single object, bootstrapped at application start, is responsible for, well, locating services. Or dependencies, as it were.

The concern about which he was asking was how to write unit tests without first knowing the implementation of the code being tested. He's seen that Test Driven Development is preferred throughout the industry but couldn't reconcile how one can effectively write tests without knowing some details about the implementation. Specifically with regards to dependencies. And, furthermore, as the implementation changes and the dependencies change, he asserts that the unit tests would have to change as well.

He's right. Because he's using one of my non-preferred methods of dependency injection. And therein lies the problem. Let's assume for the moment that he's using constructor injection. In the example, then, he ends up with an object like this:

public class MyMathObject
{
    public MyMathObject(MyOtherClass1 dependency)
    {
        // implementation details
    }

    public int Add(int addend, int augend)
    {
        // implementation details
    }
}

Looks clean enough, right? But there's a problem. There's a leaky abstraction. His assertion was that, prior to implementing the class, the only known footprint is this:

public class MyMathObject
{
    public int Add(int addend, int augend)
    {
        // implementation details
    }
}

And that it's the implementation details which change the footprint to the previous one with the injectable dependencies. Thus, one ends up in a cycle. Define the object, write tests, implement the object (thus changing its footprint), re-write the tests to match, make updates to the object later in the software life cycle (maybe further changing its footprint), re-write the tests again to match, and so on.

He's right, that is a vicious cycle. And it's all stemming from that leaky abstraction. The problem isn't in the tests or in Test Driven Development at all. The problem is in a flaw in the design of the object. That constructor is making implementation details externally visible. It's not only allowing but requiring that all external neighbors to it know about its implementation details on some level in order to supply those dependencies. And, of course, as those details and dependencies change then all neighbors must also change.

This is tight coupling. If a change to Object A requires that Object B must also change then Object A and Object B are coupled around that feature. In this case those changes are internal implementation details, and so this coupling is of course wrong.

And this is precisely that subtle reasoning I've had behind my preferred method of dependency injection which has never explicitly occurred to me before. With something like Common Service Locator (or, more commonly for me, a home-grown implementation of the same pattern), the dependency injection within the object instead looks more like this:

public class MyMathObject
{
    public int Add(int addend, int augend)
    {
        var dependency = ServiceLocatorObject.Resolve<widgetdependency>();
        // more implementation details
    }
}

Externally to the object there is no knowledge of the dependency. The coupling is eliminated. So things like tests (or any other neighbors to this object anywhere in the system) don't need to know anything about its implementation details, just as it should be.

Tuesday, January 1, 2013

Appy New Year

Be sure that I haven't forgotten about this blog. Be sure also that I've been inordinately busy lately. This seems to have been a theme in my life in 2012... Take on as many things as possible. Or, more colloquially... FILL ALL THE TIME! This blog, much like many of my reading/writing activities, has simply been pushed down the list of priorities. This list ebbs and flows, really. But just to give you an idea of what's currently on the list, in no particular order:

  • A big project at work becoming increasingly stressful as it pushes toward a release date
  • A pro-bono side project where I get a chance to practice various skills and get in on the ground floor on a business opportunity
  • Websites and small projects that allow me to keep tinkering and learning
  • Windows Store apps
  • Increased family commitments
  • A relatively new hobby that takes up a little time and a lot of money (Revolutionary War re-enacting)
I'm indeed quite behind on my reading, though I continue to build my backlog of books at the standard rate. (One new tech book every two months.) Someday the tide will swing back to reading a lot and I'll catch up, I'm sure.

Of these items on this admittedly incomplete list, the one I'd like to bring attention to at the moment is:
  • Windows Store apps
As you're probably well aware, most of my development takes place on the .NET platform. I'm a fan of C#, I guess you could say. Though fanaticism isn't really my thing, nor would devotion to a language or particular tool seem in any way healthy in my opinion. Perhaps it's just a series of coincidences throughout my career, but it is what it is. And if you've kept up with the churnings at Microsoft recently then you're aware of this new RT thing.

Microsoft is changing its platforms. Probably not as fast as they want to, since they still have to support everything else they have. But it is a bold new era for them, or at least they're trying their best to make that be the case. And so they have this new Windows Store development paradigm. You've seen those Windows 8 commercials, right? Touch-friendly interfaces, "fast and fluid", and so on.

Well, recently I became possessed of a Surface RT tablet. ("Recently" as in maybe two weeks ago.) I like it. Sure, it's no iPad, not yet anyway. But it's something. It fills a space in the tech gadget world. And, more importantly, it provides me with a platform on which I can test Windows Store apps as they are intended. Until now I've had only my work laptop and VMs on my personal laptop, which respectively provide less and less of the intended Windows 8 experience.

I have a couple of simple ideas for apps. Nothing major, though I hope that one of them can evolve into something major. I've always had a desire to write these on one platform or another, but that ebbing and flowing list never seemed to have enough space on it for adopting an entirely different platform just for some tinker-level apps.

Then came Windows Store apps. They're mobile apps like any other app store out there, but they're a hell of a lot closer to the .NET space than anything else. Hell, I can even write them in JavaScript, which is something I thoroughly enjoy practicing already. This lowered the barrier to entry significantly. Sure, I'd still like to target other platforms, but now I can get in some early practice and cut my teeth on a more familiar platform.

So as a proof of concept for myself, I've written my first Windows Store app. Indeed, my first app on any app store. It's nothing special, not terribly complicated in any way. The whole thing weighs in at about 200 lines of code (not counting the dressing that Visual Studio puts in by default) and 19KB when uploaded to the store.

All it does is turn your device into a photo frame. (Which I use at work when it's idle, basically like a screen saver that's also family photos on my desk.) What makes it a little more unique is the added feature that you can enter the network address of an Apple TV device (which I have at home and thoroughly enjoy) and the slideshow of photos will be pushed there as well.

Again, it's all terribly simple and I can't be humble enough about it. But I'm proud of it nonetheless. I'm proud of it because it's my first. It's something. It's a thing that I created and published. And that makes it special to me. I'm well into my next app, which is a bit more ambitious. But this one provided me with the momentum.

So I guess in some software geek sense, I'm "published" now? It doesn't feel like the term fits. But, again, it's something. And it's something I'm thoroughly enjoying. Here's hoping my next (more ambitious) app is a huge success.