Lost in Translation

An entry about domain-driven design Publication date 26. February 2009 11:36

One of.. no, the core concept of Domain Driven Design is the Ubiquitous Language. The UL, simply put, consist of the words and phrases we use to express the domain model. It is the language that both the domain experts and the team of developers use when talking about the application. The UL should exist anywhere the concepts of the domain is addressed – in written documents, diagrams, conversations - and in code, where classes and their methods should be named according to it.

That sounds fairly reasonable; some would even say obvious.

Do you speak-a my language?

However: Most developers write code in English, even if it is not their native tongue. For them, most of the domains they work with are thus expressed in a language which differs from the language they write code in. The question then becomes – should we translate the ubiquitous language into English? Or should we really be writing code in our native language? Or do we write code in English, but use non-English words and phrases where required to conform with the UL…

I’ve worked on projects where the ubiquitous language became anemic because the developers translated the Norwegian domain into English. Apart from often having trouble finding good translations for many of the domain concepts, the fact that the developers begun calling things by their English names when talking about them often caused misunderstandings between the developers and the domain experts.

The “GetLønnslipp()” method is a common joke amongst Norwegian developers – but maybe that actually is the way we should be naming our methods?

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Linq to Sql, Programming Against an Interface and the Repository Pattern

An entry about tdd | linq | design patterns | domain-driven design Publication date 5. May 2008 21:56

Program against an interface, not an implementation. I've always been a big fan of that saying. Obviously, in this context interface doesn't necessarily mean an actual interface type; maybe it should have been written as "program against an abstraction, not an implementation" to make that clear. With Linq to Sql - and really most O/R mappers out there that do code-generation - this pretty much goes out the window since you're leaving the O/R mapper in charge of generating the code for the domain model objects for you, based on some (database) schema. What you end up with as a consequence of this, is code like:

var query = from pages in dataContext.Pages where pages.IsPublished select pages;
 
foreach (Page page in query)
{
    // do something with page...
}

 

Here, I'm not programming against an interface - I'm programming against the explicitly implemented Page class. My strongly typed DataContext, autogenerated by the O/R mapper (Linq to Sql), exposes a property Pages which is of type Table<Page>. What I want, though, is an interface IPage that everyone (apart from the factory creating the instance, obviously) should program against; they should never touch the actual Page type.

Partial Rescue

Thankfully C# has got what it takes to solve this, we just have to jump through a few hoops for it. When SqlMetal generated the Page class it made it partial, which allows me to extend the class definition. I can do this by implementing another partial class named the same:

public partial class Page : IPage
{
    IRoute IPage.Route
    {
        get { return this.Route; }
        set { this.Route = (Route)value; }
    }
}

 

At runtime, the compiler will combine both mine and the auto-generated Page class into one. Originally, my Page table had a one-to-one relationship with the Route table. I want the Route property on Page to return an IRoute though, so I've explicitly implemented this property from the IPage interface so that anyone programming against IPage sees an IRoute - but Linq to Sql, which works against the concrete Page type, will of course still see the concrete Route type. The same would be true for any one-to-many relationships; in the interface I would declare them as a generic IList<T>. EntitySet<T>, the type that Linq to Sql uses for collections, actually implements IList<T>, so it's just an implicit cast to get that working too.

But this only gets us halfway there. The autogenerated DataContext still exposes a Table<Page> type, when we really want a Table<IPage> type - or even better, the much more abstract IQueryable<T> type. What we need, is a pattern devised a long time ago...

The Repository Pattern

From Fowler, "conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them". From Evans, "the Repository retrieves the requested object, encapsulating the machinery of database queries and metadata mapping". That last quote is lifted from his book Domain Driven Design (p. 151), which he published back in 2004. What is funny, is that he goes on to say that "a Repository lifts a huge burden from the client, which can now talk to a simple, intention-revealing interface, and ask for what it needs in terms of the model. To support all this requires a lot of complex technical infrastructure". That first part is spot on. But the part about implementing the repository pattern being complex? I guess we've come a long, long way these last four years - C# 3.0 and Linq does away with all the complexity for us, so that all we have to do to implement a super-flexible Repository is defining something like the following interface:

public interface IDataContext, IDisposable
{
    /// <summary>
    /// Gets the repository for the given type of entities
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <returns>The repository of the given type</returns>
    IQueryable<T> Repository<T>() where T : class, IEntity;
 
    /// <summary>
    /// Adds a new entity to the repository
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <param name="item">The entity to add</param>
    void Insert<T>(T item) where T : class, IEntity;
 
    /// <summary>
    /// Deletes the specified entity from the repository
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <param name="item">The entity to delete</param>
    void Delete<T>(T item) where T : class, IEntity;
 
    /// <summary>
    /// Commits the changes to the repository
    /// </summary>
    void Commit();
}

 

That's it! And implementing this interface for Linq to Sql is not much harder:

public class LinqToSqlContext : IDataContext
{
    private readonly DataContext _context;
 
    public static Dictionary<Type, Type> TableMaps = new Dictionary<Type, Type>();
 
    public LinqToSqlContext(DataContext context)
    {
        _context = context;
    }
 
    /// <summary>
    /// Gets the repository for the given type of entities
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <returns>The repository of the given type</returns>
    public IQueryable<T> Repository<T>() where T : class, IEntity
    {
        ITable table = _context.GetTable(TableMaps[typeof(T)]);
        return table.Cast<T>();
    }
 
    /// <summary>
    /// Deletes the specified entity from the repository
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <param name="item">The entity to delete</param>
    public void Delete<T>(T item) where T : class, IEntity
    {
        ITable table = _context.GetTable(TableMaps[typeof(T)]);
        table.DeleteOnSubmit(item);
    }
 
    /// <summary>
    /// Adds a new entity to the repository
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <param name="item">The entity to add</param>
    public void Insert<T>(T item) where T : class, IEntity
    {
        ITable table = _context.GetTable(TableMaps[typeof(T)]);
        table.InsertOnSubmit(item);
    }
 
    /// <summary>
    /// Commits the changes for this unit of work to the repository
    /// </summary>
    public void Commit()
    {
        _context.SubmitChanges();
    }
 
    public void Dispose()
    {
        // we don't assume to manage the lifetime of the data 
        // context, so there's nothing to dispose
    }
}

 

The magic that lets us run queries against for example IPage, is in the Cast<T> extension method in System.Linq. By using it, it allows clients to ask the Repository<T> method for IPage, which then through the mapping configured in the static TableMaps dictionary (where at application startup I've added the mapping between IPage and Page) gets translated into a request for the Page table from the context, and then finally cast back to a IQueryable<IPage> before being returned to the caller, ready for querying against. The implementation-specific code I posted at the beginning of this article can now be thrown away in favour of the following more loosely coupled code:

var query = from pages in dataContext.Repository<IPage>() where pages.IsPublished select pages;
 
foreach (IPage page in query)
{
    // do something with page...
}

 

The Power of an Abstraction is it's Transparent Plugability

One clear win from doing things this way, is the transparent plugability that we achieve by hiding the DataContext behind our repository abstraction. For writing tests, this is invaluable. We can now implement a simple InMemoryDataContext that satisfies all the operations of the interface, allowing us to fake an actual database for testing purposes. The usage of Linq against the IQueryable<T> type means that any query in our application will then instead be executed in-memory instead of translated to SQL, completely transparent from the calling code. My InMemoryDataContext looks like this:

public class InMemoryDataContext : IDataContext
{
    private readonly List<object> _inMemoryDataStore = new List<object>();
 
    public IQueryable<T> Repository<T>() where T : class, IEntity
    {
        var query = from objects in _inMemoryDataStore
                    where typeof (T).IsAssignableFrom(objects.GetType())
                    select objects;
 
        return query.Select(o => (T)o).AsQueryable();
    }
 
    public void Insert<T>(T item) where T : class, IEntity
    {
        _inMemoryDataStore.Add(item);
    }
 
    public void Delete<T>(T item) where T : class, IEntity
    {
        _inMemoryDataStore.Remove(item);
    }
 
    public void Commit()
    {
        InvokeCompleted(EventArgs.Empty);
    }
 
    public event EventHandler Completed;
 
    private void InvokeCompleted(EventArgs e)
    {
        EventHandler completedHandler = Completed;
        if (completedHandler != null) completedHandler(this, e);
    }
}

 

Notice in particular that I've modified the Commit method to raise an event upon being called, so that tests which expect a Commit call can easily assert this. For example, I have a test to verify that when the title of a page is edited, the edited page gets committed to the draft repository (which is another great possibility of having the abstraction at hand - by injecting a special implementation of IDataContext when in page editing mode, I can make it so that changes done in the editor commit to a different storage location than the live data that site visitors see, until the user hits 'Publish'):

[TestClass]
public class When_SetTitle_action_executed
{
    const string route = "#";
    const string newTitle = "##";
    private Page page;
    private InMemoryDataContext context;
    private EditorController controller;
 
    [TestInitialize]
    public void Setup()
    {
        page = new Page {Route = new Route {Path = route}};
        context = new InMemoryDataContext();
        context.Insert(page);
 
        controller = new EditorController(context, MockHelpers.FakeTemplateRepository);
    }
 
    [TestMethod]
    public void New_title_gets_committed()
    {
        bool completed = false;
        context.Completed += (s,e) => completed = true;
 
        controller.SetTitle(route, newTitle);
 
        Assert.IsTrue(completed);
    }
    
// other tests omitted
}

 

And that's it for now. Hopefully this post makes some sense; much of what was written here comes fresh from my Visual Studio instance running in the background. If nothing else, I felt that writing this post helped clarify to myself what I needed to achieve, and that it does in fact seem like a good choice to make for my persistence strategy :)

Currently rated 4.8 by 29 people

  • Currently 4.827586/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Powered by BlogEngine.NET 1.4.5.0

Welcome!

My name is Fredrik Kalseth, and this is my blog - thanks for visiting! I am fortunate enough to work with what I love for a living, and this blog is essentially the biproduct of that.

I work as a senior consultant for Capgemini, and am also an active participant in the Norwegian .NET community, as an avid attendee but also as a speaker (most recently at NNUG and MSDN Live).

As a developer, I have a wide circle of interest. My primary passion is for agile, test-driven development, with focus on best practices and clean code. That said, I also love to work on the frontend, especially with web development.

On Twitter? My handle is fkalseth. On LinkedIn? I`m there too.


Disclaimer

This is a personal blog; any opinions expressed here are my own and do not necessarily reflect those of my employer. All content herein is my own original creation, and as such is protected by copyright law. Unless otherwise stated, all source code posted on this blog is freely usable under the Microsoft Permissive License.

What Readers Talk About

Comment RSS