Where are your Scenarios in your domain?

If you design your entities before you design your scenarios, you are data-driven! The Scenarios are primary – The entities are secondary!

– Daniel Wertheim

My words of what I think is wrong in many projects, and thats what this post is about.

Definition of Scenario

a postulated sequence of possible events

http://wordnetweb.princeton.edu/perl/webwn?s=scenario

In computing, a scenario is a narrative describing foreseeable interactions of types of users (characters) and the system. Scenarios include information about goals, expectations, motivations, actions and reactions. Scenarios are neither predictions nor forecasts, but rather attempts to reflect on or portray the way in which a system is used in the context of daily activity.

http://en.wikipedia.org/wiki/Scenario_(computing)

I tend to bump into situations where I meet people that are proclaiming they are adapting DDD in their projects and that they are writing object-oriented systems. As I’m always interested in learning, I fire of a couple of questions about what they mean by DDD and OO. I will not bother you with the dialog, but will rather skip to a summarize of the conversation. and present five of the artifacts that they think significates that they are conforming to DDD which I think is well worth to notice and discuss about:

  • They are object-oriented
    Meaning “that they are not using datasets anymore to keep track of the state and simple validation.”
  • They have POCO entities
    Meaning “that they have an OR/M that to some extent hides some of the artifacts of dealing with persisting the entities.”
  • They have repositories
    Meaning “there’s at least one repository per aggregate root (most often more), dealing with CRUDs.”
  • They have domain-services
    Meaning “they have some objects named [Entity][Service/Manager] which contains logic and calls to repositories”.
  • They have a model
    Meaning “they have a bunch of the above objects collaborating together”.
  • Ok, so I have designed system like these to. I will probably do it again. But lets look at what I mean by “systems like these” and what I think is wrong.

    Whats wrong?
    So I think we tend to create a model with an emphasis on entities, which more or less becomes a representation of tables in a traditional database. I like to define these entities as “an intelligent data-row” and by intelligent I mean that it might have simple validation of state and some logic for aggregating values, e.g. “Sum of the contained order lines in the order”. Furthermore we tend to create a bunch of services/managers that is named: “[Entity][Service/Manager]”; which to some extent holds together the flow – which most often means, they do some simple validation/rule-evaluation and they interact with a repository. I think these Services/Manager-classes arise from a mental mind of the developer looking like this: “The entity must be POCO and can’t have anything to do with persisting entities. I’ll just create a service that calls the repository and since I’m working with my order-entity, I’ll name it “OrderService”.

    Again, we end up here because we are thinking objects and state and how the objects correlate to each other. And when sitting there, performing TDD with a shallow understanding of the domain; it’s probably the easiest way to get started. Classic example: “Customer places a new order” => “OrderService.PlacerOrder” which receives an order entity with some contained lines and a customer. So my question to you then is: “What exactly is OrderService in the business”? If it is the customer that makes the request, why can’t it be “Customer.PlaceNewOrder”? Or a domain-object named something that mimics the scenario/process, e.g.: “PlaceNewOrder” or “OrderRegistration”.

    To sum it all up: The scenarios/processes in the domain is the core of the business. It’s what make the business unique and is what they are competing with against other competitors. This is what should drive your design. Without a fair understanding of the domain you will risk, getting data centric. The Domain should drive the design of your model, not TDD. Get a deep knowledge of the business and it’s processes and not only the binary rules and the state. These are the aspects that should be reflected in your code.

    //Daniel

    NHibernate – HbmNHibContext & FluentNHibContext

    In this post I’m going to share some parts of my architechture that I use when working with NHibernate. I’m using a Dependency Injection framework (e.g. Microsoft Unity) to create my repositories, services etc.

    All my repositores that are implemented using NHibernate takes something I call a “NHibContext”. The NHibContext has one main responsibility: “Creating Unit of Works” that are used within my repositories. To create these Unit of works, the NHibContext needs a way to create ISession’s from an ISessionFactory. To begin with, I have created two implementations (see below): HbmNHibContext, FluentNHibContext. But first lets look at the base-class:

    NHibContext

    /// <summary>
    /// A NHibernate-context object which operates on a single-database.
    /// Offers functionality for creating UnitOfWorks for use in e.g
    /// Repositories that uses NHibernate.
    /// To create a custom Context implementation, inherit from this
    /// class and ensure that SessionFactory is assigned in cTor.
    /// </summary>
    public abstract class NHibContext
    {
        protected ISessionFactory SessionFactory { get; set; }
    
        /// <summary>
        /// Creates an new UnitOfWork.
        /// </summary>
        /// <returns></returns>
        public NHibUnitOfWork CreateUnitOfWork()
        {
            return new NHibUnitOfWork(SessionFactory.OpenSession());
        }
    }
    

    HbmNHibContext
    Is setup using plain old fashioned HBM-files and uses Xml-configuration for the database etc.

    FluentNHibContext
    Uses, like the HbmNHibContext, Xml-configuration for the database, but instead of Hbm-files, it uses Fluent-NHibernate for defining the mapping.

    /// <summary>
    /// Uses Xml-configuration for setup-config and for mappings is Hbm-files used.
    /// </summary>
    public class HbmNHibContext : NHibContext
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="HbmNHibContext"/> class.
        /// Since you do not provide an assembly that contains the mappings,
        /// you have to provide these via configuration of mapping-resources.
        /// </summary>
        public HbmNHibContext()
            : this(null)
        {}
    
        /// <summary>
        /// Initializes a new instance of the <see cref="NHibContext"/> class.
        /// </summary>
        /// <param name="assemblyName">The Name of the Assembly containing the mappings.</param>
        public HbmNHibContext(string assemblyName)
        {
            SessionFactory = CreateSessionFactory(assemblyName);
        }
    
        /// <summary>
        /// Creates and returns a session factory.
        /// </summary>
        /// <param name="assemblyName">Optional Name of the assembly that contains the mappings.</param>
        /// <returns></returns>
        private ISessionFactory CreateSessionFactory(string assemblyName)
        {
            var cfg = new Configuration();
            cfg = cfg.Configure();
    
            if (assemblyName.IsNotNullOrEmpty())
                cfg.AddAssembly(assemblyName);
    
            return cfg.BuildSessionFactory();
        }
    }
    
    /// <summary>
    /// Uses Xml-configuration for setup-config and for mappings is Fluent-NHibernate used.
    /// </summary>
    public class FluentNHibContext
        : NHibContext
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="FluentNHibContext"/> class.
        /// </summary>
        /// <param name="assemblyWithMappings">The assembly containing the Fluent mappings.</param>
        public FluentNHibContext(Assembly assemblyWithMappings)
        {
            SessionFactory = CreateSessionFactory(assemblyWithMappings);
        }
    
        /// <summary>
        /// Creates and returns a session factory.
        /// </summary>
        /// <param name="assemblyWithMappings">The assembly containing the Fluent mappings.</param>
        /// <returns></returns>
        private ISessionFactory CreateSessionFactory(Assembly assemblyWithMappings)
        {
            var cfg = new Configuration();
            cfg = cfg.Configure();
    
            return Fluently.Configure(cfg)
                .Mappings(m =>
                          m.FluentMappings.AddFromAssembly(assemblyWithMappings))
                .BuildSessionFactory();
    
            //return cfg.BuildSessionFactory();
        }
    }
    

    HBM-Mappings
    My mappings are located in the assembly that contains the repositories and not in the assembly containing my entities. This since the mappings are for storage and not domain-logic, hence the entities that are mapped is located in a sepparate domain-assembly.

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping
        xmlns="urn:nhibernate-mapping-2.2"
        namespace="Sds.X.Domain" assembly="Sds.X"
        schema="dbo"
        default-access="property"
        default-lazy="true">
      
      <class name="UserAccount" table="UserAccounts">
        <id name="Id" type="Int32" unsaved-value="null">
          <generator class="identity" />
        </id>
        <property name="Username" type="String" not-null="true" unique-key="true" />
        <property name="Password" type="String" not-null="true" />
        <property name="Email" type="String" not-null="true" unique-key="true" />
      </class>
    </hibernate-mapping>
    

    Fluent Mappings
    My fluent-mappings are located in the same assembly as the one that contains my HBM-mappings.

    [Serializable]
    public class UserAccountMapping
        : ClassMap<UserAccount>
    {
        public UserAccountMapping()
        {
            Table("UserAccounts");
    
            Id(p => p.Id).GeneratedBy.Identity().Not.Nullable();
    
            Map(p => p.Username)
                .Not.Nullable()
                .Unique();
            Map(p => p.Email)
                .Not.Nullable()
                .Unique();
            Map(p => p.Password)
                .Not.Nullable();
        }
    }
    

    Repositories
    My repositories needs an injected NHibContext (preferably from a dependency injection framework), since the repository want’s to get an Unit of work from the Context. All repositories are defined by an interface that is designed to handle aggregate-root-entities. For simplicity I have defined an base-interface that specifies common operations that should exist through all my repositories, so my specific repository-interfaces inherits from this base-interface. Wy I work with interfaces is for being able to mock my repositories when performing tests. I also want to be able to create repositories that uses other persistence-technologies, like SubSonic, Linq-to-SQL or something else.

    public interface IRepository<T> where T : class
    {
        ITransaction CreateTransaction();
    
        void Insert(T item);
        void Update(T item);
        void Delete(T item);
    
        T SingleBy(Expression<Func<T, bool>> query);
    
        IList<T> List();
        IList<T> ListBy(Expression<Func<T, bool>> query);
    }
    

    For centralizing common functionality amongst my repositories i have created a base-class for my NHibernate-based repositories.

    public abstract class NHibRepository<T> : IRepository<T>
        where T : class, new()
    {
        protected NHibContext Context { get; private set; }
    
        protected NHibRepository(NHibContext context)
        {
            Context = context;
        }
    
        public virtual ITransaction CreateTransaction()
        {
            return new Transaction();
        }
    
        public virtual void Insert(T item)
        {
            using(var uow = Context.CreateUnitOfWork())
            {
                uow.Insert<T>(item);
                uow.SaveChanges();
            }
        }
    
        public virtual void Update(T item)
        {
            using (var uow = Context.CreateUnitOfWork())
            {
                uow.Update<T>(item);
                uow.SaveChanges();
            }
        }
    
        public virtual void Delete(T item)
        {
            using (var uow = Context.CreateUnitOfWork())
            {
                uow.Delete<T>(item);
                uow.SaveChanges();
            }
        }
    
        public virtual T SingleBy(Expression<Func<T, bool>> query)
        {
            T result;
    
            using (var uow = Context.CreateUnitOfWork())
            {
                result = uow.GetItemBy<T>(query);
            }
    
            return result;
        }
    
        public virtual IList<T> List()
        {
            IList<T> result;
    
            using (var uow = Context.CreateUnitOfWork())
            {
                result = uow.GetList<T>();
            }
    
            return result;
        }
        public virtual IList<T> ListBy(Expression<Func<T, bool>> query)
        {
            IList<T> result;
    
            using (var uow = Context.CreateUnitOfWork())
            {
                result = uow.GetListBy<T>(query);
            }
    
            return result;
        }
    }
    

    Consume the infrastructure (core-lib)
    So far we have mostly been dealing with basic infrastructure code that doesn’t change so much. Now lets look at how this is consumed in the “domain”. My repositories for my aggregates than looks like:

    public class UserAccountRepository : NHibRepository<UserAccount>, IUserAccountRepository
    {
        public UserAccountRepository(NHibContext context)
            : base(context)
        {}
    }
    

    Consuming the repository
    The code shown below uses a simple factory method. This is just for brevity. Usually I get the instance from an ObjectSpace that uses a dependecy-injection framework to resolve the correct implementation.

    [TestMethod]
    public void CanInsertSingleUser()
    {
        var newUserAccount = CreateUserAccount();
    
        IUserAccountRepository userRepository = CreateRepository();
        userRepository.Insert(newUserAccount);
    
        Assert.AreEqual(1, StorageTestHelper.RowCount(UserAccountsTableName));
    }
    
    private static IUserAccountRepository CreateRepository()
    {
        return new UserAccountRepository(StorageTestHelper.NHibContext);
    }
    

    Thats it for now. I hope you have found it interesting.

    //Daniel