The single responsibility principle (SRP) is a design principle that object oriented developers believe in. In it’s simplest form it means:

Each class should have a single responsibility, and therefore only a single reason to change.

This enforces stability throughout our system. If we build small composable objects that each focus on a single responsibility, we are then able to introduce change much easier. Changes are isolated and more focused to smaller areas of the code base.

Violations of SRP are easy to recognize. They can usually be found in classes that have many lines of code.

Let’s take a look at the following example:

 1 public class Foo
 2     {
 3       public IEnumerable<DataRow> bar(string sql)
 4       {
 5         using( var connection = new SqlConnection(ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["active.connection"]].ConnectionString))
 6         {
 7           var command = connection.CreateCommand();
 8           command.CommandText = sql;
 9           command.CommandType = CommandType.Text;
10           var table = new DataTable();
11           table.Load(command.ExecuteReader());
12           return table.Rows.Cast<DataRow>();
13         }
14       }
15     }

Let’s try to break down the above code by describing what it’s responsibilities are.

I think it’s probably safe to say that it’s possible that we may need to open up a connection to the database in other areas of the application. Perhaps to ExecuteNonQuery(), or ExecuteScalar(). How many other places are we likely going to have the same boiler plate “open a connection” code.

Let’s re-factor this a bit to break out the separate responsibilities in to separate classes.

 1 public class Foo
 2     {
 3       IConnectionFactory connectionFactory;
 4       IMapper<IDataReader, IEnumerable<DataRow>> mapper;
 5 
 6       public Foo(IConnectionFactory connectionFactory, IMapper<IDataReader, IEnumerable<DataRow>> mapper)
 7       {
 8         this.connectionFactory = connectionFactory;
 9         this.mapper = mapper;
10       }
11 
12       public IEnumerable<DataRow> bar(string sql)
13       {
14         using( var connection = connectionFactory.OpenConnection())
15         {
16           var command = connection.CreateCommand();
17           command.CommandText = sql;
18           command.CommandType = CommandType.Text;
19           return mapper.MapFrom(command.ExecuteReader());
20         }
21       }
22     }

By breaking apart the different responsibilities in to different classes we are now able to re-use those classes in other areas of the application, and we reduce the amount of duplication spread across the application. If there happens to be an error, it’s likely only a single component needs to be corrected. For instance if we were to forget to “Open” the connection, we can fix this error in one location. Hence the “single reason to change” philosophy.

The IConnectionFactory is responsible for Opening a connection to the database. The IMapper is responsible for mapping an IDataReader to an IEnumerable. Foo is responsible for executing the command against the IDbConnection.

In my next post, I will show you how to re-factor this solution to use the strategy pattern to fix the Open Closed Principle violation.

comments powered by Disqus