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!

2 pensieri riguardo “SOLID principles by examples: single responsability”

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.