Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Get SOLID: Single Responsibility Principle

SOLID is a popular acronym that refers to a set of 5 important class design principles. I know developers get overloaded with the endless jargon that keep popping up, especially when it seems to do little more than complicate what seems pretty straightforward. Do know that we use jargon not only to make ourselves feel smart, but also as the basis for a common vocabulary which can have real benefits when trying to communicate complex systems.


Today I want to talk about the first part of SOLID: Single Responsibility Principle (SRP). This is a pattern that is simple to understand on paper, but not so clear-cut in practice. SRP states that a class should have one and only one responsibility. There are a number of benefits to following this principle:



  • Code complexity is reduced by being more explicit and straightforward,

  • Readability is greatly improved,

  • Coupling is generally reduced,

  • Your code has a better chance of cleanly evolving

It’s quite logical – if a class focuses on one specific responsibility, it’s bound to be cleaner and more receptive to change.


Great, super-clear on paper, but what does it all actually mean?


The first problem we need to address is: what is a responsibility. I think of it as a fancy word for purpose. That purpose can be whatever you need from your class. Many of your classes will form the basis of your domain model, and the single responsibility of such classes is to be to represent their respective real-world counterparts. The responsibility of our Car class is to represent a real-world Car. Not to worry about data access, presentation, or the purchasing aspect of our domain. Similarly, we might have a utility class for data access – such a class must avoid doing anything not directly related to data access.


Here’s an example. Given a DataAccess class that looks something like:

public class DataAccess
{
public class GetUser(string userName, string password)
{
using (var connection = new SqlConnection(…))
using (var command = new SqlCommand())
{
command.CommandTex = “SELECT Id, Name, UserName, Password, DateOfBirth FROM Users where UserName = @UserName and Password = @Password”;
command.Parameters.Add(“@UserName”, SqlDbType.VarChar).Value = userName;
command.Parameters.Add(“@Password”, SqlDbType.VarChar).Value = password;
command.Connection = connection;
connection.Open();
using (var reader = command.ExecuteReader())
{
return dr.Read() ? MapUser(dr) : null;
}
}
}

private User MapUser(IDataReader dr)
{
return new User
{
Id = Convert.ToInt32(dr[“Id”]),
Name = dr[“Name”].ToString(),
UserName = dr[“UserName”].ToString(),
Password = dr[“Password”].ToString(),
DateOfBirth = Convert.ToDateTime(dr[“DateOfBirth”]),
};
}
}


We have a violation of our single responsibility principle – DataAccess has two clear and distinct purposes: data access and data mapping. Now, it’s true that data access and data mapping go hand-in-hand, but the unnecessary coupling of logic within a single class makes both functions (access and mapping) unnecessary brittle. By being in the same class, GetUser is tightly coupled to the mapping logic (which makes it more likely to be negatively effected by any changes).


Another way to look at SRP is from the perspective of reason to change. Wikipedia gives a good illustration from this perspective:



As an example, consider a module that compiles and prints a report. Such a module can be changed for two reasons. First, the content of the report can change. Second, the format of the report can change. These two things change for very different causes; one substantive, and one cosmetic. The SRP says that these two aspects of the problem are really two separate responsibilities, and should therefore be in separate classes or modules. It would be a bad design to couple two things that change for different reasons at different times.


The reason it is important to keep a class focused on a single concern is that it makes the class more robust. Continuing with the foregoing example, if there is a change to the report compilation process, there is greater danger that the printing code will break if it is part of the same class.


The other problem I see people having when it comes to applying SRP is an irrational dislike for having multiple classes and a fear of object instantiation. At the very least, the solution to our above design problem is to create a new class, named DataMapper, and create an instance of it from within our DataAccess class. This would provide logical separation (which is what SRP is concerned about). However, we’d still have tight coupling and would likely consider introducing an IDataMapper interface and leverage dependency injection (other parts of SOLID focus on those aspects, so we’ll skip the details for now). The point is that we’d introduce a new type (possibly two), and an extra object instantiation:

using (var reader = command.ExecuteReader())
{
return dr.Read() ? new DataMapper().MapUser(dr) : null;
}

//or

using (var reader = command.ExecuteReader())
{
return dr.Read() ? Factory.Create<IDataMapper>().MapUser(dr) : null;
}


I consider both side effects extremely insignificant (non-existent really) in comparison to what is gained (readability, maintainability and testability).


In the end, the lesson here is that you should put thought into each and every one of your classes. That starts by first defining a very specific purpose for each class – regardless or how many .cs files you end up with. But don’t think that SRP is something you can apply at the start and naturally maintain. As your system grows so too will your classes. At some point you’ll notice that a class that once had a defined purpose seems to be a little murky. Do not hesitate to immediately refactor your code.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

17 Responses to Get SOLID: Single Responsibility Principle

  1. dfgd says:

    dfg

  2. ffghfgh says:

    gfhfgh

  3. Yngve Nilsen says:

    I’m having some issues connecting this to the repository pattern, really and I’d be very happy if someone could shed some light for me.

    The SRP states that each class should have a “Single Responsibility”, but if I have a repository – UserRepository – I would like to have the methods GetUsers, Save and Delete.

    Would you say this is a violation of the SRP? In all fairness the name UserRepository is a pretty vague description, so basically I should be able to put whatever user-related I want in that class and still fulfill SRP..

    any comments?

  4. Colin Jack says:

    “SRP states that a class should have one and only one responsibility.”

    I think the better definition, and the one I’ve read, is reason for change. Responsibility is way too vague for my liking.

  5. Dave Schinkel says:

    >>>Well, I have a further problem with the semantics of this… what is a purpose? I can easily state a class’ ‘purpose’ as been anything at any level of detail or abstract.

    start with commenting your class to give it a purpose. When a developer looks at a class, it’s purpose should be commented on at the top as a FIRST step for one thing

  6. Jay Smith says:

    Where can I find out more information about SOLID?

  7. While I always agree that decoupled code and that generally most things should have a single responsibility I disagree with your example, I think this has already been voiced but I feel your sample entirely fits into the single responsibility of a data context.

    Especially in DDD. There’s no reason to pollute any layer of your domain with mapping code other than tightly coupled to the DAL. This is perfectly acceptable design because data mapping is 95% of the time coupled to the specific database. There really isn’t any easy way to decouple it other than moving towards a solution such as NHibernate/Fluent-Nhibernate which would be why I highly support these projects even for my only introductory usage of them.

    But this example brings up another clear reason I absolutely hate databases because you are tightly coupled to them for your data layer. Even with your suggestion of splitting the tightly coupled mapping out into its own layer with a factory is just as coupled as you were before because the mapping is coupled to the database irregardless. And now, in my opion you’re actually WORSE off, because now you have alot more code noise AND you’re passing around a datareader which is still connected to the database. IMO it’s best practice to never pass out a live data reader outside of the context of the class so there’s never a concern of what domains it crosses.

  8. Karl,

    nice post. I assume the GetUser method signature in your example should be written as:

    public User GetUser(string userName, string password)

    not

    public class GetUser(string userName, string password)

  9. eKnacks says:

    You’ve been knacked. Keep up the good work.

  10. DaRage says:

    I have one comment regarding the use of interface in the example code. I think the wide spread use of DI is encouraging the misuse of interfaces. In the example above the use of DI to inject an implementation of IDataMapper is wrong and because the DataMapper expects a specific implementation that now how to map to a user class and the code above leaves a room to inject a wrong implementation which will fail on runtime. And this is very likely to happen since in practice the configuration of the DI happens somewhere far from the context of use of the class. I think a better implementation of the code above was if the DataAccess class takes a UserMapper in the constructor.

    for me i have this rule when using interfaces: You should only create interfaces if it will have more than one implementation; otherwise it’s YAGNI and leads to DRY.

  11. Great post!

    You could make your point more clear, by naming you classes UserDataAccess and UserDataMapper.

    You would violate the Single Responsibility Principle by having a single DataAccess class for retrieving Users, Order, Products etc.

    BTW there is an error in your code – the method GetUser cannot return class – line 3:
    public class GetUser(string userName, string password)

  12. Even after your refactoring, the class DataAccess is responsible for way to many things and is violating the SRP big time: It creates a new DataConnection of type SqlConnection and also a new Command of type SqlCommand.
    In my opinion, this is not any of its business whatsoever.
    The class should rely on some other dependencies (see Gateway Pattern) that would be responsible for executing for example an sql query and return a DataTable.

  13. Owen Pellegrin says:

    I think the problem I have with SRP is when it comes to designing higher-level components.

    Suppose I’m making a game and I need to save/load data files. I could start by saying, “This class is responsible for game data management” and implement everything in that class. Technically, if saving data changes I’m going to have to modify loading data as well, so it makes sense to me that I’d tightly couple these actions. In fact, I usually just implement a Save and Load method on the GameData class itself. If the GameData changes, wouldn’t it follow that both saving and loading the data might change as well?

    Alternatively, I could state the responsibility as, “This class is responsible for saving and loading data.” Oops, that’s two responsibilities! Now instead of one class, I have GameSaver, GameLoader, and GameData. I might implement Save and Load on GameData still, but use dependency injection to have them delegate to a GameSaver and GameLoader. Did this really bring me any advantages?

    Would it be better instead to say that SRP applies mostly to situations where you anticipate constant change or for lower-level components? It seems like applying SRP completely would lead me to create FileOpener and FileDataWriter since GameSaver would have both of these responsibilities. So it seems like there’s a point at which you can say that the components of a responsibility aren’t worth separating. Likewise, the interface provided by GameData.Save is more usable than using a factory to create a class that will be used for one line. Is it right to say that for high-level components the interface can trump the design?

    This is stuff that’s bugged me since I first read about SRP. I practice it as much as I can, but no one’s ever really written about the cases where you might not use it.

  14. Richard Nagle says:

    Someone (Martin Fowler I think) said something along the lines of “Describe what the class does if you need to use the word ‘and’ then the class has more responsibility”.

    Not 100% of the time, but a good starting point.

  15. karl says:

    Richard:
    That’s a fair enough criticism. A lot of it is gut feeling. A lot of it becomes evident when you try to test your class, or change its functionality.

    I do think the “reason to change” perspective cuts down on the ambiguity behind “responsibility” or “purpose”.

    I don’ t think it’s necessary to get it right when you first design the class. I don’t think SRP is something you can necessarily enforce proactively all the time. But, when you do feel things are getting overly complicated, don’t hesitate to quickly and aggressively react.

  16. Richard Lowe says:

    Well, I have a further problem with the semantics of this… what is a purpose? I can easily state a class’ ‘purpose’ as been anything at any level of detail or abstract.

    “To deliver data” is a statement of a single purpose that might encapsulate querying and mapping. ‘To retrieve query results’ is a statement of single purpose that might mean it ONLY gets results, it doesn’t submit the queries.

    I think you should find a way to define responsibility and purpose that does not leave so much room for interpretation.