Simple branching advice

A friend of mine asked me the following questions:

  • Are you working in different branches?
  • Are you working in the same project as other developers at the same time?

As this is a topic of much debate at most offices around the world, I’m writing my own advice here. As I work almost exclusively in Visual Studio, my experience and advice is limited to that environment, and to relatively small teams.

Here’s my rule:

Try to avoid branching at all times!

Branching always costs valuable time. It takes time merging. It takes time resolving conflicts or a bad merge. It takes time explaining how it works and what features should be implemented on what branches. It takes time keeping track of your branches.

Here’s the workflow I prefer, which avoids almost all conflicts:

  1. Write a little piece of functionality.
  2. If it works and builds, check it in.
  3. If you know your affecting other developers, be sure to communicate this to them. Then check it in.
  4. Make sure your team gets the latest source after you added a conflicting change (I’m looking at you code first migrations!).

I almost never encounter any problems using this workflow. It’s great. Even when working with more developers in one project, you shouldn’t encounter much trouble.

That said, there are 2 scenario’s when I do use branching:

  1. Feature Reviews
    When there’s a new or junior developer, I always let them work on their own branch first to implement a feature. When they are done, they create a pull request in VSTS so we can review their work together. We can discuss the code and make changes if required.
  2. Production Releases
    Once you’ve got a version in production, you have to be able to provide hotfixes for it. I do this by creating a branch for that release. When there is a critical bug, it can be fixed on that branch. If applicable the fix can be merged back into the main branch. Creating a branch for each release you need to support and developing further on the main branch keeps the merges as limited as possible.

Pragmatic unit testing with Entity Framework 6

 

In my current project, we were first using a lot of mocking to be able to unit test. This resulted in a very time-consuming way of writing unit tests. After reading a blog post of Richard Garside, this got a whole lot easier.

The idea is simple, we provide a new implementation for DbSet that uses an in-memory store. Using this approach, we can use all the usual methods in a normal way without mocking all of them. We already had an interface for our DbContext, because we use Autofac for dependency injection.

Our DbContext interface

public interface IMyEntities
{
    IDbSet MyEntities { get; set; }    

    void Commit();

    void Dispose();

    void SetModified(object entity);

    System.Data.Entity.IDbSet<TEntity> Set() where TEntity : class;
}

Our actual DbContext implementation
The actual implementation of the DbContext implements the interface, so we can easily provide another implementation for our unit tests:

public class MyEntities : DbContext, IMyEntities
{
    public IDbSet MyEntities { get; set; }

    public virtual void Commit()
    {
        base.SaveChanges();
    }

    public IDbSet<T> Set<T>() where T : class
    {
        return base.Set<T>();
    }

    public void SetModified(object entity)
    {
        Entry(entity).State = EntityState.Modified;
    }
}

In-memory DbContext implementation
The implementation of our in-memory DbSet is displayed below. In the constructor, we set each entity set we use to a specific Fake implementation. We will get to that in a bit.

public class FakeMyEntities : DbContext, IMyEntities
{
    public FakeMyEntities()
    {
        MyEntities = new FakePersonSet();
    }

    public IDbSet MyEntities { get; set; }

    public virtual void Commit()
    {
    }

    public IDbSet<T> Set<T>() where T : class
    {
        foreach (PropertyInfo property in typeof(FakeMyEntities).GetProperties())
        {
            if (property.PropertyType == typeof(IDbSet<T>))
                return property.GetValue(this, null) as IDbSet<T>;
        }
        throw new Exception("Type collection not found");
    }

    public void SetModified(object entity)
    {
    }
}

In-memory DbSet base and specific sets

The base class for all FakeDbSets looks like this:

public class FakeDbSet<T> : IDbSet<T>
    where T : class
    {
        HashSet<T> _data;
        IQueryable _query;

        public FakeDbSet()
        {
            _data = new HashSet<T>();
            _query = _data.AsQueryable();
        }

        public virtual T Find(params object[] keyValues)
        {
            throw new NotImplementedException("Create a Fake(object)Set in Pegasus.Tests.Infrastructure.FakeSet");
        }

        public T Add(T item)
        {
            _data.Add(item);
            return item;
        }

        public T Remove(T item)
        {
            _data.Remove(item);
            return item;
        }

        public T Attach(T item)
        {
            _data.Add(item);
            return item;
        }
        public T Detach(T item)
        {
            _data.Remove(item);
            return item;
        }
        Type IQueryable.ElementType
        {
            get { return _query.ElementType; }
        }
        System.Linq.Expressions.Expression IQueryable.Expression
        {
            get { return _query.Expression; }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return _query.Provider; }
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _data.GetEnumerator();
        }
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return _data.GetEnumerator();
        }

        public TDerivedEntity Create() where TDerivedEntity : class, T
        {
            throw new NotImplementedException("Derive from FakeDbSet and override Create");
        }

        public T Create()
        {
            throw new NotImplementedException("Derive from FakeDbSet and override Create");
        }

        public System.Collections.ObjectModel.ObservableCollection<T> Local
        {
            get { throw new NotImplementedException("Derive from FakeDbSet and override Local"); }
        }
    }

All we have to do now for each entity set, is to create a FakeDbSet and implement the Find method, as the primary key can be different for each Model object.

public class FakePersonSet : FakeDbSet
    {
        public override Order Find(params object[] keyValues)
        {
            return this.SingleOrDefault(e => e.SocialSecurityNumber == Convert.ToInt32(keyValues.Single()));
        }
    }

Now you just have to make sure that your unit tests use the FakeDbContext instead of the real one, and your code will just work. It requires a bit of setup, but once this works, writing your unit tests is a lot easier.