Single Responsibility Principle

This is post is the first in the installment of my coverage of SOLID development principles. I’ve been wanting to cover this for a while now. I am going to be giving examples of these principles in C#, but by no means does that mean these only apply to the C# language. These principles have been around for a while and they are used to make your code more extensible and reusable. The first of these SOLID principles is going to be the Single Responsibility Principle.

Single Responsibility Principle (SRP)

This one basically means that our classes should have only one responsibility. There are some benefits to this especially when we start to talk about the next principle of Open/Close, but that’s for the next post! Just to keep it simple though, think about it if our class has multiple responsibilities it is going to need to change more frequently and can also become a point of confusion, especially with naming as well as functionality and extensibility. Another way to look at it is, our class code should do one thing and do it well.

Example

This would not be complete without some sort of example. There are many ways to implement this principle as just as many ways to violate it. Not saying that a violation of this principle is always a bad thing, but think of the SRP as a heuristic for quality code. Often times, a method that is very procedural, which does many things is a great candidate for refactoring (another art in itself) but can demonstrate a violation of the SRP. Let’s look at the code below which contains a class for representing a customer.

using System;
using System.Collections.Generic;
using System.Text;
 
namespace SingleResponsibilityPrinciple
{
    public class Customer
    {
        public int Id;
        public string FirstName;
        public string LastName;
        public string Email;
 
        public void SendCustomerEmail()
        {
            if (Email.Contains("@") && FirstName != null)
            {
                Console.WriteLine($"Sending {this.FirstName} an email...");
                return;
            }
            throw new Exception();
        }
    }
}

First of all notice that our Customer class could be split into a class of its own without any methods, which would then represent just the model to work with. Secondly, the method we are using contains the business logic for validating our email and as well as exception handling. Now, this is a pretty simple implementation, however, some code smells that can help you identify if your code is violating the SRP are if your class is mixing the following below: – Business Rules – Logging – Calculations – Validation – Persistance – Encoding

A better way is to split the above rules and behavior out into its own classes. For example, if we are doing the same a little differently we might have a separate model for Customer, as well as a separate class for SendEmail, and ValidateEmail. You could do the same for logging, exception handling and just about any other type of responsibility the code starts to take on. This can be somewhat subjective and does at times create more code, or at least more classes and organization should be paid attention to.

How To Split Out Responsibility

Notice below that We’ve split out the same code into individual classes for each of the different responsibilities.

using System;
 
 
namespace SingleResponsibilityPrinciple
{
    public class Customer
    {
        public int Id;
        public string FirstName;
        public string LastName;
        public string Email;
    }
 
    public static class SendEmail
    {
        static void SendCustomerEmail(Customer customer)
        {
            var validateEmail = new ValidateEmail(customer.Email);
            if (validateEmail.IsValid())
            {
                Console.WriteLine($"Sending {customer.FirstName} an email...");
            }
        }
    }
 
    public class ValidateEmail
    {
        private string _email;
        public ValidateEmail(string email)
        {
            _email = email;
        }
 
       public bool IsValid()
       {
         if (_email.Contains("@"))
         {
             return true;
         }
         return false;
      }
   }
}

Benefits

As was already mentioned, some of the benefits of the use of SRP is that the code is more flexible, especially when combined with the other principles involved with SOLID principles. And here are a couple more:

  • Better testability as less responsibility makes for easier testing

  • Code is less brittle especially when changes are needed, as only one area is affected if SRP is implemented.

2 thoughts on “Single Responsibility Principle”

Leave a Reply

Your email address will not be published. Required fields are marked *