Posts tagged with: single responsibility

Single Responsibility Prinicple

SRP is one of the easiest principles to learn, but one of the hardest to master. The reason to this is that it can be quite hard to see if a method or class breaks SRP or not. I got a few simple rules that will help you check if you are breaking the principle.

First of all, lets check the definition of SRP:

every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class

Hence my interpretation varies a bit from the original statement, as I like to apply it to classes, methods and interfaces. If you do not agree: Go buy an ice-cream, eat it, put a smile on your face and continue reading.

XmlDoc is an excellent tool if you use it correctly. So many users abuse it and screams out to the world their product/library/etc has DOCUMENTATION! The DoXZ! yay! What they fail to mention is that the documentation is simply a reflection of the methods and classes. Read my other blog posts to get a few tips on how to write good documentation. Back to SRP. Documentation can be a tool for SRP too. If you find yourself using AND’s when describing a method, class or an method argument you have most likely broken SRP. Refactor.

When talking about SRP it’s important to know what is meant with single responsibility. When it comes to methods, they should only contain logic for one type of responsibility. Here is a small example:

public class UserService
{
     public void Register(string email, string password)
     {
          if (!email.Contains("@"))
              throw new ValidationException("Email is not an email!");

         var user = new User(email, password);
         _database.Save(user);

         _smtpClient.Send(new MailMessage("mysite@nowhere.com", email){Subject="HEllo fool!"});
     }
}

The name Register suggests that the method should register the user in the system. Doing email validation doesn’t seem to belong in an register method. Let’s break it out into a new method.

public class UserService
{
     public void Register(string email, string password)
     {
          if (!ValidateEmail(email))
              throw new ValidationException("Email is not an email!");

         var user = new User(email, password);
         _database.Save(user);

         _smtpClient.Send(new MailMessage("mysite@nowhere.com", email){Subject="HEllo fool!"});
     }

     public bool ValidateEmail(string email)
     {
         return email.Contains("@");
     }
}

One might wonder why that line of code should be moved. It’s so small. In reality email validation might be larger, but that’s not really important. Following SRP usually makes it easier to follow DRY (Don’t repeat yourself) too, since you make methods smaller and let them solve a specific problem. Hence it’s a lot easier to reuse code.

If we continue to look at the method we’ll see that it also sends an email and is therefore also responsible of delivering the email. Lets move that to a new method too.

public class UserService
{
     public void Register(string email, string password)
     {
          if (!ValidateEmail(email))
              throw new ValidationException("Email is not an email!");

         var user = new User(email, password);
         _database.Save(user);

         SendEmail(new MailMessage("mysite@nowhere.com", email){Subject="HEllo fool!"});
     }

     public virtual bool ValidateEmail(string email)
     {
         return email.Contains("@");
     }

     public bool SendEmail(MailMessage message)
     {
         _smtpClient.Send(message);
     }
}

omg! We did it again. A single line method. Is this sh!t really necessary? Yep, it is. When the application grows you’ll see that you might want some templating. By using a separate method you could replace commonly used macros like #SITEURL#, #PRODUCTNAME# etc in that method instead of duplicating the code in each method that wants to send an email.

Now it’s time to move on and look at the class. Do it follow the SRP? Do it? Nooo, don’t try to fool me. I got some NINJA zkillz. promise! SendEmail and ValidateEmail has nothing to do with a class named UserService. Let’s refactor.


public class UserService
{
     EmailService _emailService;

     public UserService(EmailService emailService)
     {
         _emailService = emailService;
     }
     public void Register(string email, string password)
     {
          if (!_emailService.ValidateEmail(email))
              throw new ValidationException("Email is not an email!");

         var user = new User(email, password);
         _database.Save(user);

         emailService.SendEmail(new MailMessage("mysite@nowhere.com", email){Subject="HEllo fool!"});
     }
}

public class EmailService
{
     public bool virtual ValidateEmail(string email)
     {
         return email.Contains("@");
     }

     public bool SendEmail(MailMessage message)
     {
         _smtpClient.Send(message);
     }
}

Actually I’m unsure of if the ValidateEmail method belongs in the EmailService class. What do you think? Leave a comment.

SRP is nothing that you do once. It’s something that you should keep doing during all types of development (like when writing new code and when you maintain existing one).

Summary

Try to follow the following rules to get a hang of SRP:

  1. Document your code. Using AND’s should make you check your code again.
  2. You should be able to associate all method names with the class/interface name. (A method called ValidateEmail cannot be associated with a class called UserService)
  3. A method should only contain logic that can be associated with the method name.

TodoApp – Part 2: Single responsibility is what we need.

In our journey towards hardcore we need to refactor the shitcore into a bit more softcore =) I’m not going to show all source code in this blog entry. You can look at the code here.

It will take some iterations before the code is quite usable. In this iteration we will focus giving each method a single responsibility, which means that each method should only contain the logic for one thing. The constructor is a kick ass example of that. Lets look at it.

First of all, it’s responsible of connecting to the database.

public MainWindow()
{
    InitializeComponent();
    _db = new SQLiteConnection("Data Source=todomachine.db;Version=3;DateTimeFormat=Ticks;");
    _db.Open();

then, it’s also verifying that the table exists in the database.

    //create table if it do not exist.
    if (!DoesTableExist(_db, "todo_items"))
    {
        SQLiteCommand command = new SQLiteCommand(_db);
        command.CommandText =
            @"CREATE TABLE todo_items(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title VARCHAR(40) NOT NULL,
description text NOT NULL
);";
        command.ExecuteNonQuery();
    }

and finally it’s loading stuff into the list box.


    // load all todo items.
    SQLiteCommand mycmd = new SQLiteCommand(_db);
    mycmd.CommandText = "SELECT * FROM todo_items";
    var reader = mycmd.ExecuteReader();
    while (reader.Read())
    {
        lbTodos.Items.Add(new Item { Id = (long)reader["id"], Title = (string)reader["title"] });
    }
}

Let’s fix that and write a little bit of documentation for each method.

btnNew_Click

Next we have btnNew_Click which is used to save a new item:

private void btnNew_Click(object sender, EventArgs e)
        {
            var frm = new TodoItemForm();
            frm.ShowDialog(this);

            var cmd =
                new SQLiteCommand("INSERT INTO todo_items (title, description) values(@title, @description)", _db);
            cmd.Parameters.Add(new SQLiteParameter("title", frm.tbTitle.Text));
            cmd.Parameters.Add(new SQLiteParameter("description", frm.tbDescription.Text));
            cmd.ExecuteNonQuery();

            lbTodos.Items.Clear();
            // load all todo items.
            SQLiteCommand mycmd = new SQLiteCommand(_db);
            mycmd.CommandText = "SELECT * FROM todo_items";
            var reader = mycmd.ExecuteReader();
            while (reader.Read())
            {
                lbTodos.Items.Add(new Item { Id = (long)reader["id"], Title = (string)reader["title"] });
            }
        }

It has two responsibilities: Saving an item into the database and refreshing the listbox.
Fortunately, we have already created a method for the listbox in the constructor refactoring. Let’s just add that the listbox should be emptied before adding all items.

lbTodos_MouseDoubleClick

lbTodos_MouseDoubleClick is used to edit an item.

        private void lbTodos_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Item item = (Item)lbTodos.SelectedItem;

            SQLiteCommand mycmd = new SQLiteCommand(_db);
            mycmd.CommandText = "SELECT * FROM todo_items WHERE id=" + item.Id;
            var reader = mycmd.ExecuteReader();
            reader.Read();

            var frm = new TodoItemForm();
            frm.tbDescription.Text = (string)reader["description"];
            frm.tbTitle.Text = (string) reader["title"];
            frm.ShowDialog(this);

            var cmd =
                new SQLiteCommand("UPDATE todo_items set title=@name, description=@description WHERE id = @id", _db);
            cmd.Parameters.Add(new SQLiteParameter("name", frm.tbTitle.Text));
            cmd.Parameters.Add(new SQLiteParameter("description", frm.tbDescription.Text));
            cmd.Parameters.Add(new SQLiteParameter("id", item.Id));
            cmd.ExecuteNonQuery();

            lbTodos.Items.Clear();
            // load all todo items.
            SQLiteCommand cmd3 = new SQLiteCommand(_db);
            cmd3.CommandText = "SELECT * FROM todo_items";
            reader = cmd3.ExecuteReader();
            while (reader.Read())
            {
                lbTodos.Items.Add(new Item { Id = (long)reader["id"], Title = (string)reader["title"] });
            }

        }

Responsibilities:

  1. Load item from database
  2. Populate item form
  3. Save stuff from the item form into the database
  4. Populate list box

Here we’ll refactor the item form to use the Item class, and we’ll therefore make the item class standalone (instead of being a private class inside MainWindow). That should take care of #2.

#4 have already been fixed thanks to the previous method refactorings.

We’ll move the item loading into a separate method.

Done

The first refactoring is now done. The goal of this post was to help you understand what Single responsibility really means, although we are not quite done with the guideline yet. The MainWindow form still have many different responsibilities. But first let’s explore exception handling in the next post.