About Me

Training

Nothin But .Net Developer Bootcamp

Navigation

Search

Categories

On this page

Answers To Some Good Questions

Archive

Blogroll

 Agile Developer Venkat's Blog
 Ayende @ Blog
 B#
 Barry Gervin's Software Architecture Perspectives
 Boy Meets World
 Brad Abrams
 Canadian Developers
 Christopher Steen
 Claritude Software News
 Clemens Vasters: Enterprise Development and Alien Abductions
 Coding Horror
 Coding in an Igloo
 Dare Obasanjo aka Carnage4Life
 Darrell Norton's Blog [MVP]
 David Hayden [MVP C#]
 Don Box's Spoutlet
 Eric Gunnerson's C# Compendium
 EZWeb guy: Jeffrey Palermo [C# MVP]
 Fear and Loathing
 Generalities & Details: Adventures in the High-tech Underbelly
 Greg Young [MVP]
 Greg's Cool [Insert Clever Name] of the Day
 IanG on Tap
 Ingo Rammer's Weblog
 ISerializable - Roy Osherove's Blog
 James Kovacs' Weblog
 Jason Haley
 Jean-Luc David
 Jeremy D. Miller -- The Shade Tree Developer
 JetBrains .NET Tools Blog
 Jimmy Nilsson's weblog
 John Bristowe's Weblog
 John Papa [MVP C#]
 Jon Skeet's Coding Blog
 JonGalloway.ToString()
 Jump the Fence or Walk Around
 Lambda the Ultimate - Programming Languages Weblog
 Larkware News
 Lutz Roeder
 Marquee de Sells: Chris's insight outlet
 Martin Fowler's Bliki
 Mike Nichols - SonOfNun Technology
 MSDN Magazine - .NET Matters
 MSDN Magazine - All Articles
 OdeToCode Blogs
 Onion Blog
 Planet TW
 Raymond Lewallen [MVP]
 Rockford Lhotka
 RodMan's Corner
 Roger Johansson's blog
 Sahil Malik - blah.winsmarts.com
 Sam Gentile's Blog
 Scott Bellware [MVP]
 Scott Hanselman's Computer Zen
 ScottGu's Blog
 secretGeek
 Service Station, by Aaron Skonnard
 Signum sine tinnitu--by Guy Kawasaki
 Stephen Toub
 Steve Eichert's Blog
 Steven Rockarts
 The Blog Ride
 The Coding Hillbilly
 The Daily WTF
 TheServerSide.net: News
 Tim Gifford
 Vance Morrison's Weblog
 you've been HAACKED

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 369
This Year: 94
This Month: 11
This Week: 0
Comments: 973

 Wednesday, April 19, 2006
Wednesday, April 19, 2006 3:25:23 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# | Patterns )

After my last presentation on DNRTv MauricioC asked some good questions that I thought I should post some answers for. I am reposting the questions from the comments that he made to give you a context for the answers:

Q: By the way, I also have an architecture question. When implementing the Service Layer pattern (as in Martin Fowler's Patterns of Enterprise Application Architecture), where would you put persistence code? The example on the book puts methods for filling the Domain Objects in themselves, but I am a little uncomfortable in introducing a dependency for the Data Access Layer in my Domain Layer (even while using Inversion of Control). Would you retrieve/persist data in the Service Layer itself, or the dependency is manageable and I am being paranoid?

A: As with many patterns there are a multitude of ways that the pattern can be implemented. As Martin points out, the two most common approaches for the service layers are the “Domain Facade” and “Operation Script”. I tend to lean toward the domain facade approach as it keeps my logic inside of the domain objects as opposed to dispersed through multiple methods in the service layer. As far as persistence is concerned the approach that Mauricio is talking about when having domain objects responsible for persisting themselves is the Active Record approach. As he says, this places a dependency on the data access layer in the domain model. I prefer having a completely isolated domain model, one that knows nothing about the service layer, data access etc. This allows you to drive out the functionality of the domain model in isolation from anything else. In this scenario, the service layer would be responsible for talking to some sort of MapperRegistry to retrieve mappers that know how to persist objects that need to go back to the database. Again, with a domain facade the service layer code is kept as thin as possible. Having discrete mappers that know how to persist objects/families of objects, removes this responsibility from both the domain model and the service layer and puts it where it should be, in a mapping layer. Mappers can be developed test first to ensure that if a mapper is given a particular object that it can read/delete/insert that object. So the long and short of it is :

The Service Layer coordinates the persistence, but it doesn't perform the persistence.

Again, the active record pattern is still a viable alternative if you are working with a simpler object model, and you are comfortable with domain objects being responsible for persisting themselves.


Q:Another very related question: Would you use test-driven development to create the service layer (I mean, it is a very thin wrapper that should not need inversion of control, as it's common for such facades)? The same question applies for the view in the MVP pattern: If you had used TDD in DNRtv, what parts of the view would have been tested?

A: The short answer is yes. Assume you were asked to build out a new method that needs to exist on a service layer class. This method will be called whenever a new Customer is to be added to the system. Here’s the catch, there is currently no mapper for a Customer object. And yet you still want to carry on developing the method without that in place. You can utilize TDD to drive out this scenario, even without the actual concrete mapper in place. If everything was already in place, then the test serves as a sanity check that the service layer class is talking and interacting with its dependencies as it should. An example of such a test would look like this.

 



using System;
using NUnit.Framework;
using Rhino.Mocks;

namespace DataLayer.DataAccess.Test
{
    [TestFixture]
    public class CustomerTaskTest
    {
        MockRepository mockery;

        [SetUp]
        public void Setup()
        {
            mockery = new MockRepository();
        }

        [TearDown]
        public void TearDown()
        {
            mockery.VerifyAll();
        }

        [Test]
        public void ShouldBeAbleToCreateNewValidCustomer()
        {
            ICustomerMapper customerMapper = mockery.CreateMock<ICustomerMapper>();
            CustomerDTO dto = new CustomerDTO("JP","Boodhoo");

            ICustomerTask task = new CustomerTask(customerMapper);

            customerMapper.Insert(null);

            LastCall.On(customerMapper).Constraints(
                Is.NotNull() &
                Is.TypeOf(typeof(Customer)) &
                Property.Value("FirstName","JP") &
                Property.Value("LastName","Boodhoo"));

            mockery.ReplayAll();

            task.CreateNewCustomer(dto);        

       }
    

    
    }
}

Notice that I am taking advantage of a new mocking framework that I have come to love (RhinoMock .Net). I am going to write up another post about working with RhinoMock, for those of you who have used NMock2 (also a great framework), the immediate distinction between the two is that I can actually set expectations by actually invoking the methods on a mock interface. Again, I will save the details of using RhinoMock for another post. This test was written test first without any existing code in place, but the intent of what the concrete service layer class should do is evident. After calling the CreateNewCustomer method we know that the service layer class is going to invoke the “Insert” method on a ICustomerMapper implementation, and the Customer object that gets passed to the insert method will have had its firstname and lastname properties set. That is is. Thin service layer. We are not testing that the service layer can actually map the Customer to the database, we are testing that given a CustomerDTO, the service layer class can:

  • Unwrap the DTO and create the necessary Customer domain object
  • Invoke the Insert method on a ICustomerMapper implementation

A test around a concrete ICustomerMapper implementation would actually verify whether a customer could be mapped to the database. If you want to see the code for the CustomerTask class, here it is:

 

public class CustomerTask : ICustomerTask
{
        private ICustomerMapper customerMapper;

        public CustomerTask(ICustomerMapper customerMapper)
        {
            this.customerMapper = customerMapper;
        }

        public void CreateNewCustomer(CustomerDTO dto)
        {
            customerMapper.Insert(new Customer(dto.FirstName,dto.LastName));
        }
}
 
In this scenario, this results in an extremely "thin" service layer class. As far as testing the view in an MVP triad, now we are getting into the functional testing layer where you would want to use some sort of automated UI runner. For windows NUnitForms is a great free one, and for the web Ruby & Watir are a great combination. Again, when testing at the actual UI layer, you are really trying to test the thin layer that can’t easily be accessed by the presenter (unless you tie presenters specifically to one particular UI framework).