Friday 28 December 2012

Enterprise Example Part 1

I have recently completed a cut down example of an entire enterprise, based on Event Driven Architecture:

Click here to get the code form GitHub. This blog post is based around commit 97d6ab2ab0.

To get this up and running, you should first have the NServiceBus examples downloaded and running succesfully. Then in download the code for this example, run the SQL Scripts in the root on your local databases, change all hibernate.cfg.xml files in the projects to point at your local SQL Server and run!

Overview


The enterprise consists of four systems:
  • Human Resources
  • Sales
  • Client Services
  • Finance
The term "Service" in this example relates to anything below the UI. The following rules are being followed for inter-service and ui-service communication:
  • UIs may only query external services using WCF.
  • UIs may send commands to services via NServiceBus messages. (This is currently synchronous but I will explore asynchronous communication is later posts.)
  • Services may only communicate with other services using events. (I may exploye asynchronous commands in later posts.)
The workflow for each system and how they interact are described below.


Sales


  • A sales consultant is presented with a list of leads. When a consultant returns from visiting a lead, they log this by clicking "Show Visits" and clicking "Log New".
  • The consultant fills in information about the visit.
  • When the consultant click "Create", a command is sent to the ‘Log Visit’ Message Handler in Sales, which adds a record about the visit.
  • If "Resulted in Deal" was not checked, the consultant is returned to the list of visits. If it was checked, the consultant is forwarded to the form to register a deal.
  • The consultant fills in this form and clicks "Create".
  • This sends a command to the "Register Deal" Message Handler in Sales, and also to "Initialize Client" Message Handler in Client Services.
  • The "Register Deal" handler adds a record about the deal, recording that consultant against it and calculating his or her commission.
  • The consultant is forwarded to the list of deals.
  • The consultant, Sales system and department are no longer concerned with this lead.
  • At any point, the system can receive an "Employee Left" event from Human Resources. In this situation, the relevant handler unassigns any leads assigned to that consultant.


Client Services


  • The "Initialize Client" command is received by the relevant Message Handler in the Client Services system.
  • This adds a record to the user’s list of clients to be activated, and adds an agreement with the start and end dates of the agreement, together with its value, as entered by the sales consultant.
  • The user clicks on "Activate" for the new client.
  • The user is presented with a form containing all information from the Sales system (name, address, phone number) which he or she must confirm. The user must also enter a reference for the client and a liaison whom they will deal with.
  • The user clicks "Activate".
  • A command is sent to the "Activate Client" Message Handler. This handler updates the information about the client and activates the current agreement. It also publishes an "Agreement Activated" event that the agreement has been activated.
  • The Client now moves from the list of ‘Clients Requiring Activation’ to the list of "Active Clients".
  • The user can then click on "Agreements" for any active clients to see the agreements (at this time it only show the current one).
  • The user can then click "Cancel" to signify that the client has cancelled the agreement. This sends a "Cancel Agreement" command. The handler for this marks the specified agreement as cancelled and raises an event to signal that this has happened.
  • At any point the system can receive a "Account Suspended" event from the Finance system. This signifies that the client’s account has been suspended (because they have fallen behind in their payments). The relevant handler picks this up and marks the corresponding agreement as suspended.
  • At any point, the system can receive an "Employee Left" event from Human Resources. In this situation, the relevant handler unassigns any clients assigned to that employee.


Finance


  • The "Agreement Activated" event is received by the relevant message handler in the Finance system. This opens a new Account and calculates all the monthly Installments that will need to be paid during the lifetime of the account.
  • The list of Accounts is displayed to the user. The user may click on "View Installments" to for any particular Account.
  • For each Installment, if the due date is not reached, it is marked as "Pending", if the due date has passed it is "Due", if it is ten days passed the due date it is marked as "Overdue". It the Account is closed it is marked as "NotRequired".
  • At any point, the user can click on "Mark As Paid" for an installment. This sends a command to the "Mark Installment As Paid" handler, which updates the domain accordingly. The Installment will then go to the "Paid" state.
  • Back in the list of Accounts, the user can click "Suspend" (if a client has fallen too far behind on their payments). This sends a command to the "Suspend Account" handler, which updates the domain and raises an "Account Suspended" event. (This is subscribed to by Client Services).
  • At any point, the system can receive and "Agreement Cancelled" event (raised by Client Services) and updates closes the corresponding Account.


Human Resources


  • Users of Human Resources can at any point mark an employee as left. This sends a "Mark Employee as Left" command to the Human Resources Message Handler, which updates the domain and raises the corresponding event (subsribed to by Sales and Client Services).


Shortcomings


It is important to not that many aspects of this code are not ideal. I am exploring EDA here, and do to limited time I have skimped on other areas. These areas include validation (both in the UI and the domain), user friendlines, and performance considerations. For example, currently Sales could fail if the user tries to register a Deal for a Lead that is unassigned. At some point it needs validation around this. It has not been done because it is not relevant to the concepts being explored here.

Error handling has not been implemented particularly well - I will be exploring this more in another post. This will probably involve returning ReturnCode.Error from MessageModule.HandleError() but I'm not sure yet.

Finally, The IOC implementation in my WCF services is a bit clumsy - I am still searching for a good solution to this.

In the event of an error, the system seems to retry forever. I'm not sure why it does this because I don't think this is default behviour in NServiceBus.


Upcoming Improvements


  • I would like to be able to book holidays for Employees in Human Resources. I would also like to be able to pre-book visits in the Sales system. These bookings should not be allowed to clash, so possibly some sort of central booking service is required.
  • When an employee is marked as left, as well as Leads being unassigned in Sales, and Clients being unassigned in Client Services, the manager of those departments should also be informed which Leads/Clients have been affected by email.
  • I would like to be able to issue an invoice from Finance. This would possibly be in the form of an email that would compose data form multiple services.
  • When a Deal is registered, the value is passed to Client Services and saved in the Agreement. Value has no real place in the Client Services domain – it is of no interest to them (under current specification). The only reason it is recorded is so that it can pass it to Finance when the agreement is activated, so Finance know how much to bill the client. There should be another way of getting this information to accounts – possibly using a Saga? Start and End dates of the Account could be passed through straight from the form rather than Client Services.
  • When a Client is initialised, no information is brought through (such as address lines, phone number, even name) except the Id. When the user activates the account, the UI queries Sales for the information so the user can confirm it, and it is then saved. It would be better if the information was passed straight into the initialised Account, but this information is not available on the register deal form. I will look into the possibility of using a Saga here to bring through this information.
  • In Client Services, Agreement has a possible status of Expired. This is not derived from the expiry date but it is a persistent value. The only way to ensure this is set correctly is to have a continuous polling service that would set it when the expiry date is reached. This could also be useful for raising an event for other domains.

Tuesday 2 October 2012

NHibernate: Filtering on Properties of Subtypes

Here's a useful tip I learned about NHibernate today. Say we have a task list, displaying details about entities of type Task. Various task types inherit from this. Once such type is 'ReviewDocumentTask'. This extends Task in that it has a reference to a Document entity. The base Task does not. The requirement is to filter out all tasks where the document has been deleted. How do we filter on this field, yet still treat tasks polmorphically? Two useful feature for this purpose are the ability to create an alias with a left outer join, and the ability to restrict on the 'class' property. The resulting code looks like this:
  
var result = SessionManager.Session
    .CreateCriteria<Task>();
    .CreateAlias("Document", "document", JoinType.LeftOuterJoin)
    .Add(Restrictions.Or(
        Restrictions.Not( 
            Restrictions.Eq("class", typeof(ReviewDocumentTask))
        ),
        Restrictions.Eq("document.Deleted", false))
    );

return result.List<Task>();

Wednesday 23 May 2012

Paul T Davies SOACP

I have just completed Module 2 of Thomas Erl's SOA School course, which apparently makes me an SOA Certified Professional!

Tuesday 22 May 2012

Business Logic Based on Large Data Sets

A collegue recently came to me with help on an architecture desicion: A client wants to add a site to their list of sites, and the system must check that the site does not already exist before adding it, creating a validation error if it does. Now the validation of the new site is clearly something that belongs in the domain, so surely this should be quite straightforward, possibly something like this (this is written off the top of my head, and practically psuedocode):
  
public class Site : Entity
{
    public ValidationMessageCollection ValidateCreateSite(string siteName, string addressLine1, string addressLine2)
    {
        //...

        List<Site> matchingSites = (from matchingSite 
                                    in _sites
                                    where matchingSite.SiteName.Equals(siteName)
                                    && matchingSite.AddressLine1.Equals(addressLine1)
                                    && matchingSite.AddressLine2.Equals(addressLine2)
                                    select matchingSite)
                                    .ToList();

        if (matchingSites.Count() > 0)
            validationMessageCollection.AddError("Similar site already exists.");

        //...
    }
}
OK, ignore the simplistic message, the actual logic behind wheter or not a site is the same as another and whether or not this even compiles, the problem I'm illustrating is based around the fact that a client may have thousands of sites, and to load them all would be wasteful on resourses and slow. Somehow we need the database to do the query, but the domain to do the logic.

Here is my solution - perform the query and then simply pass the result into the domain, and let it make a descision what to do based on the results:
  
public class SiteService
{
    public long AddSite(
        string siteName, 
        string addressLine1, 
        string addressLine2) //Or whatever
    {
        ISiteRepository siteRepository = new SiteRepository();

        bool similarSitesExist = 
            siteRepository.GetWhetherSimilarSitesExist(siteName, addressLine1, addressLine2)

        ValidationMessageCollection validationMessageCollection = 
            Site.ValidateCreateSite(siteName, addressLine1, addressLine2, similarSitesExist)

        if(validationMessageCollection.Count > 0) 
            throw new ValidationFaultException(validationMessageCollection);

        Site site = Site.Create(siteName, addressLine1, addressLine2);
        siteRepository.SaveInTransaction(site);
        return site.Id.Value;
    }
}

public class Site : Entity
{
    public ValidationMessageCollection ValidateCreate(
        string siteName, 
        string addressLine1, 
        string addressLine2, 
        bool similarSitesExist)
    {
        //...

        if (similarSitesExist)
            validationMessageCollection.AddError("Similar site already exists.");

        //...
    }
}
Or, if you want to return more information about the sites that exists, this could be an option:
  
public class SiteService
{
    public long AddSite(string siteName, string addressLine1, string addressLine2) //Or whatever
    {
        ISiteRepository siteRepository = new SiteRepository();

        List<Site> similarSites = 
            siteRepository.GetSimilarSites(siteName, addressLine1, addressLine2)

        ValidationMessageCollection validationMessageCollection = 
            Site.ValidateCreateSite(siteName, addressLine1, addressLine2, similarSiteAddresses)

        if(validationMessageCollection.Count > 0) 
            throw new ValidationFaultException(validationMessageCollection);

        Site site = Site.Create(siteName, addressLine1, addressLine2);
        siteRepository.SaveInTransaction(site);
        return siteAddress.Id.Value;
    }
}

public class Site : Entity
{
    public ValidationMessageCollection ValidateCreateSite(
        string siteName, 
        string addressLine1, 
        string addressLine2, 
        List<SiteAddress>> similarSites)
    {
        //...
              
        if(similarSites.Count() > 0)
        {
            string similarSiteAddressString = "Similar site addresses exist: ";
                     
            foreach(SiteAddress similarSiteAddress in similarSiteAddresses)
            {
                string = string + similarSiteAddress.Name + ", " + similarSiteAddress.AddressLine1;
            }
                     
            validationMessageCollection.AddError(similarSiteAddressString);
       }
              
       //...
    }
}

Monday 14 May 2012

Domain Based Security Part 2

Following on from my previous post, here is a more complex example of domain based security. Here are the business rules:
  • A user can edit their own tasks.
  • A basic user can edit another basic user's task, but not an admin user's task.
  • An admin user can edit an admin user's task or a basic user's task.
Again, the user entity will have a CanEditTask that takes a task as a parameter and returns a boolean.
There could be a list of permissions such as 'Edit tasks for basic user' or 'Edit tasks for admin user', but as the list of roles increases, this quickly becomes unmaintainable. It is more flexible to have a permission such as 'Edit tasks for users in role' which can be applied to a variety of roles. The way to do this is to break up the many-to-many relationship between the Role and Permission entities by inserting a new 'RolePermission' entity in the relationship. This entity links roles to the permission that they are entitled to and had references to the relevant Role and Permission entities, but has the benefit in that it can be inherited and introduce extra elements to the relationships.

For example a RolePermission object may hold a 'Basic user' role and a 'Edit own tasks' permission. This means that a basic user can edit their own tasks, but a RolePermissionForRole could inherit RolePermission, and this could have a 'Admin user' role, an 'Edit tasks for users in role' permission, and a RoleAppliesTo field of 'Basic user'. This means an admin user can edit tasks for a basic user. Here is how the UML class diagrams of the old and new systems compare.

First the previous system:


And the new one:


The user has a reference to it's own role, and consequently it's own permissions, and thus it knows which roles it is allowed to edit tasks of. The Task object has a reference to the User it is assigned to, and that user has has a reference it's role. So the CanEditTask method has access to all this information, and thus can work out whether the edit can take place. Here are the entites:
  
public class User : Entity
{
    protected string _username;
    protected Role _role;

    public virtual string Username
    {
        get { return _username; }
        set { _username = value; }
    }
               
    public virtual Role Role
    {
        get { return _role; }
        set { _role = value; }
    }

    public virtual bool CanEditTask(Task task)
    {
        List rolesWhosTasksCanBeEditied = _role
            .RolePermissions
            .Where(rolePermission => rolePermission.Permission.Key == PermissionKey.EditTaskForRole)
            .Cast()
            .Select(rolePermissionForRole => rolePermissionForRole.RoleAppliesTo)
            .ToList();

        if(rolesWhosTasksCanBeEditied.Contains(task.AssignedTo.Role))
            return true;
        else
            return false;
    }
}

public class Role : Entity
{
    protected string _rolename;
    private IList<RolePermission> _rolePermissions;

    public virtual string RoleName
    {
        get { return _rolename; }
        set { _rolename = value; }
    }

    public virtual IList<RolePermission> RolePermissions
    {
        get { return _rolePermissions; }
        set { _rolePermissions = value; }
    }
}

public class RolePermission : Entity
{
    protected Permission _permission;

    public virtual Permission Permission
    {
        get { return _permission; }
        set { _permission = value; }
    }
}

public class RolePermissionForRole : RolePermission
{
    private Role _roleAppliesTo;

    public virtual Role RoleAppliesTo
    {
        get { return _roleAppliesTo; }
        set { _roleAppliesTo = value; }
    }
}

public class Permission : Entity
{
    protected string _key;
    protected string _description;

    public virtual string Key
    {
        get { return _key; }
        set { _key = value; }
    }

    public virtual string Description
    {
        get { return _description; }
        set { _description = value; }
    }
}
public class Task : Entity
{
    private string _description;
    private User _assignedTo;

    public virtual string Description
    {
        get { return _description; }
        set { _description = value; }
    }

    public virtual User AssignedTo
    {
        get { return _assignedTo; }
        set { _assignedTo = value; }
    }
}
So now for the test to ensure this works as expected. A permission is created for editing a task for users in a specified role, and roles for basic user and admin user are created. Two RolePermissionForRole entities are created which give the permission to edit tasks, one for basic users' tasks, and one for admin users' tasks. Both of these RolePermissionForRole entities are added to the admin role, but only the RolePermissionForRole entity for editing a basic user's tasks is added to the basic user. Users and tasks are then created and it is asserted that a basic user can edit a basic user's task but not an admin user's task, and an admin user can edit both. Hope that makes sense! Here is the test to hopefully make it clearer:
  
[TestMethod]
public void CheckUserCanEditTasksBelongingToUsersInCertainRoles()
{
    Permission editTaskPermission = new Permission()
    {
        Key = PermissionKey.EditTaskForRole,
        Description = "Edit task for users in role."
    };

    Role basicRole = new Role()
    {
        RoleName = "Basic User",
        RolePermissions = new List<RolePermission>()
    };

    Role adminRole = new Role()
    {
        RoleName = "Admin User",
        RolePermissions = new List<RolePermission>()
    };

    RolePermissionForRole editTaskPermissionForBasicUser = new RolePermissionForRole()
    {
        Permission = editTaskPermission,
        RoleAppliesTo = basicRole
    };

    RolePermissionForRole editTaskPermissionForAdminUser = new RolePermissionForRole()
    {
        Permission = editTaskPermission,
        RoleAppliesTo = adminRole
    };

    basicRole.RolePermissions.Add(editTaskPermissionForBasicUser);
    adminRole.RolePermissions.Add(editTaskPermissionForBasicUser);
    adminRole.RolePermissions.Add(editTaskPermissionForAdminUser);

    User barryBasic = new User()
    {
        Username = "Barry Basic",
        Role = basicRole
    };

    User arnoldAdmin = new User()
    {
        Username = "Arnold Admin",
        Role = adminRole
    };

    Task arnoldsTask = new Task()
    {
        Description = "Arnold's Task",
        AssignedTo = arnoldAdmin
    };

    Task barrysTask = new Task()
    {
        Description = "Barry's Task",
        AssignedTo = barryBasic
    };

    Assert.IsFalse(barryBasic.CanEditTask(arnoldsTask));
    Assert.IsTrue(arnoldAdmin.CanEditTask(barrysTask));
}
And here is the NHibernate mapping files to map all this:
  
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="TaskLogger.Domain.Entities"
                   assembly="TaskLogger.Domain">
  <class name="User" table="`User`">
    <id name="Id" column="Id" type="long">
      <generator class="identity"/>
    </id>
    <property name="Username" type="string" />
    <many-to-one name="Role" class="Role" column="RoleId" cascade="save-update" />
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="TaskLogger.Domain.Entities"
                   assembly="TaskLogger.Domain">
  <class name="Role" table="`Role`">
    <id name="Id" column="Id" type="long">
      <generator class="identity"/>
    </id>
    <property name="RoleName" type="string" />
    <bag name="RolePermissions"  >
      <key column="RoleId"/>
      <one-to-many class="RolePermission"/>
    </bag>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="TaskLogger.Domain.Entities"
                   assembly="TaskLogger.Domain">
  <class name="RolePermission" table="`RolePermission`">
    <id name="Id" column="Id" type="long">
      <generator class="identity"/>
    </id>
    <many-to-one name="Permission" class="Permission" column="PermissionId" cascade="save-update" />

    <joined-subclass name="RolePermissionForRole" table="`RolePermissionForRole`">
      <key column="`Id`"/>
      <many-to-one name="RoleAppliesTo" class="Role" column="RoleAppliesToId" cascade="save-update" />
    </joined-subclass>
    
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="TaskLogger.Domain.Entities"
                   assembly="TaskLogger.Domain">
  <class name="Permission" table="`Permission`">
    
    <id name="Id" column="Id" type="long">
      <generator class="identity"/>
    </id>
    
    <property name="Key" column="`Key`" type="string"/>
    <property name="Description" type="string" />
    
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="TaskLogger.Domain.Entities"
                   assembly="TaskLogger.Domain">
  <class name="Task" table="`Task`">
    <id name="Id" column="Id" type="long">
      <generator class="identity"/>
    </id>
    <many-to-one name="AssignedTo" class="User" column="AssignedToId" cascade="all" />
    <property name="Description" type="string" />
  </class>
</hibernate-mapping>

Sunday 13 May 2012

Domain Based Security Part 1

While I believe some elements of security should be in a centralised Security Service (such as general details about a user, what areas of the enterprise a user is allowed access to), I also believe some elements of security belong in the domain of a specific system, because the rules that surround the security are tied up with the business rules of the application. I'm going to use a task logging system as an example, and focus on a user's ability to edit a task.
So here are the business rules:
  • A basic user can edit their own tasks, but not the tasks of another user.
  • An admin user can edit their own tasks and the tasks of other users.
The user entity should have a method to test it they can edit a task, which takes the task in question as a parameter and returns a boolean that is true if they can. The user has a reference to it's own role, and consequently it's own permissions, and thus knows if it is allowed to edit its own or other user's task. The Task object has a reference to the user it is assigned to. So the CanEditTask method has access to all this information, and thus can work out whether the edit can take place. Here are the entites:
  
public class User : Entity
{
    protected string _username;
    protected Role _role;

    public virtual string Username
    {
        get { return _username; }
        set { _username = value; }
    }
               
    public virtual Role Role
    {
        get { return _role; }
        set { _role = value; }
    }

    public virtual bool CanEditTask(Task task)
    {
        if (task.AssignedTo == this && _role.Permissions.Select(permission => permission.Key).Contains(PermissionKey.EditOwnTask))
            return true;

        if (_role.Permissions.Select(permission => permission.Key).Contains(PermissionKey.EditAnotherUsersTask))
            return true;

        return false;
    }
}

public class Role : Entity
{
    protected string _rolename;
    private IList _permissions;

    public virtual string RoleName
    {
        get { return _rolename; }
        set { _rolename = value; }
    }

    public virtual IList Permissions
    {
        get { return _permissions; }
        set { _permissions = value; }
    }
}

public class Permission : Entity
{
    protected string _key;
    protected string _description;

    public virtual string Key
    {
        get { return _key; }
        set { _key = value; }
    }

    public virtual string Description
    {
        get { return _description; }
        set { _description = value; }
    }
 }

 public class Task : Entity
 {
    private string _description;
    private User _assignedTo;

    public virtual string Description
    {
        get { return _description; }
        set { _description = value; }
    }

    public virtual User AssignedTo
    {
        get { return _assignedTo; }
        set { _assignedTo = value; }
    }
}

public static class PermissionKey 
{
    public const string EditAnotherUsersTask = "EditAnotherUsersTask";
    public const string EditOwnTask = "EditOwnTask";
    public const string EditTaskForRole = "EditTaskForRole";
}
So the section to focus on is the CanEditTask(Task) method of the User entity. Here is the code for the test, which creates the permissions for editing tasks, creates the basic and admin roles with the required permissions, creates the users with their roles and creates tasks assigned to those user. It then asserts that the correct users can edit the required users tasks.
  
[TestClass]
public class UserTests
{
    [TestMethod]
    public void CheckUserCannotEditAnotherUsersTask()
    {
        Permission editAnotherUsersTaskPermission = new Permission()
        {
            Key = PermissionKey.EditAnotherUsersTask,
            Description = "Edit another user's task"
        };

        Permission editOwnTaskPermission = new Permission()
        {
            Key = PermissionKey.EditOwnTask,
            Description = "Edit own task"
        };

        Role basicRole = new Role()
        {
            RoleName = "Basic User",
            Permissions = new List()
            {
                editOwnTaskPermission
            }
        };

        Role adminRole = new Role()
        {
            RoleName = "Admin User",
            Permissions = new List()
            {
                editAnotherUsersTaskPermission
            }
        };

        User barryBasic = new User()
        {
            Username = "Barry Basic",
            Role = basicRole
        };

        User arnoldAdmin = new User()
        {
            Username = "Arnold Admin",
            Role = adminRole
        };

        Task arnoldsTask = new Task()
        {
            Description = "Arnold's Task",
            AssignedTo = arnoldAdmin
        };

        Task barrysTask = new Task()
        {
            Description = "Barry's Task",
            AssignedTo = barryBasic
        };

        Assert.IsTrue(barryBasic.CanEditTask(barrysTask));
        Assert.IsFalse(barryBasic.CanEditTask(arnoldsTask));
        Assert.IsTrue(arnoldAdmin.CanEditTask(barrysTask));
    }
}
And finally, here is the NHibernate mapping files to map all of this:
  


  
    
      
    
    
    
  





  
    
      
    
    
    
      
      
    
  





  
    
    
      
    
    
    
    

    
      
      
    
    
  




  
    
      
    
    
    
  

Wednesday 2 May 2012

Changing the Type of an Entity - Persistence with NHibernate

This is a follow up to my previous post which can be found here

So we have an Employee class and a Manger subclass, here are the classes:
  
    public class Employee : Entity
    {
        private string _name;
        private string _payrollNumber;
        private DateTime _joinedOn;

        public virtual string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public virtual string PayrollNumber
        {
            get { return _payrollNumber; }
            set { _payrollNumber = value; }
        }

        public virtual DateTime JoinedOn
        {
            get { return _joinedOn; }
            set { _joinedOn = value; }
        }

        public static Employee Create(string role, string name, string payrollNumber, string department)
        {
            Employee employee = null;

            if (role == "Manager")
            {
                employee = new Manager();
                Manager manager = employee as Manager;
                manager.Department = department;
                manager.BecameManagerOn = DateTime.Now;
            }
            else
            {
                employee = new Employee();
            }

            employee.Name = name;
            employee.PayrollNumber = payrollNumber;
            employee.JoinedOn = DateTime.Now;
            return employee;
        }

        public void Amend(string name, string payrollNumber, DateTime joinedOn)
        {
            _name = name;
            _payrollNumber = payrollNumber;
            _joinedOn = joinedOn;
        }

        public virtual Manager Promote(string department)
        {
            Manager manager = new Manager();
            manager.Id = _id;
            manager.Name = _name;
            manager.PayrollNumber = _payrollNumber;
            manager.JoinedOn = _joinedOn;
            manager.Department = department;
            manager.BecameManagerOn = DateTime.Now;
            return manager;
        }

    }

    public class Manager : Employee
    {
        private string _department;
        private DateTime _becameManagerOn;

        public virtual string Department
        {
            get { return _department; }
            set { _department = value; }
        }

        public DateTime BecameManagerOn
        {
            get { return _becameManagerOn; }
            set { _becameManagerOn = value; }
        }
    }

    public class Entity
    {
        protected long? _id;
        protected int? _hashCode;

        public virtual long? Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public override bool Equals(object obj)
        {
            Entity other = obj as Entity;
            if (other == null) return false;
            if (!other.Id.HasValue && !_id.HasValue) return other == this;
            if (!other.Id.HasValue || !_id.HasValue) return false;
            return other.Id.Value == _id.Value;
        }

        public override int GetHashCode()
        {
            if (_hashCode.HasValue) return _hashCode.Value;

            if (!_id.HasValue)
            {
                _hashCode = base.GetHashCode();
                return _hashCode.Value;
            }

            return _id.GetHashCode();
        }
    }
And here are how they are mapped in NHibernate:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="HRSystem.Domain.Entities"
                   assembly="HRSystem.Domain">
  <class name="Employee" table="`Employee`">
    
    <id name="Id" column="Id" type="long">
      <generator class="identity"/>
    </id>
    
    <property name="Name" type="string" />
    <property name="PayrollNumber" type="string" />
    <property name="JoinedOn" type="datetime" />

    <joined-subclass name="Manager" table="`Manager`">
      <key column="`Id`"/>
      <property name="Department" type="string" />
      <property name="BecameManagerOn" type="datetime" />
    </joined-subclass>
    
  </class>
</hibernate-mapping>
A common question on Stack Overflow is about changing from one class to an inherited subclass in NHibernate. Here are some examples:

Convert type of entity to subtype with NHibernate/Hibernate
Can you change from a base class to a joined subclass type in nhibernate?
Is it ever valid to convert an object from a base class to a subclass
NHibernate - Changing sub-types

One common response is that one should use composition over inheritance. In the case of our Employee/manager example, this would mean (for example) that everyone in the company would be represented by an Employee entity. Each Employee entity would have a Role entity which would be subclassed to the respective role (BasicEmployee, Manager, etc), and any varying behaviour is deferred to the Role class. see Design Patterns by the Gang Of Four for more about favouring composition over inheritance.

This is the correct approach when it is the behaviour that varies, but in our case, Manager has some extra fields, and composition over inheritance doesn't account for this. We need somewhere to store the extra fields, and inheritance is a good solution to this.

Some people suggest that the employee object should have a ManagerFields objects, where fields specific to a manager role ('_department', '_becameManagerOn') would be stored if the employee is a manager, and would be null if not. Or even, just have nullable fields '_department' and '_becameManagerOn' on Employee that are only used if the Employee is a manager. You have to ask yourself if you would do this if you were not using NHibernate?

Some people suggest that if you are using inheritance, then to promote an Employee to Manager, you should use native SQL to insert a record into the manager table, so when you next get the Employee it will cast to manager. This doesn't even warrant discussion.

The answer, that some people touch on on in the StackOverflow questions, is that you need to to delete the old entity, and replace it with the new entity. This seems quite straightforward, but there is one aggrevating factor: often we would want it to keep the same ID, as this may be a foreign key in other entities. (This is not a problem if the entity being changed is a child in an aggregate, as the aggregate root would have all the references, and would be doing all the updating so could update these references.) But what if it is an aggregate root? What if other entities in the domain, or even other domains/systems reference it? We need a way to preserve the ID.

Replacing Entities While Maintaining the Identity - GUIDs


One answer is to use GUIDs instead of auto incrementing IDs, this way assigned identites can be used. In this situation, it is not too much of a problem to delete the old Employee entity and save the new Manager entity which has the same ID. This way, when any entity is loaded that references the Employee, it will load the Manager entity. The code for the base entity would now look like this:
    public class Entity
    {
        protected Guid? _id;    //Changed from long?
        protected int? _hashCode;

        public virtual Guid? Id    //Changed from long?
        {
            get { return _id; }
            set { _id = value; }
        }

        //Implementation of Equals() and GetHaskCode() etc...
    }
The mapping files now look like this:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="HRSystem.Domain.Entities"
                   assembly="HRSystem.Domain">
  <class name="Employee" table="`Employee`">
    
    <id name="Id" column="Id" type="guid">
      <generator class="assigned"/>
    </id>
    
    <property name="Name" type="string" />
    <property name="PayrollNumber" type="string" />
    <property name="JoinedOn" type="datetime" />

    <joined-subclass name="Manager" table="`Manager`">
      <key column="`Id`"/>
      <property name="Department" type="string" />
      <property name="BecameManagerOn" type="datetime" />
    </joined-subclass>
    
  </class>
</hibernate-mapping>
Remember what the Promote code lookes like?
        public virtual Manager Promote(string department)
        {
            Manager manager = new Manager();
            manager.Id = _id;       //Especially pay attention to this line!!!
            manager.Name = _name;
            manager.PayrollNumber = _payrollNumber;
            manager.JoinedOn = _joinedOn;
            manager.Department = department;
            manager.BecameManagerOn = DateTime.Now;
            return manager;
        }
Now the code for a service to promote an Employee to a Manager looks like this:
using System;
using NHibernate;
using NHibernate.Cfg;
using HRSystem.Domain.Entities;

namespace HRSystem.Application.Implementations
{
    public class EmployeeService
    {
        public void Promote(Guid employeeId, string department)
        {
            Configuration configuration = new Configuration();
            configuration.Configure();
            configuration.AddAssembly("HRSystem.Data");
            ISessionFactory sessionFactory = configuration.BuildSessionFactory();
            ISession session = sessionFactory.OpenSession();
            Employee employee = session.Get<Employee>(employeeId);
            Manager manager = employee.Promote(department);

            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(employee);
                session.Save(manager);
                transaction.Commit();
            }
        }
    }
}
This is all quite straigntforward. This application service loads the Employee, gets a Manager version of it, deletes the Employee and then Saves the Manager in its place, with the same Id. Now when you go to load an Employee with the same Id, it will return an entity of type Manager. No need to update any other entities that have references to the entity because they will load the new Manager entity, because the ID has not changed.

Replacing Entities While Maintaining the Identity - Auto Incrementing IDs


The problem comes when you are trying to do this in system that uses auto-incrementing ints or bigints as IDs. This is when things start to get a bit messy. You need to do two things: first you need to dynamically manipulate the NHibernate configuration so the Id of the Employee class can be assigned. Secondly, we need to allow the identity to be inserted in the database, and the only way to do this (that I know of) is to use native SQL. Assume the Entity class and mapping file have reverted back to using auto-increment IDs, the way they were at the beginning of this post. The resulting code for the application service now looks like this:
using System;
using NHibernate;
using NHibernate.Cfg;
using HRSystem.Domain.Entities;

namespace HRSystem.Application.Implementations
{
    public class EmployeeService
    {
        public void Promote(Guid employeeId, string department)
        {
            Configuration configuration = new Configuration();
            configuration.Configure();
            configuration.AddAssembly("HRSystem.Data");

            //Get the class mapping for the Employee entity.
            var employeeClassMapping = (from classMapping 
                     in configuration.ClassMappings 
                     where classMapping.MappedClass == typeof(Employee)
                     select classMapping).FirstOrDefault();

            //Change the identifier strategy to assigned dynamically.
            (employeeClassMapping.Identifier as SimpleValue).IdentifierGeneratorStrategy = "assigned";

            ISessionFactory sessionFactory = configuration.BuildSessionFactory();
            ISession session = sessionFactory.OpenSession();
            Employee employee = session.Get<Employee>(employeeId);
            Manager manager = employee.Promote(department);

            using (ITransaction transaction = session.BeginTransaction())
            {
                //First delete the Employee entity.
                session.Delete(employee);

                //Native SQL to allow identity insert.
                session.CreateSQLQuery("SET IDENTITY_INSERT Employee ON").ExecuteUpdate(); 

                //Then save the Manager entity.
                session.Save(manager);

                //This is needed to ensure manager is saved while identity insert is on.
                session.Flush(); 

                //Native SQL to disallow identity insert.
                session.CreateSQLQuery("SET IDENTITY_INSERT Employee OFF").ExecuteUpdate(); 

                transaction.Commit();
            }
        }
    }
}
I never said it would be pretty but it works.

Changing the Type of an Entity - Domain

Occasionally, there are times where it makes sense to transform an entity from one type to another. Take the example of a Manager entity which inherits from an Employee entity. At some point an Employee may be promoted to a manager. Here is the code for the Employee entity, including a factory class for creation and a class to amend the entity:
  
using System;
using HRSystem.Domain.Common;

namespace HRSystem.Domain.Entities
{
    public class Employee : Entity
    {
        private string _name;
        private string _payrollNumber;
        private DateTime _joinedOn;

        public virtual string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public virtual string PayrollNumber
        {
            get { return _payrollNumber; }
            set { _payrollNumber = value; }
        }

        public virtual DateTime JoinedOn
        {
            get { return _joinedOn; }
            set { _joinedOn = value; }
        }

        public static Employee Create(string role, string name, string payrollNumber, string department)
        {
            Employee employee = null;

            if (role == "Manager")
            {
                employee = new Manager();
                Manager manager = employee as Manager;
                manager.Department = department;
                manager.BecameManagerOn = DateTime.Now;
            }
            else
            {
                employee = new Employee();
            }

            employee.Name = name;
            employee.PayrollNumber = payrollNumber;
            employee.JoinedOn = DateTime.Now;
            return employee;
        }

        public void Amend(string name, string payrollNumber, DateTime joinedOn)
        {
            _name = name;
            _payrollNumber = payrollNumber;
            _joinedOn = joinedOn;
        }
    }
}
And here is the code for the Manager entity:
  
using System;

namespace HRSystem.Domain.Entities
{
    public class Manager : Employee
    {
        private string _department;
        private DateTime _becameManagerOn;

        public virtual string Department
        {
            get { return _department; }
            set { _department = value; }
        }

        public DateTime BecameManagerOn
        {
            get { return _becameManagerOn; }
            set { _becameManagerOn = value; }
        }
    }
}
Please note that these both ultimately inherit from the Entity class, which should be familliar to any regular users of NHibernate:
  
using System;
using HRSystem.Domain.Entities;

namespace HRSystem.Domain.Common
{
    public class Entity
    {
        protected long? _id;
        protected int? _hashCode;

        public virtual long? Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public override bool Equals(object obj)
        {
            Entity other = obj as Entity;
            if (other == null) return false;
            if (!other.Id.HasValue && !_id.HasValue) return other == this;
            if (!other.Id.HasValue || !_id.HasValue) return false;
            return other.Id.Value == _id.Value;
        }

        public override int GetHashCode()
        {
            if (_hashCode.HasValue) return _hashCode.Value;

            if (!_id.HasValue)
            {
                _hashCode = base.GetHashCode();
                return _hashCode.Value;
            }

            return _id.GetHashCode();
        }
    }
}
So how do we model the promotion of an Employee to a Manager? Perhaps a method on the Employee called Promote, like the following code. Note that in order to change the Employee to a Manager, the extra parameters that a Manager has need to be supplied:

  
        public void Promote(string department)
        {
            //Make the class I'm in a Manager, not an Employee...
        }
The problem with this is that method would somehow have to change the type of the class it belongs to. This is not possible, not in C#, not in Java, not in any OO language.

In Domain Driven Design, Eric Evans makes the case for factory methods. The arguments is that on a car, the methods represent things like the accelerator or brake, which change the state of the car. However, the car does not carry around the ability to build itself - that is done in a factory. But what if we really wanted to change the state of the car? I'm talking tuned engine, new alloys, new paint job, new ICE etc. Unfortunately my car doesn't have a button for that - I have to take it to the garage. When it comes back, it's hardly the same car. The car entity could have a myRide.Pimp() method, and what comes back from that is a whole new car.

For the Employee, the method would look something like this:
  
        public virtual Manager Promote(string department)
        {
            Manager manager = new Manager();
            manager.Id = _id;
            manager.Name = _name;
            manager.PayrollNumber = _payrollNumber;
            manager.JoinedOn = _joinedOn;
            manager.Department = department;
            manager.BecameManagerOn = DateTime.Now;
            return manager;
        }
The code to promote an employee to the manager of ICT would look like this:
  
            Manager manager = employee.Promote("ICT");
I'm not completely sure that Promote(string department) is the quite the right name for this, it should possibly be something like 'GetPromotedVersion(string department)', but I feel it is acceptable in this instance.

The next stage is how to load the Employee and then persist it as a Manager, which I will cover in the next post.

Wednesday 4 April 2012

Domain Modelling Training Session 2

Last Friday saw the practical part of my Domain Modelling Training Session. This time the 'add to cart' functionality was in place, and it was the purpose of the rask to add the 'place order functionality', following the rules and guidelines set down in the last session. The specifications for this were:
  • Place an Order with an OrderLine for each book.
  • OrderLine must record price of book.
  • Order must record total book price in Cart.
  • Order must also record shipping cost of £2 + 50p per book.
  • Order must record grand total.
Another part of the test was for the developers to begin with the Domain unit tests, then move on to develop the Domain, then the Application Layer, then the UI.
Here are some examples of what was produced:
 

Domain Unit Test Code


public static Order Place(Cart cart)
{
    Order order = new Order();
           
    foreach (Book book in cart.Books)
    {
        order._orderLines.Add(new OrderLine { Book = book, PricePaid = book.Price });
        order._booksTotal += book.Price;
    }
    order._shippingCost = 2f + (cart.Books.Count * .5f);
    order._grandTotal = order._booksTotal + order._shippingCost;     
    return order;
}

Domain Code


[TestClass]
public class OrderTest
{
    [TestMethod]
    public void CanPlaceOrder()
    {
        Cart cart = new Cart();
        Book book = new Book()
        {
            Id = 1,
            AuthorName = "Robert C. Martin",
            Title = "Agile Principles, Patterns and Practices in C#",
            Price = 35.00f
        };
        cart.AddBook(book);
        Order myOrder = Order.Place(cart);
        Assert.AreEqual(myOrder.OrderLines.Count, 1);
        Assert.AreEqual(myOrder.OrderLines[0].Book.Id, 1);
        Assert.AreEqual(myOrder.OrderLines[0].PricePaid, 35.00F);
        Assert.AreEqual(myOrder.BooksTotal, 35.00F);
        Assert.AreEqual(myOrder.GrandTotal, 37.50F);
        Assert.AreEqual(myOrder.ShippingCost, 2.5F);
    }
}

Application Layer Code


public long Place()
{
    ICartRepository cartRepository = new CartRepository();
    IOrderRepository orderRepository = new OrderRepository();
    Cart cart = cartRepository.GetByUserName(Thread.CurrentPrincipal.Identity.Name)
    Order placedOrder = Order.Place(cart);

    using (ITransactionProvider transactionProvider = new TransactionProvider())
    {
        transactionProvider.BeginTransaction();
        orderRepository.Save(placedOrder);
        transactionProvider.CommitTransaction();
    }

    return placedOrder.Id.Value;
}

UI code is simply one line calling this method.

Monday 26 March 2012

Domain Modelling Training Session 1

On Friday I hosted a training session about Domain Modelling. The session was preceeded with some 'homework', a small task I set my collegues. I created a classic e-commerce website which had a list of books, and a button to add a book to the cart. The system was built as the usual UI sitting on top of an Application Layer, which sat on and the Domain, and a Data Layer (which uses NHibernate). However, the code in the 'AddToCart' event was missing:

protected void gvBooks_RowCommand(object sender, GridViewCommandEventArgs e)
{
    if (e.CommandName == "AddToCart")
    {
        long bookId = Convert.ToInt64(e.CommandArgument);
        //ADD YOUR CODE HERE!!!
        PopulateCartGrid();
    }
}

One requirement was that the total for the cart had to be calculated, and persisted in the database.

There was also a second stage of the homework which required a discount to be added of £5 for each different book that was added, so only 1 book gets no discount, 2 of the same book gets no discount, 2 different books gets £5 discount, 3 different books get £10 discount etc.

Here are some of the proposed solutions, starting with the code in the UI and working down:

User Interface Code


Here are some examples of the submissions for code in the UI, showing how the UI interacts with the Application Layer:

Example 1


ICartService cartService = new CartService();
Cart cart = cartService.GetCurrentUsersCart(); 
IBookService bookService = new BookService();
Book book = bookService.GetById(bookId);
cart.AddBook(book);
cartService.Save(cart);

This code has three calls to the application layer to add the book to the cart, including a Save() service that takes an entity as a parameter (something that should be avoided). Also, here we have UI code calling a method on an entity, something which should also be avoided, and would be impossible if using DTOs or WCF.

Example 2


ICartService cartService = new CartService();
IBookService bookService = new BookService();
var book = bookService.GetById(bookId);
Cart cart = cartService.GetCurrentUsersCart();
cartService.AddItemtoCart(cart,book);

This is an improvement. There are still three calls to the UI, but no methods being called on the Cart entity, and there is no Save service which takes an entity as a parameter. The AddItemToCart service performs the logic associated with adding the item to the cart and then persists it, all in one shot. But the consumer of the service has to get the Cart and Book entities before calling AddItemToCart. This could be encapsulated further by passing the IDs only.

Example 3


ICartService cartService = new CartService();
cartService.AddBook(bookId);

This is all that is required. It is not even required to pass in the user name, because the Application Layer is running in the same process, and because the UI uses Windows authentication, the Application Layer can get the user from the principal identity. All that is needed is the bookId. The service can then load the book by the ID, the cart by the username, perform any business logic and then save the result.

Summary


All commands should be done in one service call. A command can be defined as anything that changes the state of the business, or anything where a user presses a 'Submit' button. The reason for this is that this may not be the only consumer of this service, there may be a mobile App that consumes it, or possibly another service. This example is trivial, but if the system starts accessing the file system, or interacting with other services, the code can become very comlpex. Any systems consuming the service would have to replicate all required code.

Application Layer Code


Example 1


public void AddBook(Cart cart, long bookId)
{
    BookService bookService = new BookService();
    Book selectedBook = bookService.GetById(bookId);
    cart.Books.Add(selectedBook);
    cart.Total = (from b in cart.Books select b.Price).Sum();
}

This submission is from before the addition of the extra requirement for discounts. This shows an example of a service call in which the Cart has to have been loaded externally, and which which the Cart has to be saved externally. Another problem here is that the business logic of calculating the total is contained in the Application Layer, not the Domain.

Example 2


public void AddItemtoCart(Cart cart, Book book)
{
    ICartRepository cartRepository = new CartRepository();
    cart.AddItem(book);
    using (ITransactionProvider transactionProvider = new TransactionProvider())
    {
        transactionProvider.BeginTransaction();
        cartRepository.SaveOrUpdate(cart);
        transactionProvider.CommitTransaction();
    }
}

This example is an improvement, because the business logic is encapsulated in the Cart entity. This business logic is called from the service, and then the entity is saved, all in a single serive call. However, the Cart and Book entitys must be loaded and apssed to the service before it can be used, so it is not completely encapsulated.

Example 3


public void AddBook(long bookId)
{
    ICartRepository cartRepository = new CartRepository();
    IBookRepository bookRepository = new BookRepository();   
    Cart cart = cartRepository.GetByUserName(Thread.CurrentPrincipal.Identity.Name);
    Book book = bookRepository.GetById(bookId);
    cart.AddBook(book);
    using (ITransactionProvider transactionProvider = new TransactionProvider())
    {
        transactionProvider.BeginTransaction();
        cartRepository.Save(cart);
        transactionProvider.CommitTransaction();
    }
}

In this example, the Book is loaded from the ID passed in, the Cart is loaded from the current security principle identiy name, the business logic is called on the Cart (passing in the Book) and then the Cart is saved. This is all encapsulated into one call.

Domain


Example 1


public virtual void AddItem(Book book)
{
    if (Books == null)
    {
        Books = new List<Book>();
    }

    Books.Add(book);
    Total = _books.Sum(b=>b.Price);
}

In the examples where the Cart entity had an 'AddBook' or similar method which took a Book entity as a parameter, the logic was encapsulated in the Domain (this example was from before the discount requirement). However, one problem here is that the entity is accessing its own public 'set' properties.

Example 2


public virtual void AddBook(Book book)
{
    _books.Add(book);
    float discount = ((from curBook in _books select curBook).Distinct().Count() - 1) * 5f;
    _total = (from curBook in _books select curBook.Price).Sum() - discount;
}

In this example (which includes the discount requirement), the entity is accessing its private member variables. We can create a rule that the 'set' properties should not be used at all (I will keep them in for NHibernate, although I believe it is possible for NHibernate to use the private members - I will review this). The private member variables should only be ammended through methods that reflect use cases. This was the entities will adhere to OO principles and will reflect the business more acurately.

Unit Tests


[TestMethod]
public void AddingTwoDifferentBooksGivesDiscount()
{
    Cart cart = new Cart();

    Book book1 = new Book()
    {
        Id = 1,
        AuthorName = "Robert C. Martin",
        Title = "Agile Principles, Patterns and Practices in C#",
        Price = 35.00f
    };

    Book book2 = new Book()
    {
        Id = 2,
        AuthorName = "Martin Fowler",
        Title = "Patterns of Enterprise Application Architecture",
        Price = 30.00f
    };


    cart.AddBook(book1);
    cart.AddBook(book2);
    Assert.AreEqual(60.00f, cart.Total);
}

One way of ensuring that the Domain has been developed correctly is to check that tests for business logic can be written against the Domain which touch only the Domain and nothing else, as in this example (of course, if you are following TDD, the tests should be written first).

Summary


The lessons learnt from this training session can be summarised in this following list of rules and guidances:

  • All commands which change the state of the business (equivalent to pressing ‘Submit’ button) should be encapsulated in one service call.
  • Never have a ‘Save’ service operation which takes an entity (or DTO of an entity) as a parameter.
  • Never call methods of entities in the UI.
  • Services usually just load entities, call business logic in domain, and save. *
  • Command services should have names that reflect use cases, and call methods on entities with a similar name. *
  • Business logic should be contained in the entities.
  • You should be able to write tests for the business logic that touch the Domain and nothing else.
  • Do not use ‘set’ properties of entities – entity state can only be changed through methods that have names that reflect use cases.

* These are guidances rather than hard rules.