Single-Responsibility Principle, the first principle and meaning of the letter S in the SOLID principles.
The famous and well-known SOLID design principles of the programming world, which developer does not know them? What would we do without Uncle Bob (Robert C. Martin) teaching them to us? What would the world of object-oriented programming be like without them?
If you are not familiar with SOLID principles, they were defined in the book “Agile Software Development Principles, Patterns and Practices” by Robert C. Martin. These SOLID principles applied to programming in general and were not focused on any particular language. Later on, the C# version of this book was republished, called “Agile Software Development Principles, Patterns and Practices in C#“, which by the way, is one of the best C# books that are recommended.
The SOLID Principles created by Uncle Bob are 5, which are:
- Single Responsibility Principle (SRP)
- Open/Closed Principle (OSP)
- Liskov Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
And as you may have seen in the title, in this article we are going to talk about and explain the C# Single Responsibility Principle (SRP), the first of the SOLID Principles.
If you are looking to understand Single Responsability Principle in C# or you have questions like:
- What is Single Responsibility Principle in C#?
- Why is Single Responsibility Principle important?
- Why use Single Responsibility Principle?
- How to implement Single Responsibility Principle in c#?
This is the place for you! Here you will discover everything you need to know about this SOLID principle with real world examples. Stay!
What is single responsibility principle in C#?
Single-Responsibility Principle in C# is the first design principle of SOLID. It is very common to see Single-Responsibility Principle also known as SRP, so if you see SRP somewhere you will know what it is.
If you are wondering what SRP states in C#, Single-responsibility Principle is defined as:
“Each software module or class should have only one reason to change”
Obviously, as the name of the principle itself indicates, a class or method should have only one responsibility and one reason for change. Single Responsibility Principle is C# SOLID principle easier to explain but at the same time, the most difficult to put into practice.
Even though this single reason to change sounds a bit weird (and Martian in my opinion👽), so self-explained will be:
“Enforce that a class only does one thing”
If you have a class in C# that does X thing and also does Y thing, I would suspect that you are not complying with the Single Responsibility Principle. It’s like a developer, it doesn’t matter if it’s you or me, if we are developers and our responsibility is to develop but at the same time we do Marketing, yes, we are gods but we are not complying with the Single Responsibility Principle!
Why you should follow the Single Responsibility Principle
By implementing SRP in the code you can achieve several benefits at the code level and also save time. The biggest advantage of follow the C# SRP is to have a clean c# code, reducing its complexity and turning it into a simple and easy to read code.
Another great advantage of implementing SRP in C# code is to gain the ability to reuse or recycle code excerpts. If the Single Responsibility principle is followed, it is possible to reuse the logic of that code in other parts of the application or directly reuse it in another project. You can save a lot of development time!
Another advantage of using Single Responsibility Principle is coherence, that is, although each method does different things, when they are united they do one thing together and do it well.
We are also going to see and explain the main benefits and advantages of using SRP in our C# code.
Main Benefits of C# Single Responsibility Principle
At this time you may now be wondering what are the benefits of using Single Responisiblity Principle in C#. The number of advantages for using this SOLID principle, as I said before, are many. The following reasons are the most important reasons in terms of impact on development and time:
- Improves code simplicity: If the Single Responsibility Principle in C# is respected and not violated, classes should only contain a single property or method. This makes it easier to understand what does what and the complexity of the code would be reduced.
- Maintains a manageable project: Related to the previous advantage. When a class has only one responsibility, your developer brain will only have to think about that one responsibility and no more. This allows you to have a “cleaner” brain of information and allows you to think and manage the project or application better.
- Enhaces maintenance and scalability: If we think for a second about a class that violates the SRP, we will think about a class that does many things. If for any reason that class has to be modified, it will most likely return errors that did not happen before. If the class does only one thing, you will only have to see to it that you modify that one thing and check that it works well. You don’t have to worry that changing one thing will break another.
- Makes testability better: As any good C# developer we know that writing and running unit tests is always advised and considered good practice. By respecting SRP we will find that writing unit tests in the class is an easy task since the class only does one thing and not several and therefore, reduces bux fixes and reduces testing time.
- Reduces coupling: If methods only do one thing, one of the things we C# developers will avoid is coupling. That is, a method will not depend on another method and this makes them more independent of each other.
- Facilitates code extension: If the Sigle Responsibility Principle is met in C#, we have the possibility to combine these classes and build a more user-friendly and modular code. This can be achieved thanks to the dependency injection getting a more testable and extensible code.
How To Implement Single Responsibility Principle in C#
Follow the Single Responsibility Principle in C# is easy as long as you know the responsibility of each class. That is the trick to be able to implement SRP in our apps or developments: know the responsibility of each class.
Let’s look at several self-explained examples so you can understand how to implement the SRP principle in a C# code where it is being violated.
Example in C# without Single Responsibility Principle implementation
For this first case study example of a software C# code extract, we see how SRP is being violated, specifically the
add method is, on the one hand, adding a user and on the other hand, it is writing to the log. These are too many things for one method, it should only know and take care of one thing or responsibility.
For example, we should separate on one side the action of adding a user and on the other side writing in the log.
Implementing Single Responsiblity Principle in C#
Let’s take a look at the following example. In this example we have refactored the code following the SRP principle, separating the responsibilities into several classes.
As you can see, the
Logger has simply been abstracted. Now on one side we have the class
UserSRP to add the user and the class
Logger to write the errors in the log.
In this simple way we respect the SRP principle and we could reuse the code elsewhere in a much simpler way. However, even if SRP is implemented and is not violated, it can be done in a better way.
Better implementation of SRP in C#
As I said before, SRP is implemented correctly in the code but there is always room for improvement. So now let’s see a way to implement it even better.
In this example we can see that the
Add method has been wrapped in an error handler. This way
User only knows how to add the user and that is his only responsibility.
It is not really necessary to get to this point, this is a very punctual way and may not apply to all cases. As long as each of your classes handles only one responsibility, you will be complying with the SRP principle.
Single Responisbility Principle Example in Practice
When we are developing a project, we must take SRP into account and respect it, especially to give some reusability to our code. Let’s look at some Single Responsibility Principle example in C# and see how we can reduce coupling and increase cohesion.
Violating the Single Responsibility Principle in C# (real world example)
Let’s imagine that we have a user logging. In this first example of SRP in C# we see that the
UserSettings class has several responsibilities such as getting the user and verifying its credentials. Obviously this works but we are violating SRP.
To solve the Single Responsibility Princile violation in C# we should separate the methods of this class in several different classes.
Refactoring Towards SRP in C#
As I said before, the best solution is to split the functionality into 2 classes so that there is only one task in the class. In this example the class
UserAuth is born (to identify and verify the user), keeping the class
UserSettings which is in charge of the rest of the user settings.
Now yes, now each class only handles one responsibility. If, for example, at some point we need to make a change in the responsibility, it will be as easy as modifying that single class.
Detecting if the Single Responsibility Principle is being violated
The violation of the Single Responsibility Principle in C# can occur in different ways and it’s really not possible to be 100% sure that this SOLID principle is not being violated.
In this case the ideal is to know the following hints to detect a violation of the Single Responsibility Principle in C# and to put into practice everything you have learned about this principle:
- Number of imports: Always keep an eye on the number of imports because if this number is high, it is very likely that the number of classes we are importing is very high and maybe there are extra things we are doing.
- Number of public methods: A simple way to detect SRP violation in C# is to check how many public methods a class has. If you wonder why, if a class has a large number of different public methods, most likely that class is doing several things at once and leads to not comply with Single Responsibility Principle.
- Difficult testing: A good practice is to manage to write unit tests on the class. If writing these unit tests costs a little, most likely the class is doing several things at the same time.
- Number of lines: Although it may seem absurd, this is often the way to identify that the Single Responsibility Principle is being violated. You only have to look at the size of the class and its number of lines. If you suspect that it has too much code for what it does, probably not only one task and has more than one responsibility.
These are the most common methods to detect if this principle is not being met. There are really no specific or better or worse hint, it all depends on many factors and these four tricks mentioned above usually work to detect SRP violations in most cases.
What happens if a class has more than one responsibility?
It is true that there are times when complying with the Single Responsibility Principle and SOLID principles is not easy or not possible. I say this because there can be cases in which a class has more than one responsibility. The first example that comes to my mind is a class that, on the one hand, reads information from a server and on the other hand, writes or uploads information.
Almost certainly that class, as I always say, is doing too many things and if at some point it requires some change, get ready!
In these cases two well known terms are used to describe the reason why a class or module does several things at the same time. These two terms are cohesion and couping. Let’s understand them:
Cohesion means how strongly various data or elements are related to each other. If several classes are highly dependent on other classes, this means that the level of cohesion is low and obviously, the Single Responsibility Principle is being violated.
An example of having a low cohesion is not healthy for the code, if we need to modify a class it is possible that another class depends on this one. This could cause unwanted errors in the code.
Coupling is the term used in programming to refer to the degree of dependence or independence between various modules of a system (something similar to cohesion). If you have a high coupling it would be similar to cohesion, the modules have a high level of coupling between them and again the Single Responsibility Principle is violated.
If for example you want to change some function of a module and you modify it, having a high coupling there are many probabilities that those changes affect other modules due to the dependency and something breaks.
And you may be wondering, is it possible to solve cohesion and coupling in C#? How can it be fixed in a simple way?
Let me advance you that yes, and in a very simple way.
Fixing cohesion and couping in C#
The answer to this question that seems to have no solution is very simple. It is as easy as splitting the responsibilities of that class into several different classes!
One of the best practices is to use Interface Method Usage Matrix (IMUM) to be able to know which methods should be in another class or which methods should be grouped.
At this point you are probably wondering: What does IMUM mean? How does it help to avoid cohesion and SRP violation? Let’s see.
Interface Method Usage Matrix (IMUM) Explained
To officially define the term IMUM, as Krisijan explains it, it is a matrix formed by two axes: X-axis and Y-axis. On one axis are the methods and on the other the interfaces.
In the following example you can see in the X-axis the interfaces we have and in the Y-axis the methods. This way you can easily group methods with the same responsibility and detect if there is any violation of the Single Responsibility Principle.
As you may have noticed, with this simple IMUM Matrix you can clearly see which interface is using which methods.
Just in this example to avoid Single Responsibilty Principle violation we can notice that MethodC and MethodD have a high level of coupling and low level of cohesion. As Krisijan relates, this can be an indicator that they have the same responsibility.