02 October 2015

single responsibility principle

SOLID principles play an important role in designing your classes during low level design. Last time we discussed about DRY principle, this time let's discuss on SRP principle (Single Responsibility Principle). Single Responsibility Principle is one of the SOLID design principles. It stands for letter "S" in the "SOLID" acronym.

What is SRP principle

The single responsibility principle states that, a class, a method, etc should have only one responsibility OR should be doing only one thing. In essence a class or method should have only one reason to change.

Let's consider an example:

Class not following SRP

public class EmailSender
{
  public void SendEmail(string customerID, 
                       string emailNotificationType)
  {
    //STEP1: load customer details
    //STEP2: get email content
    //STEP3: send email (using SmtpClient class)
  }

  public string GetEmailContent(Customer customer, 
                 string emailNotificationType)
   {
    // Build the email notification content
   }
}

If you look at EmailSender class, it is doing three things in it:

  1. Loading customer details from database, which is REPOSITORY responsibility.
  2. Building the content of the email to be send, its not a responsibility of email sender class.
  3. Sending email. Ideally sending email should only be the sole responsibility of the email sender class.

OK, but what is the problem with above class design?. EmailSender class is working as expected!

Problems with not following SRP

The EmailSender class can go under changes because any of the below reasons:

  1. Changes in the way, you are loading customer details.
  2. Changes to the email content because of requirement enhancements / changes.
  3. If there any change in the way you are sending the email instead of using SmtpClient class or something like that.

So in essence, the EmailSender class will have to undergo changes if any the above three changes, which leads to regression efforts which is going to involve the other two responsibility as well.

Code re-factoring using SRP

  • Create a separate class to load the Customer details.
  • Create a separate class to build the email content.
  • With that, the EmailSender will have only one responsibility, i.e. just deal with sending email out.
public class CustomerRespository
{
  public Customer GetCustomer(string id)
  {
    // logic load customer from Database
  }
}
public class EmailContentBuilder
{
  public string getEmailContent
               (Customer customerDetails)
  {
    // logic to build email content
  }
}
public class EmailSender
{
 public void SendEmail(string emailaddress, 
            string subject, string bodycontent)
  {
    //logic to send email out
  }
}

Advantages of following SRP

If they are any changes to the above three class, then only that class will have code changes and the testing efforts just isolated to that class alone.

Which means you don't need worry about regressing other two class responsibility, as they have not undergone any code changes. So single responsibility principle leads to better class design to ensure less regression effort in case of a class responsibility / functionality changes.

Hope you got the gist of single responsibility principle. As always your comments are welcome!

2 comments:

  1. And how to comibe all these classes? Create a new one? Like: SendEmailManager? To get the customer object, then format email content ant then everything pass to mail sender?

    ReplyDelete
  2. Yes, that is one the option.

    You can call the new class as EmailNotificaitonManager.
    This EmailNotificationManager can compose objects of different responsibility. i.e., one for loading the content to be sent, one for formatting the content and one for sending the actual email out.

    ReplyDelete