var blog = new ThoughtStream(me); RSS 2.0
 Monday, March 31, 2008

A while back, I posted a stream of thoughts concerning programming in triples. The basic idea is that we have 2 developers doing pair programming and a third developer doing automated acceptance test development, on the same story at the same time.

Triples Programming Terms

I've been discussing this idea with various people since then, and I'm finding myself referring to this team organization with a specific term, now:

Pair+1 Programming

I don't know if this term has been used previously, or if there is already a term for this. However, I find this to be a good name for the organization that I am talking about.  It really is pair programming, as defined by many common sources, plus one acceptance test developer. The really fun part is that all three of the developers in this unit will switch roles throughout the day. The end result is that we have a very well cross-trained team - each member of each unit will be responsible for writing unit tests, writing production code, writing acceptance tests, and thinking ahead of the current code, throughout any given day.

An Agile Team includes more than just the developers - the customers, the test lead, the technical writers, the project manager, etc., are all part of the team. Pair+1 Programming is not into teams. A "team" implies that they the persons involved are fairly static - they don't move between teams, etc. In order to distinguish the Pair+1 organization from the Team as a whole, I am also going to refer to this group with another name:

Development Unit (Update: based on further discussion, renaming this)

WorkCell

Just as a developer will rotate rolls within the Unit, I believe Pair+1 programmers should move between WorkCells on a regular basis. This will further the cross-training that occurs and help to pollinate the knowledge of one WorkCell into the thoughts and goals of other WorkCells. The migration is likely to be less volatile than the role switching that happens within a WorkCell. For example, developers rotate positions every 2 or 3 hours, within the WorkCell, whereas a developer may only rotate between WorkCells once a day or once a week.

Development Systems

Within each Development Unit, there will be two development systems.

  1. The primary system of that Unit will be the pair programming system. This system should have a very large monitor - 30" is preferable - to allow the Pair to easy see everything on the screen.
  2. The secondary system will be used for Acceptance Tests and is likely to only need a 22" or 24" monitor, as it will be primarily used by a single developer.

Each of these systems, aside from monitor size, should be a mirror of each other - the same system specs with the same software development packages installed. Every machine used for development should be able to execute any of the tests - unit tests or acceptance tests - no matter the primary use of that development machine. This is required so that the Pair working on the Development machine can execute the Acceptance Tests being created on the Acceptance Test machine; thus ensuring that they are coding appropriately, and passing the expected tests. The Acceptance Test developer should also be able to execute the code being written by the Pair, to ensure that the Acceptance Tests are being written against the API correctly.

Following standard Agile practices, these machines should not be concerned with Email, IM, or other non-development tasks. They should be dedicated entirely to development work. If a person needs Email, IM, etc. then the office space should provide access via shared systems and/or a developer should have their own system (likely a laptop) that they can take with them wherever they go. The point is, though, to remove distraction from the Development Unit. Keep the non-development software off the Unit's systems, as much as possible, to ensure that the Unit can focus on development and not be distracted by 50 different flashing icons and windows on the machine.

Disclaimer

A lot of my thoughts are purely academic, at this point. I am hopefully going to have some actual experience with this environment, soon. As such, I am trying to organize my thoughts so that I can have some direction to start with. I reserve the right to be wrong and change my mind whenever I want, likely re-defining the terms and processes involved in Pair+1 Programming.

Monday, March 31, 2008 2:26:19 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Acceptance Testing | Agile | Behavior Driven Development | Management | Pair+1 Programming | Unit Testing

In my previous post, I talked about my base repository class that I use, to abstract the NHibernate details away from the actual repository. Now that I have the Do and DoTransaction methods to further the abstraction, I thought it would be good to share my whole abstraction.

using System;
using NHibernate;
using NHibernate.Cfg;
 
namespace RepositoryBase
{
 
    public abstract class Repository : IDisposable
    {
 
        #region Vars
 
        private static readonly Configuration _config;
 
        private static readonly ISessionFactory _factory;
 
        #endregion
 
        #region Constructor / Destructor
 
        static BaseDAL()
        {
            _config = new Configuration();
            _config.Configure(typeof(BaseDAL).Assembly, "RepositoryBase.hibernate.cfg.xml");
            _factory = _config.BuildSessionFactory();
        }
 
        ~BaseDAL()
        {
            Dispose();
        }
 
        #endregion
 
        #region Properties
 
        public ISession Session { get; private set; }
 
        public ITransaction Transaction { get; private set; }
 
        #endregion
 
        #region Methods
 
        protected void Do(Action unitOfWork)
        {
            try
            {
                OpenSession();
                unitOfWork();
            }
            finally
            {
                CloseSession();
            }
        }
 
        protected void DoTransaction(Action unitOfWork)
        {
            try
            {
                OpenSession();
                BeginTransaction();
                
                if (unitOfWork != null)
                    unitOfWork();
                
                CommitTransaction();
            }
            catch
            {
                RollbackTransaction();
                throw;
            }
            finally
            {
                CloseSession();
            }
        }
 
        #endregion
 
        #region Helper Methods
 
        private void OpenSession()
        {
            if (Session != null) return;
 
            Session = _factory.OpenSession();
            Session.FlushMode = FlushMode.Auto;
        }
 
        private void CloseSession()
        {
            if (Session == null) return;
 
            if (Session.IsOpen)
            {
                Session.Close();
            }
            Session.Dispose();
            Session = null;
        }
 
        private void BeginTransaction()
        {
            ValidateSession();
 
            Transaction = Session.BeginTransaction();
        }
 
        private void CommitTransaction()
        {
            ValidateSession();
 
            if (Transaction != null)
                Transaction.Commit();
 
            CloseTransaction();
        }
 
        private void RollbackTransaction()
        {
            if (Transaction != null)
                Transaction.Rollback();
 
            CloseTransaction();
        }
 
        private void ValidateSession()
        {
            if (Session == null)
                throw new ApplicationException("NHibernate Session Not Open.");
        }
 
        private void CloseTransaction()
        {
            if (Transaction == null) return;
 
            Transaction.Dispose();
            Transaction = null;
        }
 
        #endregion
 
        #region IDisposable Members
 
        public void Dispose()
        {
            CloseTransaction();
            CloseSession();
        }
 
        #endregion
 
    }
}

Note that I am using an embedded resource as my "hibernate.cfg.xml" location. Just change this line to use a file system resource, or whatever you want for your hibernate configuration.

I'm still wanting to re-abstract this into a set of objects that let's me be concerned with transactions and queries at a business level. One step at a time, though. The syntax that I would like to see, at the moment, would be something like this:

public void SomeBusinessValue()
{
    Something something = DoSomething.BusinessRelated();
    SomethingElse somethingElse = SomethingElse();
    Repository.DoTransaction(() =>
    {
        SomeRepository.Save(something);
        SomeOtherRepository.Delete(somethingElse);
    });
}

And if I get really ambitious, I may try to incorporate Castle.Windsor's Automatic Transaction Facility, so that I can have syntax like this:

[Transactional(Transaction.Requires)]
public void SomeBusinessValue()
{
    Something something = DoSomething.BusinessRelated();
    SomethingElse somethingElse = SomethingElse();
 
    SomeRepository.Save(something);
    SomeOtherRepository.Delete(somethingElse);
}

Of course, the more I travel down this path, the more obvious it is how Rhino.Commons' Repository came along. Heh - I'm only about 2 steps away from completely re-doing Ayende's UnitOfWork.

In fact, I may try to re-use NHibernateQueryGenerator and go for this syntax:

[Transactional(Transaction.Requires)]
public void SomeBusinessValue()
{
    Something something = Repository<Something>.Find(Where.SomeProperty = someValue);
 
    Something something = DoSomething.BusinessRelated();
    SomethingElse somethingElse = SomethingElse();
 
    Repository<Something>.Save(something);
    Repository<SomethingElse>.Delete(somethingElse);
}

Wouldn't that be fun... I really do like this syntax. In fact, I spent 9+ months working with it on a project because I love the simplicity of the syntax. In the end, though, I did not understand all of the underlying architecture and abstraction and Ayende set up (he includes the ability to plug in any DAL, including Castle.ActiveRecord, NHibernate, etc) and it caused headaches for me.

...

The major problem I have with this syntax, at the moment, is unit testing the Repository object. I either need to hide these details behind an IWhateverRepository interface (complete with Save, Delete and GetByWhatever methods) like I have been doing, or I I'll need to learn how to unit test NHibernate with in-memory database or something... We'll see where this leads.

(side note: how's that for a "ThoughtStream". )

Monday, March 31, 2008 1:22:29 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Data Access | NHibernate | Unit Testing | UnitOfWork

For the last few months, I've had a very small base class that abstracts out the NHibernate configuration, session creation, etc. It works very well, but is very limited in what it can do. basically, every method in my actual repository implementation would have to open a new session, execute a criteria and close the session. A typical implementation would look like this:

public ICollection<Invoice> GetAll()
{
    ICollection<Invoice> invoices = null;
    try
    {
        OpenSession();
 
        invoices = Session.CreateCriteria(typeof(Invoice)).List<Invoice>(); 
    }
    finally
    {
        CloseSession();
    }
 
    return invoices;
}

That certainly is easy and keeps the code fairly clean, removes a lot of duplication, etc.

However, there is a significant limitation - I can't have any code re-use for multi-query scenarios, without duplicating code. In other words, if I want to load that list of invoices and then load some other collection from another repository, I have to use two different Sessions across two different repository implementations. This really becomes an issue when dealing with transactions - I want my entire change set to pass or fail in a single transaction. In my current abstraction, this can't be done.

Fortunately, NHibernate has the solution to my dilemma built right in - all I need to do is create my criteria objects without a session, and then I can execute any / all of them from any session that I want.

public ICollection<Invoice> GetAll()
{
    ICollection<Invoice> invoices = null;
    try
    {
        DetachedCriteria criteria = DetachedCriteria.For<Invoice>();
        
        OpenSession();
        invoices = criteria.GetExecutableCriteria(Session).List<Invoice>(); 
    }
    finally
    {
        CloseSession();
    }
 
    return invoices;
}
 

I don't have a complete abstraction of the separate execution, yet. However, a very basic implementation could look like this (idea stolen from Ray Houston):

protected void Do(Action unitOfWork)
{
    try
    {
        OpenSession();
        unitOfWork();
    }
    finally
    {
        CloseSession();
    }
}
 
public ICollection<Invoice> GetAll()
{
    ICollection<Invoice> invoices = null;
 
    DetachedCriteria criteria = DetachedCriteria.For<Invoice>();
 
    Do(() =>{
        invoices = criteria.GetExecutableCriteria(Session).List<Invoice>();
    });
    
    return invoices;