SOLID principles by examples: single responsability

This blog post will explain with simple examples the Singe Responsabily Principle of SOLID agiles principles to better understand how we can improve our daily coding activites. In future post I’ll cover the other four priciples.

The Definition

A class should have only one reason to change.

Defined by Robert C. Martin in his book Agile Software Development, Principles, Patterns, and Practices it is the first of the five SOLID agile principles. What it states is very simple, however achieving that simplicity is not so obvious.

Let’s start with the classic example, an object that can save itself.

class Book_NoSRP
    {
        public string Author { get; set; }

        public string Title { get; set; }

        public void Save()
        {
            //Save to database code.
            //Open db connection.
            //Make some logic checks.
            //DB CRUD operations.
            //Close connection.
        }
    }

This class violates the SRP principles because it has more than one reason to change:

  • It can change because we want to add a specific attribute for a book, the year of the first edition for example
  • It can change because our database structure changes and we need to update the data operations or because we want to save our book in a XML file format.

How do we change this situation?

We move the saving logic away from this class

class Book_SRP
    {
        public string Author { get; set; }

        public string Title { get; set; }
    }

    class PersistenceService
    {
        public void Save(Book_SRP bookToSave)
        {
            //Save to database code.
            //Open db connection.
            //DB CRUD operations.
            //Close connection.
        }
    }

This principle can help us to design better procedures or function, too. This method, for example, is doing too much. Because of that the SendAlert class could change if the validation criteria changes and that is not the main purpose of the class.

class AlertService
    {

public void SendAlert(string emailTo, string alertMessage)
        {
            if (!emailTo.Contains("@"))
            {
                throw new ArgumentException("email is not in a valid format");
            }

            if (!emailTo.Contains("blackListedDomain.com"))
            {
                throw new InvalidOperationException("domain blackListedDomain.com blackListed.");
            }

            if (alertMessage == null)
            {
                throw new ArgumentNullException(nameof(alertMessage));
            }

            SmtpClient client = new SmtpClient();
            client.Send(new MailMessage("mysite@nowhere.com", emailTo)
            {
                Subject = "Alert",
                Body = alertMessage
            });
        }
}

We can refactor like this.


interface IEmailValidationService
    {
        string Validate(string emailTo);
    }

class AlertService
    {
        private readonly IEmailValidationService _emailValidationService;

        public AlertService(IEmailValidationService emailValidationService)
        {
            _emailValidationService = emailValidationService;
        }

        public void SendAlert(string emailTo, string alertMessage)
        {
            var validationError = _emailValidationService.Validate(emailTo);

            if (!string.IsNullOrWhiteSpace(validationError))
            {
                throw new InvalidOperationException(validationError);
            }

            if (alertMessage == null)
            {
                throw new ArgumentNullException(nameof(alertMessage));
            }

            SmtpClient client = new SmtpClient();
            client.Send(new MailMessage("mysite@nowhere.com", emailTo)
            {
                Subject = "Alert",
                Body = alertMessage
            });
        }
    }

This way the AlertService class has only one reason to change and it doesn’t have to change if something in the validation logic changes.

TL;DR

The primary benefit the Single-Responsibility Principle gives you is high-cohesion, low-coupling code. Following SRP minimizes that one class will have to change for a given requirement, and maximizes the possibility that changing one class will not impact any other classes.

Happy coding!

Advertisements

2 thoughts on “SOLID principles by examples: single responsability

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s