Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Dependency Patterns

Hey!  You got your chocolate in my peanut butter!  What kind of coupling was created when you got your chocolate in my peanut butter?  Is the chocolate service-located or injected?  Can you get your chocolate back without depriving me of any of my peanut butter?  Would it have been easier if the peanut butter was in the chocolate rather than the chocolate in the peanut butter?

Disclaimer: I’m not a pattern hatchery and I don’t presume to have final say on these things, but I thought I’d throw out some stuff that doesn’t seem to be named – not for the purpose of staking a claim – but to try make communicating agile design a bit more effective.

Here are the dependency patterns that I often work with.  There are likely more of them out in the wild and there are likely better names, but like I said, getting the names and attributions right at this point isn’t the point…

Dependencies

A dependency is created when one object has a reference to another object.  For example: a business service object that has a reference to a data access object.

public class BusinessService
{
    
private IDataAccess _dataAccess = new DataAccess();
    
// …
}

Two Kinds of Dependencies: Good, Evil, and Other

There are two kinds of dependency patterns: Opaque and Transparent.  There are subtypes of these as well (and there are possibly more sibling types).

Opaque Dependencies

Opaque dependencies are the bad kind of dependencies… some would even say that they’re evil.  Well, they’re not necessarily evil, and they’re not even necessarily bad.  There’re just mostly bad… in some circumstances.  In short… don’t use them… ever… unless you should :)

Opaque dependencies are the kind that you can’t assign using a class’s public API.  The example of the business service using a data access (above) is an opaque dependency; you can’t assign the data access object from the outside of the business service class.

Here’s the same opaque dependency as the example above, except with the default constructor initializing the dependency:

public class BusinessService
{
    
private DataAccess _dataAccess = new DataAccess();

    public BusinessService()
    {
        _dataAccess =
new DataAccess();
    }
}

This kind of design makes it hard to test any behavior on that service class that might need to use the data access layer.  Testing behavior on objects should be doable without having to access an actual database even though the service code might make calls on the data access object.

In order to make a class more testable, a class’s dependencies should come in from the outside (this, by the way, is what Dependency Inversion and Inversion of Control is about).

Transparent Dependencies

Transparent dependencies (or inverted dependencies) are assigned from the outside.  The BusinessService’s opaque dependency on the DataAccess class can be turned into a transparent dependency by making the data access a constructor argument:

public class BusinessService
{
    
private readonly DataAccess _dataAccess;

    public BusinessService(DataAccess dataAccess)
    {
        _dataAccess = dataAccess;
    }
}

This makes the business service class’s logic testable without having to deal with a live database.   A fake data access object can be provided to the business service that allows you to get around actually talking to a database.  You need to make some of the data access class’s methods virtual or part of an abstract interface, but that’s a story for later.

Testing

Transparent dependencies are preferred because they drive us (via TDD) toward greater and more explicit Separation of Concerns, which is NASA-speak for “make testing easier now,” among other things (NOTE: NASA-speak is the linguistic effluence of that aspect of programmer vanity that drives programmers to make programming sound like rocket science when in fact it’s just… programming. This phenomenon is closely related to Doctor Speak which is the predisposition to invert English grammar in code so that it reads like Latin as an effort by programmers to sooth their minds over not having had the cajones to get a medical degree).

Here’s a version of the BusinessService class that has been changed slightly to take advantage of the transparent dependency in testing:

public class BusinessService
{
    
private readonly IDataAccess _dataAccess;

    public BusinessService(IDataAccess dataAccess)
    {
        _dataAccess = dataAccess;
    }
}

You might have missed the small change in the above code: the DataAccess class now implments an IDataAccess interface.  A fake version of the DataAccess class can be created, which gets the real data access class out of the way when testing the BusinessService’s business logic.

[Test]
public void TestCase()
{
    
FakeDataAccess fakeDataAccess = new FakeDataAccess();
    fakeDataAccess.ExpectedTotalOfOrders = 100m;

    BusinessService businessService = new BusinessService(fakeDataAccess);

    Customer customer = new Customer(“Bob”);
    
Order order = new Order(customer);

    businessService.ApplyDiscount(order);

    Assert.AreEqual(11m, order.DiscountRate);
}

This is a test of the business service’s ApplyDiscount operation.  It has logic that branches on the result of a query to the database via the data access class.  We want to test both branches without having to setup the database with separate test data that would allow us to cover both branches.  Here’s the implementation of that method:

public void ApplyDiscount(Order order)
{
    
decimal totalOfOrders = _dataAccess.GetTotalOfOrders(order.Customer);

    decimal discountRate = 0m;
    
if (totalOfOrders >= 100m)
    {
        discountRate = 11m;
    }

    order.DiscountRate = discountRate;
}

Since the instance of IDataAccess in the test is a FakeDataAccess, the return value of GetTotalOfOrders() can be controlled without having to do any database setup.

Transparent Dependencies are a Pain in the Metacarpal

Transparent dependencies solve one problem, and create another.  It was much easier to instantiate an instance of BusinessService when it had opaque dependencies because BusinessService had the smarts to instantiate the DataAccess class.

With an opaque dependency, the instantiation of BusinessService was simply:

BusinessService businessService = new BusinessService();

With transparent dependencies, the instantiation is a bit more onerous:

string connectionString =
    ConfigurationManager.ConnectionStrings[“MyConnectionString”].ConnectionString;
DataAccess dataAccess = new DataAccess(connectionString);
BusinessService businessService = new BusinessService(dataAccess);

NOTE: The dependency on ConfigurationManager is opaque! :)

Dependency Injection

Folks typically don’t like transparent dependencies because of the extra coding that it causes.  This should make you wonder… are all these people who advocate TDD and IoC simply off their collective rocker for doing all this extra work?  Of course not!  We use dependency injection frameworks to do this stuff automatically.

Here’s how the above three lines of code would look when enabled by a dependency injection tool:

BusinessService businessService = Container.Resolve<BusinessService>():

A dependency injection framework like Windsor, StructureMap, or Spring will handle the dependency wire-up automatically.  A lot of people are already writing a lot of useful material about Dependency Injection and Inversion of Control.  A blog search on any of these frameworks should reveal a lot of guidance.  I’m not going to go into details.

Transitive Dependencies

Transitive dependencies are slightly less evil than opaque dependencies, but there are times when you might want to use them.

A dependency is transitive when it is assigned opaquely by a transparent factory.  This is NASA Doctor speak for a constructor with a service locator:

public class BusinessService
{
    
private readonly IDataAccess _dataAccess;

    public BusinessService()
    {
        _dataAccess = Container.Resolve<
IDataAccess>();
    }
}

In the above example, Container can create (a la Factory pattern) an instance of the DataAccess class, or it can provide one that it is already holding on to (how long it holds on depends of the configured lifestyle, eg: per web request, per thread, etc).

You could re-write the above test using a transitive dependency and achieve some of the same results:

[Test]
public void TestCase()
{
    
FakeDataAccess fakeDataAccess = new FakeDataAccess();
    fakeDataAccess.ExpectedTotalOfOrders = 100m;

    Container.Configure<IDataAccess>(fakeDataAccess);

    BusinessService businessService = Container.Resolve<BusinessService>();

    Customer customer = new Customer(“Bob”);
    
Order order = new Order(customer);

    businessService.ApplyDiscount(order);

    Assert.AreEqual(11m, order.DiscountRate);
}

This is really a pattern that you might avoid though, especially for testing.  There’s no need to jump through the extra hoops when a constructor and a sprinkling of dependency injection will get you just as far, and with cleaner, more self-evident code.

Self-Documenting API

Self-evident or self-documenting API’s are a side effect of transparent dependencies.  A class’s dependencies are obvious to a reader when he can discover them from the class’s API.

For example, which of the following two lines of test code better document BusinessService’s dependency:

BusinessService businessService = Container.Resolve<BusinessService>();

or:

BusinessService businessService = new BusinessService(dataAccess);

Also, consider the dependency discoverability that you get through IntelliSense.  The first example will present you with a default constructor with no arguments, and the second will present you with a constructor that takes an IDataAccess.  The second example leads to greater explicitness and self-documentation, which makes the code more learnable.

Wrap-Up

All this dependency injection stuff is about making something easier.  Once you start recognizing the dependencies in your code, you start seeing all the little gotchas the make unit testing efforts more difficult.  If you get rid of the unnecessary opaque dependencies, and the automate the dependency wire-up with a tool, then you’ve effectively crossed one of the tougher agile development chasms… which will ultimately lead you to yet another chasm :)

I find it helpful to contemplate and then devour as many Reese’ Peanut Butter Cups as possible as a warm up to dependency inversion programming exercises.  Maybe you could benefit from this practice, too!  :)

This entry was posted in Agile, Design. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

Leave a Reply