Steve Smith's Blog

Musings on Software and the Developer Community

Avoiding Dependencies

I gave a one day class to about 20 developers today introducing Microsoft .NET, C#, and ASP.NET. As it was only one day and there were no hands-on labs, coverage was necessarily cursory, but overall things went very well.

In the course of discussing the Base Class Library and specifically the areas of logging and sending emails (System.Diagnostics and System.Net), I was careful to emphasize to the class that they should definitely avoid making direct calls to these namespaces' members for their logging and emailing needs.  Instead, they should encapsulate their dependency on these classes using one of two patterns (and I'm inclined to favor the latter).  Specifically with regard to email, I gave the example that testing the application in a staging environment might really send out emails if there were no way to swap out that functionality.  It was clear from their reactions that several of the developers in the room could directly relate to this scenario.

Before showing the fix, let me demonstrate the problem by way of example.  Let's say you have a need to send emails in your application.  You might have the following code inside a Cart class as part of an online store.

Tightly Coupled Code

   1: public void Checkout()
   2: {
   3:     // Do some other stuff
   4:  
   5:     System.Net.Mail.MailMessage myMessage =
   6:         new MailMessage("store@acme.com",
   7:             "someuser@domain.com",
   8:             "Order Confirmation",
   9:             "Your Order Was Received.");
  10:     SmtpClient mySmtpClient = new SmtpClient("localhost");
  11:     mySmtpClient.Send(myMessage);}
  12: }

This works.  It's simple.  The problem is, it's quite inflexible and it's tightly coupled to System.Net.Mail.  If you have code like this all over your application, and you find a need to switch to another class for sending emails (which anyone who depended on System.Web.Mail should relate to, as it's been deprecated in favor of System.Net.Mail now), you'll have to touch many different parts of your application to make that one change.  That definitely violates the DRY principle.

Facade Pattern (reference)

Create a simple wrapper of the functionality required, exposing only those methods needed by your application.  This has the effect of simplifying the API as well as limiting the dependency on the underlying class to one location.  The resulting wrapper need not be static, but if we take a very simple example that sends an email, it might look like this:

   1: public static class Mailer
   2: {
   3:     public static void SendMail(string To, string From, 
   4:         string Subject, string Body)
   5:     {
   6:         System.Net.Mail.MailMessage myMessage =
   7:             new MailMessage(From, To, Subject, Body);
   8:         SmtpClient mySmtpClient = new SmtpClient("localhost");
   9:         mySmtpClient.Send(myMessage);
  10:     }
  11: }

With this wrapper class in place, the original tightly coupled code could be written simply as follows:

   1: public void Checkout()
   2: {
   3:     // Do some other stuff
   4:  
   5:     Mailer.SendMail("someuser@domain.com", "store@acme.com",
   6:         "Order Confirmation", "Your Order Was Received.");
   7: }

Strategy Pattern (reference)

The Strategy pattern essentially describes one of the most common techniques for performing Dependency Injection.  Using the Strategy pattern to eliminate the dependency on System.Net.Mail, we would define an interface and then push that interface into the constructor of the class that currently is carrying the dependency.  So if we imagine that this Checkout() method resides on a Cart class, we would modify the Cart class to include a private member variable of the interface's type and create one or more constructors allowing this interface to be passed in when the object is created.  Within the constructor, the local instance of the interface is assigned to the one being passed in.  This is rather more involved, but far more powerful, than the simple static wrapper class approach, and has other benefits as well (like support for swapping out implementations without having to rebuild the application).

Let's start with the interface.  All we need it to do at the moment is send email, so we'll call it ISendEmail.

   1: public interface ISendEmail
   2: {
   3:     void SendMail(string To, string From, string Subject, string Body);
   4: }

Now we can create a class that implements this interface.  The Mailer class nearly does so - removing the static keywords does the trick (and noting adding the reference to the dependency, of course).  We'll also rename it so it's clear that it really is sending mails via Smtp.

   1: public class LiveSmtpMailer : ISendEmail
   2: {
   3:     public void SendMail(string To, string From, string Subject, string Body)
   4:     {
   5:         System.Net.Mail.MailMessage myMessage =
   6: new MailMessage(From, To, Subject, Body);
   7:         SmtpClient mySmtpClient = new SmtpClient("localhost");
   8:         mySmtpClient.Send(myMessage);
   9:     }
  10: }

Next we need to modify the Cart to accept an ISendEmail instance via its constructor.

   1: public class Cart
   2: {
   3:     private ISendEmail emailProvider;
   4:     public Cart()
   5:     {
   6:         emailProvider = new LiveSmtpMailer();
   7:     }
   8:  
   9:     public Cart(ISendEmail emailProvider)
  10:     {
  11:         this.emailProvider = emailProvider;
  12:     }
  13: }

Notice that the parameterless constructor now sets the ISendEmail local instance to LiveSmtpMailer, so its behavior remains unchanged by default.  If you have existing code that has hard dependencies on concrete implementations, you can leave their funtionality in place using this technique, but still provide the capability to alter the behavior by adding additional constructor overloads (or, alternately, property setters).

At this point we're done.  But for the latter case let's go one step further and say we want to write a test for Checkout().  In the original and in the Facade pattern implementation, there is no way to remove the dependency on System.Net.Mail from the code as it is written.  Thus, any tests written would need to be hacked to look for Smtp connection exceptions, or worse, they might actually send out emails.  Compare that with the Strategy / Dependency Injection approach, which can easily be tested by mocking ISendEmail or by creating a simple test stub, like the following.

   1: public class TestStubEmailer : ISendEmail
   2: {
   3:     public int MessagesSent;
   4:     public string LastMessageTo;
   5:     public string LastMessageFrom;
   6:     public string LastMessageSubject;
   7:     public string LastMessageBody;
   8:  
   9:     public void SendMail(string To, string From, string Subject, string Body)
  10:     {
  11:         MessagesSent++;
  12:         LastMessageTo = To;
  13:         LastMessageFrom = From;
  14:         LastMessageSubject = Subject;
  15:         LastMessageBody = Body;
  16:     }
  17: }

Writing the test is now a simple matter.

   1: [Test]
   2: public void CheckOutTest()
   3: {
   4:     string testTo = "test@test.com";
   5:     string testFrom = "test2@test2.com";
   6:     string testSubject = "Test Subject";
   7:     string testBody = "Test Body";
   8:     TestStubEmailer myEmailer = new TestStubEmailer();
   9:     Cart myCart = new Cart(myEmailer);
  10:     myCart.Checkout();
  11:     Assert.AreEqual(testTo, myEmailer.LastMessageTo);
  12:     Assert.AreEqual(testFrom, myEmailer.LastMessageFrom);
  13:     Assert.AreEqual(testSubject, myEmailer.LastMessageSubject);
  14:     Assert.AreEqual(testBody, myEmailer.LastMessageBody);
  15:     Assert.AreEqual(1, myEmailer.MessagesSent);
  16: }

Not Just For Testing

But there's more benefit from the Strategy pattern approach than just testing.  In fact, let me revisit the initial problem being discussed, which is that the application should not really send out emails when it is being tested, but there should be some way for the developers to know that emails would have been sent.  Using the Strategy pattern approach (and especially if you couple it with an IoC container to make things easy), it would be a simple matter to have the default implementation of ISendEmail depend on a configuration setting.  In a Stage environment, an implementation of ISendEmail that actually just logs the messages to an event log could be configured, while in production the configuration could wire up the actual LiveSmtpMailer class.  Never again would you need to worry about accidentally sending emails out to customers while testing the application from the stage server.  Clearly the result is more flexible code that is easier maintain, configure, and test.

It's only been in the last year or so that I've really fallen in love with the Strategy pattern.  Capabilities like this, as well as the ability to potentially swap out implementations using configuration or IoC containers, make it a much more flexible approach than simply inserting a concrete Facade class between the dependency and its consumers (which is how I typically approached the problem previously).  If you find yourself struggling to remove dependencies in your application, the Strategy pattern as shown here may be helpful for you.

Update: Part 2 wraps up with the Strategy Pattern With Ninject

kick it on DotNetKicks.com

kick it on DotNetKicks.com

Thursday, 18 September 2008

Comments

 avatar

Kamran Shahid said on 19 Sep 2008 at 12:38 AM

Nice One


 avatar

Andrei Rinea said on 19 Sep 2008 at 9:26 AM


ssmith avatar

ssmith said on 19 Sep 2008 at 10:43 AM

@andrei,

I've used similar tools to "catch" emails but that requires greater configuration of the environment, eliminating XCopy deployment. It's another moving part that you have to be sure to install on a new developer's machine or a new test server, so it's not as good, in my opinion, as replacing the mail functionality with something else in the code itself.


 avatar

Chris Marisic said on 19 Sep 2008 at 11:04 AM

Software architecture is always a good thing especially going full out with loosely coupling with IoC patterns.

If you've considered writing a follow up to this I would recommend doing your follow up implementing this using either Unity or Structure Map.


ssmith avatar

ssmith said on 19 Sep 2008 at 11:23 AM

@chris,

Yeah, I'm planning on following up with Unity, StructureMap, and/or Ninject. Thanks for the comment!


 avatar

Chad Myers said on 19 Sep 2008 at 11:47 AM

Good post.

Depending on the situation, you might even want to go one step further and remove the concept of "email" altogether and use a more generic, abstract concept such as "Notify"/"Notification".

Like I said, it depends whether this would help or not. On larger systems, you should consider this because you may, at a later date, need to determine the user's notification preferences and send them an HTML or text email, or maybe even a twitter or SMS message, etc, etc, etc.

This is part of the Open-Closed Principle. Depend upon abstractions, not details. In this case, the details of "email" are seeping through the abstraction (ISendEmail).

Again, it depends. In this case, it's OK that email details are seeping through because that's all we really want to do here and it's unlikely we'll do anything different.

Just something to consider. Again, good post. Thanks!


ssmith avatar

ssmith said on 19 Sep 2008 at 12:24 PM

@Chad,

Thanks! I agree, the fact that I'm depending on SMTP in this case is seeping into my abstraction (ISendEmail). In this case, it works since I was trying to make a simple point, but in a more complex environment I totally agree a more abstract notification or messaging interface would make sense.


 avatar

Andrei Rinea said on 19 Sep 2008 at 4:08 PM

@ssmith : Sorry about the comment, I posted two comments but just the last one (the one above a few scrolls) got published.

My first (and unpublished) comment :

I was thinking that a complementary way to test the behavior (testing also the TCP/IP transport) was this SMTP solution. I did not say that it replaces this test methodology. :)


 avatar

Edward J. Stembler said on 19 Sep 2008 at 6:15 PM

I've always preferred the Provider pattern instead, where the concrete provider (even a default) is specified via configuration. That way nothing is hard-coded, including the default.

Nowadays, though, I use a combination of Unity + Provider model. Or just Unity if I'm feeling especially lazy.

On the other hand, none of these abstractions are necessary in dynamic languages such as Python and Ruby. I like having the smaller granularity. No heavy interfaces or base classes. Of course, you can simulate duck typing in C# but it's really a hack in my opinion.


 avatar

nefajciar said on 19 Sep 2008 at 6:41 PM

Steve Smith, listen to me...

you are a GEM! there are tons of DI/IoC articles that are so complicated that even authors do not know in the end what they wanted to say ;)

neither do I

but this one, althought not in part 5 like many, is gazillion times better, because it striked me!

wish you will be writing more, as you have a gift of explaining, which many developers do not posses!

excellent job!


 avatar

austin avrashow said on 20 Sep 2008 at 11:08 AM

well done. not theoretical and thus skeletal as many design pattern explanations are.

you need to cover more patterns in this start-with-a-problem-preventing-directly-coding for the solution.

i would subscribe to that article series. though i concur that this article (and others in this hoped-for series) should have a follow-up article on using real-world tools to achieve this pattern. and why they help.


Leave a Comment

Please join the discussion and share your thoughts.