Wednesday, January 4, 2012

Simple Circles–Persistence (Part 2)

This post is part of a series on building a simple to use web-based contact and customer relationship management application. The goal is to support various audiences including businesses, teams, clubs, religious organizations, etc. With a basic structure for the domain objects taking shape it’s time to move on to the notion of persistence.
One of the tenets of DDD is known as “aggregate root” – a top-level, course grained collection of responsibilities. In plain object-oriented systems, objects tend to expose granular methods to operate on their data. Unfortunately, this approach allows business knowledge and intimate design details to creep outside of the model. That is, accomplishing a business operation usually entails making several method calls across several objects – this sequencing of calls becomes embedded externally in calling applications making the whole thing tightly coupled and brittle. The aggregate root principle groups related objects closely and provides consistent and coordinated access to these related objects.Vaughn Vernon wrote an in depth three-part article on the topic of Effective Aggregate Design.
In this model the Party is an obvious root object – we don’t access addresses or notes without first going through the Party instance they belong to. This approach leads to methods like Party.AddAddress() or Party.AddNote() rather than creating addresses and notes separately.
Once the aggregate root(s) have been identified it’s time to move on to persisting the data they contain. The Repository pattern is a proven way to implement persistence in a storage-neutral manner. There are many references to consult for more information but in the context of DDD, Jak Charlton’s post, DDD: The Repository Pattern, is particularly concise and a good starting point for why it is useful. Gabriel Schenker provides another good write up with code examples on the NHibernate FAQ. Given that we have a Party aggregate root, we should also have a PartyRepository since each aggregate should be responsible for its own “domain” or “scope” if you will.
Since repositories manage aggregate roots and their associated entities/ values, the basic semantics for the repository follow that of a generic collection. For us this means something like:
namespace Circles.Persistence
{
  using System;
  using System.Collections.Generic;

  public interface IPartyRepository
  {
    IList<Party> FindAllParties();
    Party FindPartyById(Guid Id);
    Guid Add(Party party);
    void Delete(Guid Id);
    void Update(Party party);
  }
}

Some might balk at the Delete and Update methods, arguing that pure collections have “Remove” instead. However, I am of the opinion that we’re working with domain (a.k.a. business) entities that are persisted somewhere so the semantics of persisting data are more natural with delete and update.

Of course the above approach is very "party-specific” so it could be refactored using generics like this:
namespace Circles.Persistence
{
  using System;
  using System.Collections.Generic;

  public interface IRepository<T> where T : Entity
  {
    IList<T> FindAll();
    T FindById(Guid Id);
    Guid Add(T entity);
    void Delete(Guid Id);
    void Update(T entity);
  }
}

Now we’ve got an interface that supports any type of domain entity – note the removal of the term “Party” from the method names.

The above refactored interface implies that every repository created supports all four “CRUD” operations.  A better approach would be to split out the operations and then have a specific repository implement the ones it needs like this:
namespace Circles.Persistence
{
  using System;
  using System.Linq;

  public interface IRepository<T, in TId> where T : Entity
  {
    T this[TId id] { get; set; }
    IQueryable<T> FindAll();
    T FindById(TId Id);
  }

  public interface ISupportSave<in T, out TId> where T : Entity
  {
    TId Add(T entity);
    void Update(T entity);
  }

  public interface ISupportDelete<T, in TId> where T : Entity
  {
    void Delete(TId Id);
  }

  public interface IPartyRepository : IRepository<Party, Guid>, ISupportSave<Party, Guid>, ISupportDelete<Party, Guid>
  {
    IQueryable<Household> FindAllHouseholds();
    IQueryable<Organization> FindAllOrganizations();
    IQueryable<Person> FindAllPersons();
  }

Now we’re explicit about what the PartyRepository does. By implementing IRepository, ISupportSave and ISupportDelete we’re clear that the IPartyRepository supports full CRUD behavior using Guids for the Id types. Additionally, we provide FindAllxxx methods for retrieving specific types from the repository. Notice that having the repository return IQueryable gives flexibility on both sides – concrete implementations can translate the LINQ query passing it to the underlying data store for execution and callers can query the repository in various ways rather than being forced to go through a rigid, narrowly defined API we provide.

One more thing to cover – I slipped in a new Type called Entity that is a base class for all domain entities. Rather than rehashing all the details here I’d suggest checking out Jason Dentler’s blog or his book NHibernate 3.0 Cookbook. Equally important is Billy McCafferty’s work on Sharp Architecture. Standing on the shoulder’s of giants…

The source code for this article can be downloaded from here.

Next we’ll look at testing what we have xUnit.

No comments:

Post a Comment