Skip to content

Twitter Registration Using Single Responsibility Principle

We design Twitter registration software with the help of the single responsibility principle that contains a notification service, database repository, account service, and execution class.

Gopi Gorantala
Gopi Gorantala
5 min read

Table of Contents

In this reading, we will discuss the following.

  1. Introduction to SRP
  2. Why SRP?
  3. Benefits/Advantages of SRP
  4. Disadvantages of SRP
  5. Real-life use cases (with examples, code and explanation).
    • 🔐 Register/Signup process on Twitter
    • Employee details
  6. Conclusion

A class should have one and only one reason to change.

This principle is one of the five SOLID principles of object-oriented design and is an important aspect of creating clean, maintainable, and scalable code.

Introduction

The Single Responsibility Principle (SRP) states that every class should have only one reason to change, meaning that a class should have only one responsibility. The class should encapsulate this responsibility and have only the minimum necessary data and behavior to fulfil that responsibility.

In simple terms, any class or component in our code should only have one functionality. Everything in the class should be related to just one goal.

It reduces the risk of introducing bugs and makes it easier to test individual components in isolation. SRP encourages the separation of concerns, making the code more modular and scalable.

This principle promotes the separation of concerns and helps to keep the code maintainable and scalable.

Why SRP?

  • The SRP reduces coupling between components and increases cohesion within a class.
  • It improves the readability and maintainability of code. It makes it easier to understand and modify code.
  • Promotes code reusability.
  • It helps to isolate changes in one part of the system from affecting others.
  • It avoids having classes that are too large and complex.
  • Facilitates testing by making it easier to test individual components in isolation.
  • Encourages modular design and separation of concerns.

Advantages

The advantages of following the Single Responsibility Principle (SRP) include the following:

  • Better code organization and maintainability.
  • Improved readability and understanding of code.
  • Easier debugging and testing of code.
  • A higher degree of code reusability.
  • Facilitation of parallel development and implementation of new features.
  • Ability to make changes to code with less risk of introducing bugs.

Disadvantages

Some of the disadvantages of the Single Responsibility Principle (SRP) include the following:

  • Increased complexity, as a system may require more classes to implement the same functionality.
  • Potential for over-engineering, leading to too much abstraction and unnecessary code.
  • Difficulties in determining the appropriate granularity of responsibilities.
  • Challenges in balancing the trade-off between separating responsibilities and maintaining performance.

When programmers try to add features or new behaviour to a software product, they frequently integrate everything within the current class. When something needs to be changed later, due to the complexity of the code, the code refactor process is extremely time-consuming and tedious.

The Single Responsibility Principle helps us create simple classes that perform just one task. This helps make modifications or adding extensions to the existing code much more effortless.

Real-Life Examples

Examples of the Single-Responsibility principle in practice are:

1. 🔐 Signup process on Twitter

Consider a use case where a user wants to register with Twitter.

The steps Twitter takes to register are user are:

  1. Twitter asks users to register with signup forms.
  2. Twitter stores the user object in their database, which contains User details - email, name, password, and other metadata etc.
  3. Twitter sends a welcome message to the user.

Let us declare a class that does the above steps.

public class TwitterRegistration {
    public void register() {
        // step 1
        System.out.println("Fill signup form");

        // step 2
        System.out.println("Store account details in database");

        // step 3
        System.out.println("Send a welcome message");
    }
}

We are creating an account on Twitter, and the three steps should be handled separately. But the above class declared them all in a single TwitterRegistration class. Isn't this a violation of SRP?  

Also, step 2 of storing an object in the database requires additional work to open a connection with the database, authenticate the handshake, and store the user object. This is insertion logic and should be handled separately.

The third step is sending out a welcome message to the user, which should be handled by NotificationService, separately.

Using the SRP principle, we divide the above TwitterRegistration class into three different classes, each having a single and only one responsibility.

Refactoring TwitterRegistration the class gives:

// Notification Service
class NotificationService {
    public void sendNotification() {
        // step 3
        System.out.println("Send out welcome message");
    }
}
// Database handshakes
class AccountRepository {
    public void createUser() {
        // step 2
        System.out.println("🔐 Auth Success!");
        System.out.println("Store user data into database");
    }
}
// Account Registration
class TwitterAccountRegister {
    public void registerUser() {
        // step 1
        System.out.println("fill account internal details");
    }
}

Finally, after refactoring the above classes. We first allow the TwitterAccountService  to create a couple of objects for AccountRepository and NotificationService to register users with Twitter.

// Execution Class or Main class
public class TwitterAccountRegister {
    public static void main(String[] args) {
        TwitterAccountService service = new TwitterAccountService();
        service.registerUser();
    }
}

// Account Registration Service
class TwitterAccountService {
    AccountRepository repository = new AccountRepository();
    NotificationService notificationService = new NotificationService();

    public void registerUser() {
        // step 1
        System.out.println("fill account internal details");

        repository.createUser();
        notificationService.sendNotification();
    }
}

// Notification Service
class NotificationService {
    public void sendNotification() {
        // step 3
        System.out.println("Send out welcome message");
    }
}

// Database handshakes
class AccountRepository {
    public void createUser() {
        // step 2
        System.out.println("🔐Signup Success!! Registered");
        System.out.println("Store user data into database");
    }
}

/*
Outputs:
fill account internal details
🔐Signup Success!! Registered
Store user data into database
Send out welcome message
*/

In above TwitterAccountService is doing all three tasks. The primary responsibility is to fill in account details in account details and delegate the other responsibilities to other classes.

Finally, we know many teams work on the same software product. By following the SRP principle, if we see file changes in Github for a file named TweetAnalytics, we can be sure that the changes incorporated are related to analytics. This helps version control with ease.

2. Employee details

Here's another example of the Single Responsibility Principle (SRP) applied to a class representing an employee.

class Employee {
  private String name;
  private String email;
  private double salary;

  public Employee(String name, String email, double salary) {
    this.name = name;
    this.email = email;
    this.salary = salary;
  }

  public String getName() {
    return name;
  }

  public String getEmail() {
    return email;
  }

  public double getSalary() {
    return salary;
  }
}

In this example, the Employee class has a single responsibility: model an employee. It has three instance variables, name, email, and salary, and three methods to retrieve the values of these variables. The class has no other responsibilities, such as calculating taxes, sending emails, or printing information.

By following SRP, the code is easier to understand and maintain. Suppose we needed to add additional functionality in the future, such as calculating taxes. In that case, we could create a new class for this responsibility rather than adding it to the existing Employee class. This helps to keep the code organized and maintainable and reduces the risk of introducing bugs.

By refactoring the above Employee use-case with SRP.

Here's an example of the Employee class following the Single Responsibility Principle (SRP) by separating the responsibilities of modelling an employee and calculating taxes:

class Employee {
  private String name;
  private String email;
  private double salary;

  public Employee(String name, String email, double salary) {
    this.name = name;
    this.email = email;
    this.salary = salary;
  }

  public String getName() {
    return name;
  }

  public String getEmail() {
    return email;
  }

  public double getSalary() {
    return salary;
  }
}

class TaxCalculator {
  public double calculateTax(Employee employee) {
    // code to calculate tax based on salary
    return employee.getSalary() * 0.1;
  }
}

In this example, the Employee class has a single responsibility: model an employee. It has three instance variables, name, email, and salary, and three methods to retrieve the values of these variables. The TaxCalculator class is responsible for calculating taxes based on an employee's salary.

Following SRP, the code is better organized, more maintainable and scalable. If we need to change how we model an employee, we only need to modify the Employee class, and if we need to change how we calculate taxes, we only need to modify the TaxCalculator class. This reduces the risk of introducing bugs and makes it easier to test individual components in isolation.

Conclusion

In conclusion, the Single Responsibility Principle (SRP) is a software design principle that states that every class should have only one reason to change.

Following SRP makes code easier to understand, maintain, and extend. It reduces the risk of introducing bugs and makes it easier to test individual components in isolation.

SRP encourages the separation of concerns, making the code more modular and scalable. This principle is one of the five SOLID principles of object-oriented design and is an important aspect of creating clean, maintainable, and scalable code.

Core JavaSOLID Principles

Gopi Gorantala Twitter

Gopi has been a Full Stack(Java+React) since 2016. He worked in Europe, and India, from startups to tech giants. He has a strong engineering professional with a Bachelor's in Satellite Communications.

Comments


Related Posts

Members Public

Array Implementation

You will learn how to implement a custom array-like data structure.

Array Implementation
Members Public

A Guide to Common Errors and Exceptions in Java and How to Fix Them

You will be introduced to the most common errors and exceptions in Java. With examples and steps to rectify them. Some tips and suggestions to developers are provided in detail.

Members Public

Single Responsibility Principle Examples

We see some of the real-time software products following the SRP rule.