CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Karl Seguin

.NET From Ottawa, Ontario - http://twitter.com/karlseguin/

December 2007 - Posts

  • Foundations of Programming - pt 7 (sorta) - ActiveRecord

    You may be wondering what happened to part 6. Well, it's still being worked on and should be available early next week.

    I wasn't sure if there would be a part 7 and if so what it would be about - but I was heavily considering writing about an ActiveRecord implementation. Turns out that Kent Sharkey, beat me to it with his overview of Subsonic on DotNetSlackers.

    I want to spend just a couple paragraphs trying to tie in Kent's article with the Foundations series.

    In Part 3 we talked about persistence and manually wrote our data access layer and mapping code. As I said at the time, doing that manually is fine for simple cases with few domain objects and straightforward mapping, but can quickly get out of hand. To solve the problem and keep us efficient, we can leverage existing O/R mappers to do all the mundane work. Some O/R mappers, like NHibernate which we'll look at in Part 6, are unbelievably flexible and can be used to address very large systems (as systems grow in size, it's common for their impedance mismatch to grow as well, which makes a flexible tool all the more important). Of course, NHibernate isn't the simplest thing to configure and it has a relatively steep learning curve.

    An alternative approach is to use the ActiveRecord (AR) design pattern. AR is still considered an O/R mapper, but it's specifically targeted at more straightforward applications (which likely represent 95% of the work we're all doing). AR is one of the two components that has made Ruby on Rails so popular and productive (the other is their first class MCV pattern implementation). There are two popular .NET implementations that I'm aware of: Subsonic and Castle ActiveRecord. Both the Castle and Subsonic line of products are open source, and come with a full range of products (MVC, ActiveRecord, Scaffolding, utility functions, etc) that integrate nicely with each other. Interestingly, Castle is implemented on top of NHibernate - which gives you a hit about just how flexible NHibernate really is.

    With Castle ActiveRecord, you take your domain object and decorate it with attributes. You add the ActiveRecordAttribute to your class, and the PropertyAttribute to your properties. So, if you have a Car class with a Name property which are properly set up, Castle will automatically map to a table named Car and a column named Name.

    It turns out that ActiveRecord implementations can be setup within minutes and handle 99% of all your data access needs. They can make you unbelievably productive by providing functionality and performance above that of DataSets, while maintaining your rich domain layer and allow you to easily write unit tests.

    It's still worthwhile to learn a more complex framework like NHibernate for a couple reasons. First, once you're used to it, it too can be set up quickly and efficiently (avoiding upfront learning is a losing strategy). Secondly, NHibernate is a lot closer to important fundamental concepts. With AR implementations, a lot of the details are taken care of for you - which is great in most cases, but doesn't teach you nearly as much. If you spend some time with NHibernate, you'll learn about first and second level caching, identity map, concurrency and locking and various other concepts relating to persistence.

    Enjoy Kent's article, and I hope take the time to download and play with either Subsonic or Castle.

    Happy holidays to all our CB readers and your families. 

     

     

    Posted Dec 28 2007, 10:12 AM by karl with 18 comment(s)
    Filed under:
  • Foundations of Programming - Part 5 – Unit Testing

    Throughout this series we've talked about the importance of testability and have looked at techniques to make it easier to test our system. It goes without saying that a major benefit of writing tests for our system is the ability to deliver a better product to our client. Although this is true for unit tests as well, the main reason I write unit tests is that nothing comes close to improving the maintainability of a system as much as a properly developed suite of unit tests. You'll often hear unit test advocates speak of how much confidence unit tests give them – and that's what it's really all about. On a project I'm currently working on, we're continuously making changes and tweaks to improve the system (functional improvements, performance, refactorings, you name it). Being that it's a fairly large system, we're sometimes asked to make a change that flat out scares us. Is it doable? Will it have some weird side effect? What bugs will be introduced? Without unit tests, we'd likely refuse to make the higher risk changes. But we know, and our client knows, that it's the high risk changes that have the most potential for success. It turns out that having 700+ unit tests which run within a couple minutes lets us rip components apart, reorganize code, and build features we never thought about a year ago, without worrying too much about it. Because we are confident in the completeness of the unit tests, we know that we aren't likely to introduce bugs into our production environment – our changes might still cause bugs but we'll know about them right away.

    Unit tests aren't only about mitigating high-risk changes. In my programming life, I've been responsible for major bugs caused from seemingly low-risk changes as well. The point is that I can make a fundamental or minor change to our system, right click the solution, select "Run Tests" and within 2 minutes know where we stand.

    Why wasn't I unit testing 3 years ago?
    For those of us who've discovered the joy of unit testing, it's hard to understand why everyone isn't doing it. For those who haven't adopted it, you probably wish we'd shut up about it already. For many years I'd read blogs and speak to colleagues who were really into unit testing, but didn't practice myself. Looking back, here's why it took me a while to get on the bandwagon:

    1. I had misconception about the goals of unit testing. As I've already said, unit testing does improve the quality of a system, but it's really all about making it easier to change / maintain the system later on. Furthermore, if you go to the next logical step and adopt Test Driven Development, unit testing really becomes about design. To paraphrase Scott Bellware, TDD isn't about testing because you're not thinking as a tester when doing TDD – you're thinking as a designer.
    2. Like many, I used to think developers shouldn't write tests! I don't know the history behind this belief, but I now think this is just an excuse for lazy programmers. Testing is the process of both finding bugs in a system as well as validating that it works as expected. Maybe developers aren't good at finding bugs in their own code, but they are the best suited to make sure it works the way they intended it to (and clients are best suited to test that it works like it should (if you're interested to find out more about that, I suggest you research Acceptance Testing and FitNess (http://fitnesse.org/)). Even though unit testing isn't all that much about testing, developers who don't believe they should test their own code simply aren't accountable.
    3. Testing isn't fun. Sitting in front of a monitor, inputting data and making sure everything's ok sucks. But unit testing is coding, which means there are a lot of challenges and metrics to gauge your success. Sometimes, like coding, it's a little mundane, but all in all it's no different than the other programming you do every day.
    4. It takes time. Advocates will tell you that unit testing doesn't take time, it SAVES time. This is true in that the time you spend writing unit tests is likely to be small compared to the time you save on change requests and bug fixes. That's a little too Ivory Tower for me. In all honesty, unit testing DOES take a lot of time (especially when you just start out). You may very well not have enough time to unit test or you client might not feel the upfront cost is justified. In these situations I suggest you identifier the most critical code and test it as thoroughly as possible – even a couple hours spent writing unit tests can have a big impact.

    Ultimately, unit testing seemed like a complicated and mysterious thing that was only used in edge cases. The benefits seemed unattainable and timelines didn't seem to allow for it anyways. It turns out it took a lot of practice (I had a hard time learning what to unit test and how to go about it), but the benefits were almost immediately noticeable.

    The Tools

    With StructureMap already in place from the last part, we need only add 2 frameworks and 1 tool to our unit testing framework: nUnit, RhinoMocks and TestDriven.NET.

    TestDriven.NET is an addon for Visual Studio that basically adds a "Run Test" option to our context (right-click) menu. We won't spend any time talking about it. The personal license of TestDriven.NET is only valid for open source and trial users. Don't worry too much if the licensing doesn't suite you, nUnit has its own test runner tool, just not integrated in VS.NET. (http://www.testdriven.net/) (Resharper users can also use its built-in functionality).

    nUnit is the testing framework we'll actually use. There are alternatives, such as mbUnit, but I don't know nearly as much about them as I ought to. (http://www.nunit.org/)

    RhinoMocks is the mocking framework we'll use. In the last part we manually created our mock – which was both rather limited and time consuming. RhinoMocks will automatically generate a mock class from an interface and allow us to verify and control the interaction with it. (http://www.ayende.com/projects/rhino-mocks.aspx)

    nUnit
    The first thing to do is to add a reference to the nunit.framework.dll and the Rhino.Mocks.dll. My own preference is to put my unit tests into their own assembly. For example, if my domain layer was located in CodeBetter.Foundations, I'd likely create a new assembly called CodeBetter.Foundations.Tests. This does mean that we won't be able to test private methods (more on this shortly). In .NET 2.0+ we can use the InternalsVisibleToAttribute to allow the Test assembly access to our internal method (we'd open Properties/AssemblyInfo.cs and add [assembly: InternalsVisibleTo("CodeBetter.Foundations.Tests")] – which is something I typically do.

    There are two things you need to know about nUnit. First, you configure your tests via the use of attributes. The TestFixtureAttribute is applied to the class that contains your tests, setup and teardown methods. The SetupAttribute is applied to the method you want to have executed before each test – you won't always need this. Similarly, the TearDownAttribute is applied to the method you want executed after each test. Finally, the TestAttribute is applied to your actual unit tests. (There are other attributes, but these 4 are the most important). This is what it might look like:

     
    using NUnit.Framework;
    
    [TestFixture]
    public class CarTests
    {
       [SetUp]
       public void SetUp()
       {
          //todo
       }
       [TearDown]
       public void TearDown()
       {
          //todo
       }
       [Test]
       public void SaveThrowsExceptionWhenInvalid() 
       {
          //todo
       }
       [Test]
       public void SaveCallsDataAccessAndSetsId()
       {
          //todo
       }
       //more tests
    }
    

    Notice that each unit test has a very explicit name – it's important to state exactly what the test is going to do, and since your test should never do too much, you'll rarely have obscenely long names.

    The second thing to know about nUnit is that you confirm that your test executed as expected via the use of the Assert class and its many methods. I know this is lame, but if we had a method that took a param int[] numbers and returned the sum, our unit test would look like:

    [TestFixture]
    public class MathUtilityTester
    {
      [Test]
      public void MathUtilityReturnsZeroWhenNoParameters()
      {
         Assert.AreEqual(0, MathUtility.Add());
      }
      [Test]
      public void MathUtilityReturnsValueWhenPassedOneValue()
      {
         Assert.AreEqual(10, MathUtility.Add(10));
      }
      [Test]
      public void MathUtilityReturnsValueWhenPassedMultipleValues()
      {
         Assert.AreEqual(29, MathUtility.Add(10,2,17));
      }
      [Test]
      public void MathUtilityWrapsOnOverflow()
      {
         Assert.AreEqual(-2, MathUtility.Add(int.MaxValue, int.MaxValue));
      }
    }
    

    You wouldn't know it from the above example, but the Assert class has more than one function, such as Assert.IsFalse, Assert.IsTrue, Assert.IsNull, Assert.IsNotNull, Assert.AreSame, Assert.AreNotEqual, Assert.Greater, Assert.IsInstanceOfType and so on.

    What is a Unit Test
    Unit tests are methods that test behavior at a very granular level. Developers new to unit testing often let the scope of their tests grow. Most unit tests follow the same pattern: execute some code from your system and assert that it worked as expected. The goal of a unit test is to validate a specific behavior. You might have noticed that the above two examples use multiple unit tests on the same function. We don't want to write an all encompassing test for Save, but rather want to write a test for each of the behavior it contains – failing when the object is in an invalid state, calling our data access's Save method and setting the id, and calling the data access's Update method. It's important that our unit test pinpoint a failure as best possible.

    I'm sure some of you will find the 4 tests used to cover the MathUtility.Add method a little excessive. You may think that all 4 tests could be grouped into the same one – and in this minor case I'd say whatever you prefer. However, when I started unit testing, I fell into the bad habit of letting the scope of my unit tests grow. I'd have my test which created an object, executed some of its members and asserted the functionality. But I'd always end up saying, well as long as I'm here, I might as well throw in a couple extra asserts to make sure these fields are set the way they ought to be. This is very dangerous because a change in your code could break numerous unrelated tests – definitely a sign that you've given your tests too little focus.

    This brings us back to the topic about testing private methods. If you google you'll find a number of discussions on the topic, but the general consensus seems to be that you shouldn't test private methods. I think the most compelling reason not to test private methods is that our goal is not to test methods or lines of code, but rather to test behavior. This is something you must always remember. If you thoroughly test your code's public interface, then private methods should automatically get tested. Another argument against testing private methods is that it breaks encapsulation. We talked about the importance of information hiding already. Private methods contain implementation detail that we want to be able to change without breaking calling code. If we test private methods directly, implementation changes will likely break our tests, which doesn't bode well for higher maintainability. Here's a question for you: should we care that a change to a private method broke a test?

    ...

    ...

    Hopefully you're starting to get my drift, the answer is NO. What we care about is whether the behavior/functionality is broken, which our tests against the public API will do.

    Mocking
    To get started, it's a good idea to test simple pieces of functionality. Before long though, you'll want to test a method that has a dependency on an outside component – such as the database. For example, you might want to complete your test coverage of the Car class by testing the Save method. Since we want to keep our tests as granular as possible (and as light as possible – tests should be quick to run so we can execute them often and get instant feedback) we really don't want to figure out how we'll set up a test database with fake data and make sure it's kept in a predictable state from test to test. In keeping with this spirit, all we want to do is make sure that Save interacts property with the DAL. Later on we can unit test the DAL on its own. If Save works as expected and the DAL works as expected and they interact properly with each other, we have a good base to move to more traditional testing.

    In the previous part we saw the beginnings of testing with mocks. We were using a manually created mock class which had some pretty major limitations. The most significant of which was our inability to confirm that calls to our mock objects were occurring as expected. That, along with ease of use, is exactly the problem RhinoMock is meant to solve. Using RhinoMock couldn't be simpler, tell it what you want to mock (an interface or a class – preferably an interface), tell it what method(s) you expect to be called, along with the parameters, execute the call, and have it verify that your expectations were met.

    Before we can get started, we need to give RhinoMock access to our internal types. This is quickly achieved by adding [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] to our Properties/AssemblyInfo.cs file.

    Now we can start coding by writing a test to cover the update path of our Save method:

    using NUnit.Framework;
    
    [TestFixture]
    public class CarTest
    {
      [Test]   
      public void SaveCarCallsUpdateWhenAlreadyExistingCar()
      {     
         MockRepository mocks  = new MockRepository();
         IDataAccess dataAccess = mocks.CreateMock<IDataAccess>();
         ObjectFactory.InjectStub(typeof(IDataAccess), dataAccess);
    
         Car car = new Car();
         dataAccess.Update(car);
         mocks.ReplayAll();
    
         car.Id = 32;
         car.Save();
    
         mocks.VerifyAll();
         ObjectFactory.ResetDefaults();
      }
    }
    

    Once a mock object is created, which took 1 line of code to do, we inject it into our dependency injection framework (StructureMap in this case). When a mock is created, it enters record-mode, which means any subsequent operations against it, such as the call to dataAccess.UpdateCar(car), is recorded by RhinoMock. We exit record-mode by calling ReplayAll, which means we are now ready to execute our real code and have it verified against the recorded sequence. When we then call VerifyAll after having called Save on our Car object, RhinoMock will make sure that our actual call behaved the same as what we expected. In other words, you can think of everything before ReplayAll as stating our expectations, everything after it as our actual test code with VerifyAll doing the final check.

    If we were to change the test to something along the lines of (notice the extra dataAccess.Update call):

    using NUnit.Framework;
    
    [TestFixture]
    public class CarTest
    {
      [Test]   
      public void SaveCarCallsUpdateWhenAlreadyExistingCar()
      {         
         MockRepository mocks  = new MockRepository();
         IDataAccess dataAccess = mocks.CreateMock<IDataAccess>();
         ObjectFactory.InjectStub(typeof(IDataAccess), dataAccess);
    
         Car car = new Car();
         dataAccess.Update(car);
         dataAccess.Update(car);
         mocks.ReplayAll();
    
         car.Id = 32;
         car.Save();
    
         mocks.VerifyAll();
         ObjectFactory.ResetDefaults();
      }
    }
    

    RhinoMock would cause our test to fail and tell us that it didn't expect two calls to update.

    For the save behavior, the interaction is slightly more complex – we have to make sure the return value is properly handled by the Save method. Here's the test:

    using NUnit.Framework;
    
    [TestFixture]
    public class CarTest
    {
      [Test]   
      public void SaveCarCallsSaveWhenNew()
      {         
         MockRepository mocks  = new MockRepository();
         IDataAccess dataAccess = mocks.CreateMock<IDataAccess>();
         ObjectFactory.InjectStub(typeof(IDataAccess), dataAccess);
    
         Car car = new Car();
         Expect.Call(dataAccess.Save(car)).Return(389);
         mocks.ReplayAll();
    
         car.Save();
    
         mocks.VerifyAll();
         Assert.AreEqual(389, car.Id);
         ObjectFactory.ResetDefaults();
      }
    }
    

    Using the Expect.Call method allows us to specify the return value we want. Also notice the Assert.Equals we've added – which is the last step in validating the interaction. Hopefully the possibilities of having control over return values (as well as output/ref values) lets you see how easy it is to test for edge cases. Imagine that we changed our Save function to throw an exception if the returned id was invalid, our test would look like:

    using NUnit.Framework;
    
    [TestFixture]
    public class CarTest
    {
      private MockRepository _mocks;
      private IDataAccess _dataAccess;
    
      [SetUp]
      public void SetUp()
      {
         _mocks = new MockRepository();
         _dataAccess = _mocks.CreateMock<IDataAccess>();
         ObjectFactory.InjectStub(typeof(IDataAccess), _dataAccess);
      }
      [TearDown]
      public void TearDown()
      {
         _mocks.VerifyAll();
      }
    
      [Test, ExpectedException("CodeBetter.Foundations.PersistenceException")]   
      public void SaveCarCallsSaveWhenNew()
      {                  
         Car car = new Car();
         using (_mocks.Record())
         {
            Expect.Call(_dataAccess.Save(car)).Return(0);
         }
         using (_mocks.Playback())
         {
            car.Save();
         }     
      }
    }
    

    We've actually changed a lot. First, we've shown how nUnit ExpectedException attribute can be used to test for an exception. Secondly, we've extracted the repetitive code that creates, sets up and verifies the mock object into the SetUp and TearDown methods. Finally, we used a different, more explicit, RhinoMocks syntax for setting up our record and playback states - I generally prefer this syntax.

    More on nUnit and RhinoMocks
    So far we've only looked at the basic features offered by nUnit and RhinoMocks, but there's a lot more than can actually be done with them. For example, RhinoMocks can be setup to ignore the order of method calls, instantiate multiple mocks but only replay/verify specific ones, or mock some but not other methods of a class (a partial mock), or simply create a stub.

    Combined with a utility like NCover (http://www.ncover.com/), you can also get reports on your tests coverage. Coverage basically tells you what percentage of an assembly/namespace/class/method was executed by your tests. NCover has a visual code browser that'll highlight any un-executed lines of code in red. Generally speaking, I dislike coverage as a means of measuring the completeness of unit tests. After all, just because you've executed a line of code does not mean you've actually tested it. What I do like NCover for is to highlight any code that has no coverage. In other words, just because of line of code or method has been executed by a test, doesn't mean you're test is good. But if a line of code or method hasn't been executed, then you need to look at adding some tests.

    We've mentioned Test Driven Development briefly throughout this series. As has already been mentioned, Test Driven Development, or TDD, is about design, not testing. TDD means that you write your test first and then write corresponding code to make your test pass. In TDD we'd write our Save test before having any functionality in the Save method. Of course, our test would fail. We'd then write the specific behavior and test again. The general mantra for developers is red ? green ? refactor. Meaning the first step is to get a failing unit testing, then to make it pass, then to refactor the code as required.

    In my experience, TDD goes very well with Domain Driven Design, because it really lets us focus on the business rules of the system. If our client says tracking dependencies between upgrades has been a major pain-point for them, then we set off right away with writing tests that'll define the behavior and API of that specific feature. I recommend that you familiarize yourself with unit testing in general before adopting TDD.

     

    UI and Database Testing
    Unit testing your ASP.NET pages probably isn't worth the effort. The ASP.NET framework is complicated and suffers from very tight coupling. More often than not you'll require an actual HTTPContext, which requires quite a bit of work to setup. If you're making heavy use of custom HttpHandlers, you should be able to test those with quite a bit of ease.

     

    On the other hand, testing your Data Access Layer is possible and I would recommend it. There may be better methods, but my approach has been to maintain all my CREATE Tables / CREATE Sprocs in text files along with my project, create a test database on the fly, and to use the Setup and Teardown methods to keep the database in a known state. The topic might be worth of a future blog post, but for now, I'll leave it up to your creativity.

    Conclusion
    Unit testing wasn't nearly as difficult as I first thought it was going to be. Sure my initial tests weren't the best – sometimes I would write near-meaningless test (like testing that a plain-old property was working as it should) and sometimes they were far too complex and well outside of a well-defined scope. But after my first project, I learnt a lot about what did and didn't work. One thing that immediately became clear was how much cleaner my code became. I quickly came to realize that if something was hard to test and I rewrote it to make it more testable, the entire code became more readable, better decoupled and overall easier to work with. The best advice I can give is to start small, experiment with a variety of techniques, don't be afraid to fail and learn from your mistakes. And of course, don't wait until your project is complete to unit test – write them as you go!

    Posted Dec 20 2007, 08:22 AM by karl with 21 comment(s)
    Filed under:
  • Foundations of Programming - pt 4 – Dependency Injection

    It's common to hear developers promote layering as a means to provide extensibility. The most common example, and one I used in Part 2 when we looked at interfaces, is the ability to switch out your data access layer in order to connect to a different database. If your projects are anything like mine, you know upfront what database you're going to use and you know you aren't going to have to change it. Sure, you could build that flexibility upfront - just in case - but what about keeping things simple and You Aren't Going To Need IT (YAGNI)?

    I used to write about the importance of domain layers in order to have re-use across multiple presentation layers: website, windows applications and web services. Ironically, I've rarely had to write multiple front-ends for a given domain layer. I still think layering is important, but my reasoning has changed. I now see layering as a natural by-product of highly cohesive code with at least some thought put into coupling. That is, if you build things right, it should automatically come out layered.

    The real reason we're spending a whole part on decoupling (which layering is a high-level implementation of) is because it's a key ingredient in writing testable code. It wasn't until I started unit testing that I realized how tangled and fragile my code was. I quickly became frustrated because method X relied on a functional class Y which needed a database up and running. In order to avoid the headaches I went through, we'll first cover coupling and then look at unit testing in the next part.

    (A point about YAGNI. While many developers consider it a hard rule, I rather think of it as a general guideline. There are good reasons why you want to ignore YAGNI, the most obvious is your own experience. If you know that something will be hard to implement later, it might be a good idea to build it now, or at least put hooks in place. This is something I frequently do with caching, building an ICacheProvider and a NullCacheProvider implementation that does nothing, except provide the necessary hooks for a real implementation later on. That said, of the numerous guidelines out there, YAGNI, DRY and Sustainable Pace are easily the three I consider the most important.)

    Sneak Peak at Unit Testing
    Talking about coupling with respect to unit testing is something of a chicken and egg problem – which to talk about first. I think it's best to move ahead with coupling, providing we cover some basics about unit testing. Most importantly is that unit tests are all about the unit. You aren't focusing on end-to-end testing but rather on individual behavior. The idea is that if you test each behavior of each method thoroughly and test their interaction with one and other, you're whole system is solid. This is tricky given that the method you want to unit test might have a dependency on another class which can't be easily executed within the context of a test (such as a database, or a web-browser element). For this reason, unit testing makes use of mock classes – or pretend class.

    Let's look at an example, saving a car's state:

    public class Car
    {
       private int _id;     
       public void Save()
       {
          if (!IsValid())
          {
             //todo: come up with a better exception
             throw new InvalidOperationException("The car must be in a valid state");
          }
          if (_id == 0)
          {
             _id = DataAccess.CreateInstance().Save(this);
          }
          else
          {
             DataAccess.CreateInstance().Update(this);
          }
       }
       private bool IsValid()
       {
          //todo: make sure the object is in a valid state
          return true;
       }
    }

    To effectively test the Save method, there are three things we must do:

    1. Make sure the correct exception is thrown when we try to save a car which is in an invalid state,
    2. Make sure the data access' save method is called when it's a new car, and
    3. Make sure the Update method is called when it's an existing car.

    What we don't want to do (which is just as important as what we do want to do), is test the functionality of IsValid or the data access' Save and Update functions (other tests will take care of those). The last point is important – all we want to do is make sure these functions are called with the proper parameters and their return value (if any) is properly handled. It's hard to wrap your head around mocking without a concrete example, but mocking frameworks will let us intercept the Save and Update calls, ensure that the proper arguments were passed, and force whatever return value we want. Mocking frameworks are quite fun and effective....unless you can't use them because your code is tightly coupled.

    Not ALL coupling is bad
    In case you forgot from Part 1, coupling is simply what we call it when one class requires another class in order to function. It's essentially a dependency. All but the most basic lines of code are dependent on other classes. Heck, if you write string site = "CodeBetter", you're coupled to the System.String class – if it changes, your code could very well break. Of course the first thing you need to know is that in the vast majority of cases, such as the silly string example, coupling isn't a bad thing. We don't want to create interfaces and providers for each and every one of our classes. It's ok for our Car class to hold a direct reference to the Upgrade class – at this point it'd be overkill to introduce and IUpgrade interface. What isn't ok is any coupling to an external component (database, state server, cache server, web service), any code that requires extensive setup (database schemas) and, as I learnt on my last project, any code that generates random output (password generation, key generators). That might be a somewhat vague description, but after this and the next part, and once you play with unit testing yourself, you'll get a feel for what should and shouldn't be avoided.

    Since it's always a good idea to decouple your database from your domain, we'll use that as the example throughout this part.

    Dependency Injection
    In Part 2 we saw how interfaces can help our cause – however, the code provided didn't allow us to dynamically provide a mock implementation of IDataAccess for the DataAccess factory class to return. In order to achieve this, we'll rely on a pattern called Dependency Injection (DI). DI is specifically tailored for the situation because, as the name implies, it's a pattern that turns a hard-coded dependency into something that can be injected at runtime. We'll look at two forms of DI, one which we manually do, and the other which leverages a third party library.

    Constructor Injection
    The simplest form of DI is constructor injection – that is, injecting dependencies via a class' constructor. First, let's look at our DataAccess interface again and create a fake (or mock) implementation (don't worry, you won't actually have to create mock implementations of each component, but for now it keeps things obvious):

    internal interface IDataAccess
    {
       int Save(Car car);
       void Update(Car car);
    }
    internal class MockDataAccess : IDataAccess
    {
       private readonly List<Car> _cars = new List<Car>();
       public int Save(Car car)
       {
          _cars.Add(car);
          return _cars.Count;
       }
       public void Update(Car car)
       {         
          _cars[_cars.IndexOf(car)] = car;
       }
    }
    

    Although our mock's upgrade function could probably be improved, it'll do for now. Armed with this fake class, only a minor change to the Car class is required:

    public class Car
    {
       private int _id;
       private IDataAccess _dataProvider;
       public Car() : this(new SqlServerDataAccess())
       {
       }
       internal Car(IDataAccess dataProvider)
       {
          _dataProvider = dataProvider;
       }
       public void Save()
       {
          if (!IsValid())
          {
             //todo: come up with a better exception
             throw new InvalidOperationException("The car must be in a valid state");
          }
          if (_id == 0)
          {
             _id = _dataProvider.Save(this);
          }
          else
          {
             _dataProvider.Update(this);
          }
       }
       private bool IsValid()
       {
          //todo: make sure the object is in a valid state
          return true;
       }
    }
    

    Take a good look at the code above and follow it through. Notice the clever use of constructor overloading means that the introduction of DI doesn't have any impact on existing code – if you choose not to inject an instance of IDataAccess, the default implementation is used for you. On the flip side, if we do want to inject a specific implementation, such as a MockDataAccess instance, we can:

    public void AlmostATest()
    {
       Car car = new Car(new MockDataAccess());
       car.Save();
       if (car.Id != 1)
       {
          //something went wrong
       }
    }
    

    There are minor variations available – we could have injected an IDataAccess directly in the Save method or could set the private _dataAccess field via an internal property – which you use is mostly a matter of taste.

    Frameworks
    Doing DI manually works great in simple cases, but can become unruly in more complex situations. A recent project I worked on had a number of core components that needed to be injected – one for caching, one for logging, one for a database access and another for a web service. Classes got polluted with multiple constructor overloads and too much thought had to go into setting up classes for unit testing. Since DI is so critical to unit testing, and most unit testers love their open-source tools, it should come as no surprise that a number of frameworks exist to help automate DI. The rest of this article will focus on StructureMap, a Dependency Injection framework created by fellow CodeBetter blogger Jeremy Miller. (http://structuremap.sourceforge.net/)

    Before using StructureMap you must configure it using an XML file (called StructureMap.config) or by adding attributes to your classes. The configuration essentially says this is the interface I want to program against and here's the default implementation. The simplest of configurations to get StructureMap up and running would look something like:

    <StructureMap>
      <DefaultInstance PluginType="CodeBetter.Foundations.IDataAccess, CodeBetter.Foundations" 
                       PluggedType="CodeBetter.Foundations.SqlServerDataAccess, CodeBetter.Foundations" /> 
    </StructureMap>
    

    While I don't want to spend too much time talking about configuration, it's important to note that the XML file must be deployed in the /bin folder of your application. You can automate this in VS.NET by selecting the files, going to the properties and setting the Copy To Ouput Directory attribute to Copy Always. (There are a variety of more advanced configuration options available. If you're interested in learning more, I suggest the StructureMap website).

    Once configured, we can undo all the changes we made to the Car class to allow constructor injection (remove the _dataProvider field, and the constructors). To get the correct IDataAccess implementation, we simply need to ask StructureMap for it, the Save method now looks like:

    public class Car
    {
       private int _id;
       public void Save()
       {
          if (!IsValid())
          {
             //todo: come up with a better exception
             throw new InvalidOperationException("The car must be in a valid state");
          }
          IDataAccess dataAccess = ObjectFactory.GetInstance<IDataAccess>();
          if (_id == 0)
          {
             _id = dataAccess.Save(this);
          }
          else
          {
             dataAccess.Update(this);
          }
       }
       private bool IsValid()
       {
          //todo: make sure the object is in a valid state
          return true;
       }
    }
    

    To use a mock rather than the default implementation, we simply need to inject the mock into StructureMap:

    public void AlmostATest()
    {
       ObjectFactory.InjectStub(typeof(IDataAccess), new MockDataAccess());
       Car car = new Car();
       car.Save();
       if (car.Id != 1)
       {
          //something went wrong
       }
       ObjectFactory.ResetDefaults();
    }
    

    We use InjectStub so that subsequent calls to GetInstance return our mock, and make sure to reset everything to normal via ResetDefaults.

    DI frameworks such as StructureMap are as easy to use as they are useful. With a couple lines of configuration and some minor changes to our code, we've greatly decreased our coupling which increased our testability. In the past, I've introduced StructureMap into existing large codebases in a matter of minutes – the impact is minor.

    Conclusion
    Reducing coupling is one of those things that's pretty easy to do yet yields great results towards our quest for greater maintainability. All that's required is a bit of knowledge and discipline – and of course, tools don't hurt either. It should be obvious why you want to decrease the dependency between the components of your code – especially between those components that are responsible for different aspects of the system (UI, Domain and Data being the obvious three). In the next part we'll look at unit testing which'll really leverage the benefits of dependency injection. If you're having problems wrapping your head around DI, take a look at my more detailed article on the subject at http://dotnetslackers.com/articles/designpatterns/IntroducingDependencyInjectionFrameworks.aspx.

  • Foundations of Programming - Part 3 - Persistence

    Part 3 of the Foundations series has been posted on DotNetSlackers. You can see it at:
    http://dotnetslackers.com/articles/net/FoundationsOfProgrammingPersistence.aspx 

    This is an introduction to persistence using objects, which will be re-examined in a later part. 

    I've always believed that CodeBetter and communities like DNS have a symbiotic relationship, and this is my ongoing effort to help that relationship flourish.

    Stay tuned to the blog for more parts.

    Posted Dec 05 2007, 11:10 AM by karl with 4 comment(s)
    Filed under:
More Posts

Our Sponsors

Proudly Partnered With