Single Responsibility Principle

The Single Responsibility Principle (SRP), a guideline for software development, states that every class, function or module should have a single purpose and should only carry out tasks required to achieve that objective. This means that each class should be focused on simply carrying out the tasks required to fulfil its single, clearly defined responsibility. By following this principle, developers can create code that is easier to maintain and debug since it’s more organized and less prone to error. Let’s look at the below example:

import java.util.concurrent.atomic.AtomicInteger;

public class UserAuthentication {

    public static AtomicInteger counter = new AtomicInteger(0);

    public boolean authenticateUser(String username, String password) {
        // code to verify user credentials
        return false;
    }

    public void logUserIn(String username) {
        // code to log user in
        counter.incrementAndGet();
    }

    public void updatePassword(String username, String newPassword) {
        // code to update user password
    }

    public void logUserOut(String username) {
        // code to log user out
    }

    public int getLoginCounter() {
        return counter.get();
    }
}

Here is a small example in Java to explain SRP – a class that is responsible for handling user authentication. The class contains methods for logging users in and out, checking for valid credentials, keeping a count of logins and updating user passwords. Does the class follow SRP as per the definition?

Functions authenticateUser(), updatePassword(), logUserOut() and getLoginCounter() perform only one distinct operation. Can we say the same about logUserIn()? Method logUserIn() helps user logging in and there’s a side effect – or an out of place item. Side effect here is the counter that increments when the user logs in.

At a class level, UserAuthentication performs all the operations related to authentication and has the same out of place counter that helps keep a count of logged. Method getLoginCounter() has a definite objective of keeping a count but is like an ice-cream placed in oven. To summarize, this class has 2 objectives:

  • Assisting user authentication
  • Counting number of logged in users

Thus, the class doesn’t follow SRP. Should counting number of logins really a responsibility of authentication class? What can be the possible drawback of having this side effect?

Since, change in Software Development is the only constant(as is in life!), if we were to change the counting strategy to gives us, let’s say, an average of number of logins instead of number of logins. We will now have to change UserAuthentication class to do something completely unrelated to what it is supposed to do, counting!!!

Counting functionality has been tightly coupled to authentication. Even 3 lines of misplaced code can have damaging impact if left uncorrected. If we separate the concerns of authentication and counter, the problem is solved.

public class UserAuthentication {
    
    public boolean authenticateUser(String username, String password) {
        // code to verify user credentials
        return false;
    }

    public void logUserIn(String username) {
        // code to log user in
    }

    public void updatePassword(String username, String newPassword) {
        // code to update user password
    }

    public void logUserOut(String username) {
        // code to log user out
    }

}

Now the class does only one thing. It can change only when authentication based change comes in. With this simple example we emphasized the importance of keeping components loosely coupled and following the SRP to reduce complexity and make code easier to maintain. By following the SRP, software components become highly cohesive and loosely coupled, meaning that changes to one component should not affect any other components. Adhering to the SRP can help reduce the complexity of software design and implementation, as well as avoid the problems associated with tightly coupled components. By following the SRP, classes can be easier to maintain and refactor, making for a more flexible and maintainable code.

Thanks for reading, cheers!


Posted

in