Single Responsibility Principle

single responsibility principle

What is Single Responsibility Principle?

Single Responsibility Principle, also known as SRP is the first principle from the set of SOLID Principles.

A class should have only one reason to change.

Robert C. Martin

That means a class should have responsibility for a single part of the program’s functionality. Overloading a class with several functionalities leads to the below problems.

  1. The class will grow large and will be difficult to manage.
  2. It will be difficult to unit test it.
  3. In order to modify one functionality, we have to modify entire class. Therefore, the class will undergo more frequent modifications. As a result, more chances of introducing bugs.
  4. This will also require more amount of manual testing.

For example, consider a registration form, and see how it can break SRP and how to fix them. Below code can be downloaded from my Git repo. I have divided the code into two parts based on how it looks before and after applying SRP.

Registration class does below functions

  1. Get input from user.
  2. Validate Input.
  3. Save data into database.
  4. Trigger confirmation email.

One can create a class for this as below

static void Main(string[] args)
{
    //Input gathering
    Console.Write("Please enter your name: ");
    var name = Console.ReadLine();
    Console.Write("Please enter your email address: ");
    var email = Console.ReadLine();

    //Validation
    if (!email.Contains("@"))
    {
        Console.WriteLine("Error: invalid user");
        Console.ReadLine();
        return;
    }

    //Add user to database
    //For simplicity, I am not writing actual code. It is not in the scope of this example
    Console.WriteLine($"User {name} added to DB");

    //Send welcome email
    //For simplicity, I am not writing actual code. It is not in the scope of this example
    Console.WriteLine("email sent to " + email);

    Console.ReadLine();
}

How does it break SRP?

A class (and a method) doing so many things and thus broken SRP. If you want to change the storage from MS SQL to SQL Server, you will end up changing class and this can lead to undesirable effects. You will also have to test other functionalities in that class to make sure they are not affected.

“Remember, changes are not always as small. They can modify to global variables and that can become a nightmare”.

How to fix SRP violation?

Here we can split this class into 4 different classes as RegistrationForm, Validator, DatabaseHelper, and EmailSender. One additional class to create user object.

User Class:
This class encapsulate different properties of user. It makes passing and accessing values from different methods easier.

internal class User
{
    public string Name { get; set; }
    public string Email { get; set; }
}

RegisterationForm Class:
This class will read inputs from user and pass them to the caller.

internal class RegisterationForm
{
    public User ReadInputs()
    {
        var user = new User();

        //Input gathering
        Console.Write("Please enter your name: ");
        user.Name = Console.ReadLine();
        Console.Write("Please enter your email address: ");
        user.Email = Console.ReadLine();

        return user;
    }
}

Validator Class:
This class validates the user.

internal class Validator
{
    public bool Validate(User user)
    {
        return user.Email.Contains("@");
    }
}

DatabaseHelper Class:
This class simulates database save operation.

internal class DatabaseHelper
{
    internal void Save(User user)
    {
        Console.WriteLine($"User {user.Name} added to DB");
    }
}

EmailSender Class:
This class simulates email send operation.

internal class EmailSender
{
    internal void Send(User user)
    {
        Console.WriteLine("email sent to " + user.Email);
    }
}

and finally, we will call these code blocks together from Main method

//Input gathering
var registerationForm = new RegisterationForm();
var user = registerationForm.ReadInputs();

//Validation
var validator = new Validator();
var isValidUser = validator.Validate(user);
if(!isValidUser)
{
    Console.WriteLine("Error: invalid user");
    Console.ReadLine();
    return;
}

//Add user to database
var dbHelper = new DatabaseHelper();
dbHelper.Save(user);

//Send welcome email
var emailSender = new EmailSender();
emailSender.Send(user);

Console.Read();

We have divided one large class into multiple smaller classes. As a result, these classes are now easy to maintain and unit testable. You can safely make changes in one class without affecting others. Therefore, less amount manual testing.

You can download source code from here.

Single Responsibility Principle

Leave a Reply

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

Coding Crest Back To The Top