Archive for February, 2009

Don’t unit test the glove

Sunday, February 22nd, 2009

There was an email chain letter that my Mom forwarded to me a while back. It was a math magic trick that could predict your age. She asked me how it worked.

It had you start with the year you were born, multiply by one number, add another, repeat the digits, and go through all sorts of numeric hocus-pocus. If you just worked through it using basic algebra, it's easy to see that you were just subtracting the year of your birth from the current year. The intermediate steps added no value. How could thing predict your age? How could it not?

I'm looking at a unit test for a data access service, and I'm reminded of that email that filled Mom with wonder. The unit test mocks an order repository using Rhino Mocks:

int expectedOrderIdentifier = 5;

Order expectedOrder = new Order();
expectedOrder.OrderId = expectedOrderIdentifier;
expectedOrder.WebOrderNumber = 123;
IList<Order> orderList = new List<Order>();
orderList.Add(expectedOrder);

MockRepository mocks = new MockRepository();
IAggregateRootRepository<Order> orderRepositoryMock =
    mocks.CreateMock<IAggregateRootRepository<Order>>();

using (mocks.Record())
{
    Expect.Call(
        orderRepositoryMock.GetSatisfying(dummyOrderSpecification))
        .IgnoreArguments()
        .Return(orderList.AsQueryable<Order>());
}
using (mocks.Playback())
{
    OrderService target = new OrderService(orderRepositoryMock);
    Order returnedOrder = target.GetOrderByWebOrderNumber(expectedOrderIdentifier);
    Assert.IsTrue(
        returnedOrder == expectedOrder,
        "The mocked repostiory provided order was not returned by the repository changes will not be tracked by the unit of work.");
    Assert.IsTrue(
        returnedOrder.WebOrderNumber == 123,
        "The mocked repostiory provided order was not returned by the repository changes will not be tracked by the unit of work.");

}
// Tests to make sure the order repository was enlisted in the provided context.
mocks.VerifyAll();

Lo and behold the test passes! Amazing! Let's take a look at the code under test:

public Order GetOrderByWebOrderNumber(int webOrderNumber)
{
    // Create Specification 
    // This specification is used to get just the order entity without any dependent entities 
    ReferencedOrderByWebOrderNumberSpecification specification =
        new ReferencedOrderByWebOrderNumberSpecification(webOrderNumber);

    // Here Assumption is we get only one order from database  for the provided web order number 
    Order order = _orderRepository.GetSatisfying(specification).FirstOrDefault();

    if (order == null)
    {
        throw new ArgumentException();
    }

    return order;
}

A perfectly reasonable bit of code. It pulls an object from the repository according to a specified condition. In fact, the only interesting thing about this code is that condition.

But look closer. The unit test passes in the wrong parameter! The method takes a web order number, and the unit test passes in an order ID. The code under test creates a specification based on this incorrect information, but the mock repository ignores this parameter. No matter what the condition is, it returns the object we tell it to. Since we mocked the repository to return the object we expected, that's exactly what was returned. How could the test ever fail?

This unit test is completely meaningless. It goes through all sorts of gyrations and mock-object hocus-pocus in order to return the object that we expect. The one interesting feature of the code under test is never tested. In fact, this test passes even thought the object that we fed the mock repository didn't satisfy the condition!

Like my Mom with the email, the developer who wrote this test really though something interesting was happening. In striving for greater test coverage, he was just fooling himself into thinking that he was improving the quality of the code. Useless unit tests are worse than no unit tests, because they give you false confidence in the code.

A glove is a thin wrapper over a hand. The glove is going to do what the hand does. How could it do any different? Don't waste your time unit testing the glove.

Null coalescing operator (??) not useful

Thursday, February 12th, 2009

I still haven't found a good use for the C# ?? null coalescing operator. I always find that I want a property of the possibly null object, not the object itself. I wish it worked with this code:

Person p = null;
string name = p.Name ?? string.Empty;

That is, it should take the left-hand side if any part of the right-hand side is null. Now that would be useful.

Here's the best I could come up with for making use of it:

class Person
{
    public string Name { get; set; }

    public static Person Default = new Person();
}

Person p = null;
string name = (p ?? Person.Default).Name ?? string.Empty;

Not exactly intention revealing.

DDD to English dictionary

Thursday, February 5th, 2009

With apologies to Eric Evans.

What it means

  • Ubiquitous Language - Glossary
  • Unit of Work - Transaction
  • Repository - Data access component
  • Specification - Where clause
  • Service - Static method
  • Aggregate - Hierarchy
  • Intention-Revealing Interfaces - Good names
  • Anticorruption Layer - Contract

What it could mean, but doesn't

  • Ubiquitous Language - The phenomenon that development teams pick one programming language and stick with it
  • Unit of Work - The detail of your estimates: to the hour, day, or week
  • Repository - Source control
  • Specification - Requirements document
  • Service - RPC over HTTP
  • Aggregate - A filled-in diamond on a UML diagram
  • Intention-Revealing Interfaces - Ports 80 and 25
  • Anticorruption Layer - CRC

Domain Driven Design: we’re doing it wrong

Wednesday, February 4th, 2009

Several people have recommended the book Domain Driven Design by Eric Evans. I've heard it referenced on podcasts and in blogs. My technical manager informed me when I first started on my current project that the architecture was partially based on this book. It takes a while for a message to seep in, but I finally decided it was time to pick up this book.

When I saw the book cover, I was surprised. No, not by the retro cheesiness of the graphics, colors, and fonts. I was surprised because I recognized it. I had had this book on my shelf for over two years.

I bought this book from Amazon because it was paired with Software Factories. I started reading DDD shortly after finishing SF, but gave up before even getting through the preface. I found Evan's style unnecessarily verbose and obfuscated.

So the book languished on my shelf for over two years before I made the discovery that an important sub-discipline within my industry was passing me by, simply because of my disdain for one man's writing style. So I forced myself to wade through his awkward word choice, parabolic explanations, and prolonged narratives to extract the meat of the subject. And I'm glad I did.

It turns out, we're doing DDD wrong.

What is Domain Driven Design
The point of Domain Driven Design is to put all of the domain knowledge into a rich object layer. This layer captures the essential information about the problem domain, the relationships among those objects, and the responsibilities of those objects. If the domain is commerce, as it is in our system, then you have domain objects for products, orders, and shopping carts. The methods of these objects capture business knowledge, like inventory rules and regulatory restrictions.

This is very similar to the old Rumbaugh OOA&D thinking that my career started out with. We as an industry have come to think of that "look for the nouns" guidance as naive. Programs that run on computers need objects that represent computer ideas. So we have objects for windows, database connections, proxies, and sockets. If you follow the Gang of Four as I do, you'll write objects like factories, visitors, and strategies. Nouns from the real world have a hard time coexisting with these technical concepts in today's object oriented programs.

But Evans provides some guidance that allows us to draw from both of these views of objects. The domain objects are isolated from the technical objects. Patterns like Repository/Specification and Unit of Work hydrate domain objects without coupling them to persistence technology. Evans shows us how to take a set of objects that a domain expert would understand, and use them in a modern software application.

The advantage of Domain Driven Design is that domain objects become a medium of communication. Programmers and experts can talk about the domain by using the source code. Or at least, the classes and methods in the source code. If the source code does not accurately reflect the knowledge of the domain expert, then the source code is wrong. Using Evans' guidance and patterns, the domain model can be quickly refactored as developers learn more about the problem domain.

Unfortunately, the way that we have been applying Evans' guidance and patterns on our eCommerce system has made it more difficult to refactor the domain, and left us with a fairly rigid system. Here are some of the big mistakes we made.

Layered architecture does not mean tiered architecture
Evans recommends a layered architecture:

  • presentation
  • application
  • domain
  • infrastructure

The presentation layer handles UI, the application layer implements features, the domain layer captures business knowledge, and the infrastructure layer lends low-level support. This approach isolates the domain objects from technical concerns like storage and presentation. It allows the solution to be implemented in the language of the domain, instead of forcing the domain to implement those features.

Our approach was to separate these concerns into physical tiers. These tiers could be deployed to different servers in the datacenter for the benefits of security and scalability. Imagine my surprise when I get to page 114, where Evans says, "This could be a strong argument if the code actually got deployed on different servers. Usually it does not." I wasn't surprised because he told me something I didn't know; I was surprised because I knew and hadn't objected.

The fact is, we aren't going to need quite so many tiers. Yes, we are separating the presentation tier because it is hosted in SharePoint and resides in the DMZ. But besides that, the other layers -- not tiers -- can benefit from being in the same process and not being forced across machine boundaries.

SOA's "services" are not DDD's "services"
We architected our eCommerce application to be service oriented. The benefits are that isolated services are reusable and independently versionable. These are significant goals of this project, as we are building not just an eCommerce application, but a platform for all commerce in the company.

Domain Driven Design also talks about services. But a DDD service is an operation that doesn't belong to just one object. A service is still a domain concept, in that it captures domain knowledge, but it isn't an instance method on a domain object. We've exposed our services as WCF web services, when it may have been more appropriate to simply expose them as static methods in the domain layer. Only those services that external systems would want to consume should be published through WCF.

Entity Framework's "entities" are not DDD's "entities"
Evans' guidance is strongly informed by the difference between entities -- objects whose identity is important -- and value objects -- whose identity is not. His patterns talk about how to carefully rehydrate entities such that their in-memory identity matches their persistent identity (where it is important to do so). Above all, entities are first-class domain objects.

Before I joined the project, linq to SQL was rejected because it does not play well with rich domain objects. Certainly, a linq query pulls data from a record set and puts it into objects, but it does nothing to respect the identity of those objects. If you run two queries, it will happily construct two objects to represent the same ID.

The decision was made to use the Entity Framework, then in beta. The idea was that EF entities were partial classes, so domain logic could be added. The framework would handle persistence, and our code could take over from there.

As it turned out, Entity Framework is no better than linq to SQL for our purpose. The primary concern of the entity model is the mapping between record sets and objects. The entity model exists in a limbo between a good object model and a good relational model. Domain objects are, first and foremost, objects. If they have to compromise to conform to good relational design, then they fail to be good domain objects.

On the other hand, either EF or linq to SQL would make a good memento. Linq to SQL favors anonymous types, while EF favors its flavor of entity. If the persistence of domain objects handled the translation of domain objects to mementos, then either one could take it the rest of the way to the relational database.

We already had a repository and specification
The piece of advice from DDD that people most often cite is to use a pattern of Repositories and Specifications. A repository is a place to store objects when they are not in memory. A specification is a condition -- separate from the repository -- that you can use to fetch the objects you are interested in. The advantage of this pattern is that the application layer can provide the specification, the infrastructure layer the repository, and the domain objects remain blissfully unconcerned with these non-domain details.

The piece of advice that is not often cited, however, is "don't fight your frameworks" (page 157). If your framework already has a good implementation of the pattern, just use it. This is advice that we ignored to our peril.

.NET 3.5 introduced linq. Besides the language features that support linq, the core framework component is the IQueryable interface. As it happens, IQueryable is the repository/specification pattern. Any object that implements this interface is a repository. Any boolean delegate (or lambda expression) is a specification. Combine the two using the Where extension method, and you have implemented the pattern.

What we did, however, was to create generic interfaces with names like IAggregateRootRepository, ISpecification, and IUnitOfWork. In order to use these interfaces, you have to define entire classes that differ in no more than a class name and a where clause. The result is a common base class library that is difficult to learn and encumbered with Evans' poor choice of words. Our application is full of extra classes that could have been inlined as lambda expressions. We have an entire suite of unit tests dedicated to ensuring that these specification classes contain the right boolean expression.

Here's my solution
Although we are too far along in the process to make radical architectural changes, I like to keep an ideal in mind for new development and refactoring. The ideal is a simple one: encode business knowledge in rich domain objects, use mementos to persist them, build application and domain layers into a single process, and publish WCF web services only where needed.

I am not a born-again DDD convert. I apply Evens' advice only with an open and skeptical mind. But where I see his book brandished as justification for poor decisions, I dig deeper to find what he really meant. Yes, it takes a lot of digging, given his choice of obscure terms for otherwise well-known concepts, but there is value to be found.