Lowry Media
Interfaces and Dependencies
Jul 24, 2008 10:58 PM
In a previous article, I discussed the benefits of passing interfaces as parameters to a method instead of using concrete classes. Now I’m going to discuss other ways in which using interfaces can help future-proof your code, make it testable, and more extensible.

First, let’s define some terms. A dependency is something that code depends on in a class. For example, a business logic layer [usually] depends on calls to a data-access layer. Take this code as an example:

public static class ArticleService
{
    public static IList<Article> GetActive()
    {
        var articles = ArticleRespository.Get();
        return articles.Where(article => article.IsActive).ToList();
    }
}

This simple article service calls the article repository (the data-access layer), returns a list of articles, and then filters them based on the logic that we only want the active articles. A few things stand out with this code. First, we have a static dependency on the article repository; they are tightly coupled. If we need to switch from using SQL in the data-access layer to XML-based storage, either we will have to completely rewrite the ArticleRepository.Get() method, or we will have to write a new method and then change the GetActive() method to point to that one instead. The service knows too much about the repository.

Additionally, the service itself is static. The calling code of the article service class looks like this:

private void BindArticles()
{
    uxArticleView.DataSource = ArticleService.GetActive();
    uxArticleView.DataBind();
}

If you wanted to write a unit test to ensure that all active articles were being returned from the article service, how would you do it? Well, for the purposes of this article, you can’t (you could use something like TypeMocks). The static dependencies between all of these classes would force your unit test to have to set up a database connection. It probably can’t even do that because no connection strings are being passed into the repository.

Static dependencies are usually bad. They make unit testing extremely difficult and can cause maintenance nightmares down the road. So how do we fix this situation?

First, let’s rewrite our classes to depend on interfaces. Here is our article service interface:

public interface IArticleService
{
    IList<Article> GetActive();
}

And our article repository interface:

public interface IArticleRepository
{
    IList<Article> Get();
}

Now we can rewrite the article service to implement its interface:

public class ArticleService : IArticleService
{
    public IList<Article> GetActive()
    {
        var articles = ArticleRespository.Get();
        return articles.Where(article => article.IsActive).ToList();
    }
}

And we can refactor again to remove the static dependency. We do this by overloading the constructor for the service class:

public class ArticleService : IArticleService
{
    private readonly IArticleRepository _articleRepository;
 
    public ArticleService(IArticleRepository articleRepository)
    {
        _articleRepository = articleRepository;
    }
 
    public IList<Article> GetActive()
    {
        var articles = _articleRepository.Get();
        return articles.Where(article => article.IsActive).ToList();
    }
}

As you can see, the static call to the repository has been replaced by an interface call. In essence, we are saying that the article service depends on the article repository, so when you create the article service, you must pass in a class that implements IArticleRepository.

How does this work? Well, if a class implements an interface, it must implement all the methods of the interface. This means that we can call the Get() method and the code that runs will be whichever class you chose to pass in the constructor. In our example, I talked about how switching the storage from SQL to XML. Let’s see what would happen using interfaces. First, let’s define a SQL implementation:

public class ArticleSqlRepository : IArticleRepository
{
    public IList<Article> Get()
    {
        //define SqlConnection
        //call the database
        //fill out the article list
        return articles;
    }
}

Our calling code has now changed. Let’s review:

private void BindArticles()
{
    IArticleService articleService = new ArticleService(new ArticleSqlRepository());
    uxArticleView.DataSource = articleService.GetActive();
    uxArticleView.DataBind();
}

As you can see, the article service is defined by passing in an instance of the article SQL repository. This will now compile and work perfectly. Additionally, it is extremely easy to change from SQL to XML. Simply create a new class and pass that in:

public class ArticleXmlRepository : IArticleRepository
{
    public IList<Article> Get()
    {
        //define XmlReader
        //open the xml file
        //read the xml into the article list
        return articles;
    }
}

private void BindArticles()
{
    IArticleService articleService = new ArticleService(new ArticleXmlRepository());
    uxArticleView.DataSource = articleService.GetActive();
    uxArticleView.DataBind();
}

Our work is still not over. The calling code is a bit ugly, and having to instantiate services and repositories all the time will be take performance hit. Additionally, any changes to the dependencies would require a recompile which isn’t a huge issue, but still not ideal.

In the next article, I will cover dependency injection and how we can use it to automatically resolve the dependencies through a configuration file. Play around with the examples above (if you need to) to get a feel for it, and the next article will make a lot more sense.
Return to Previous Page
Comments
Comment posted on Jul 25, 2008 1:03 AM
Hmmm
You don't need all this interface crap if you just make a decision whether to use XML or SQL. Sheeesh!
Hmmm
Comment posted on Jul 25, 2008 1:11 AM
Brian
SQL it is!
In all seriousness, I use this example because it happened to me at a previous employer.
Brian
Comment posted on Jul 25, 2008 2:59 AM
Christian Sparre
@Hmmm

It's nice not beeing bound to a specific data store. I use the popular BlogEngine.NET on slyngelstat.dk and there is both an SQL and an XML provider for storing posts etc. And I believe in newer versions, that it has actually been extended to support others as well.

And it does not take that much more time implementing a simple provider pattern that lets users of your framework develop additional providers. Think about a hosted environment, maybe you don't have access to an MSSQL server, maybe MySQL is the only db supported? Wouldn't it be nice to be able to use the application anyway?

--
Christian
Christian Sparre
Comment posted on Jul 25, 2008 11:43 AM
Mike
I bet Hmmm doesn't even bother with "data-access layer crap" and just makes calls directly to SQL. Perhaps Hmmm doesn't like "object-oriented crap" or "design pattern crap" either.
Mike
Comment posted on Jul 25, 2008 11:48 AM
Mike
Sorry, Brian. I was so busy commenting on Hmmm's short-sightedness that I forgot to mention that I enjoyed your article. It was very well written and nicely explained the benefits of using interfaces to make code more extensible. I, like you, have had to make similar changes that would have been far easier with this style of architecture.
Mike
Comment posted on Jul 25, 2008 12:26 PM
Brian
Mike,

Thanks for the feedback. While its true that a little more effort goes into architecting a site in this manner, it really doesn't take too much longer once you get the hang of it (especially if you use ReSharper). I think the benefits far outweigh the possible and probable long-term issues.
Brian
Comment posted on Jul 25, 2008 1:12 PM
Dan
Hey Brian, this is a great pattern. In our group, we have adopted a slight modification wherein the default constructor creates a new instance of the repository. The calling code is a little simpler as you only need to update the constructor when changing from SQL to XML, for instance. Following your example:

public ArticleService()
{
_articleRepository = new ArticleSqlRepository();
}

We also use the overloaded constructor when testing using a mock framework.
Dan
Comment posted on Jul 25, 2008 1:20 PM
Brian
Dan,

I agree with you. My intentions of this article was to pave the path for dependency injection and show how using it can be extremely powerful. It sounds like your group is not too far from using it as you already have an overloaded constructor that takes an instance of the repository.

I like the idea of using the default constructor to load a default implementation of the repository.
Brian
Comment posted on Jul 25, 2008 1:37 PM
Mike
I use ReSharper and I love it and recommend it.
Mike
Comment posted on Jul 28, 2008 4:48 PM
Kyle
Great article. The key is that you explained it in a very simple manner, something that others often make overly complex when explaining it. I really like that.

JP Boodhoo's opinion is to never rely on concrete implementations if you can help it - always depend on interfaces. I'm of the same opinion.

@Hmmm, your shortsightedness is amazing. There has been no small number of times when I was asked to allow a new type of database implementation to be used in the product. You cannot get that if you hard-code your implementation as you suggested. Rather, you get it by having the ctor take in the interface object exactly as Brian stated, then you can use an IoC container (or even just store the value in XML and use reflection to dynamically load the type) to allow any user to input ANY type of database implementation. The fact is, as long as your program can query the database and use it, the specific implementation is completely irrelevant.
Kyle
Comment posted on Jul 28, 2008 4:49 PM
Kyle
If I made multiple posts, I apologize. As it turns out, in Firefox, the statement about the comment being successfully posted does not come up. If it was unable to be posted in Firefox, this should also be noted (in Firefox).
Kyle
Comment posted on Jul 28, 2008 5:01 PM
Brian
Thanks for the feeback, Kyle. I use Firefox 3 and have seen that glitch before... not really sure what it is and its hard to reproduce, but I'm posting in Firefox right now.
Brian
Comment posted on Jul 29, 2008 11:29 PM
Hmmm
Yeah, throw out transactions, referential integrity, validation, etc...
So you can have all your data sitting in a big blog of XML

XML IS NOT A DATABASE!

You shouldn't be changing your storage from SQL to XML, quite simple. Fine if you need to export from your database to XML, but changing the storage itself because your manager read that "XML is great!" in PHB weekly is just crazy.

Hmmm
Comment posted on Jul 29, 2008 11:38 PM
Brian
Hmmm, I'm not sure why you are upset as I've yet to read a comment that says XML is preferred over a DB.

Fact of the matter is, you've completely missed the point - this post is just an example of how/why to use dependency injection. Maybe your manager won't make a decision like switching to XML, but I assure you there will be some other implementation that needs to be swapped out. If you leave your code flexible as I have described, then you won't run into that situation.

What if I told you that the repository needed to be switched from database access calls to web service calls?

Would that make you feel better?
Brian
Comment posted on Jul 30, 2008 4:47 AM
Hmmm
Yes, that make me feel better :)
Hmmm
Add Comment