SOLID Programming: The Single Responsibility Principle

If you’ve been in IT long enough, you are familiar with Uncle Bob and the SOLID principles of software design. Else, sit back and relax – you’re in for a treat.

Robert C. Martin (aka Uncle Bob) is an American programmer, speaker, and teacher. To many of us in this industry, he is a mentor we look up to. You can find an extensive collection of his videos on YouTube, guiding us through the tenets of computer programming. Many of them cover the SOLID principles, a subset of basic concepts that define good practices of software engineering. They were first introduced in 2000 in Uncle Bob’s paper Design Principles and Design Patterns.

The SOLID principles are:

  • The Single Responsibility Principle;
  • The Open-Closed Principle;
  • The Liskov Substitution Principle;
  • The Interface Segregation Principle;
  • The Dependency Inversion Principle.

This article will explore the first item on the list: The Single Responsibility Principle. As Martin defines:

“There should never be more than one reason for a class to change.”

This is one of the most beautiful and heart-warming principles of all – and one that is often overlooked. As the name suggests, the main idea is that logical elements should have one, and only one, duty. Let’s look at some practical examples.

What’s the job of user interfaces? To communicate with users, period. It shouldn’t have logic that isn’t exclusively related to content presentation! For instance, if there is SQL in the code driving your UI, you are deep in trouble. Instead, why not delegate that task to a specialized entity that knows how to handle database connections and operations? That’s a much cleaner approach!

Another frequent error is to overpopulate classes with code that does everything and goes everywhere. Classes correctly defined ensure there is one, and only one, assignment to be done. For instance, suppose you are implementing a utility class which single responsibility is to send emails. It’s okay if it needs to, let’s say, log certain things – logging is often good! But if it knows how to create the actual log, you’re doing it wrong. Once again, the better approach is to create a separate logger component that encapsulates all logging logic. Then, simply consume that service wherever needed.

This concept also applies to class members. For example, if you have an enormous method in your class, there is a chance it’s doing too much and violating this first law. Ponder if minor sub-tasks can be trusted to new (maybe private, or protected) methods. You can, then, invoke them as needed. Imagine the following scenario: suppose you have a class Cart, representing customers’ shopping carts in your e-commerce application. You may have a method AddToCart, which takes in a product and a quantity parameter. Obviously, after adding a product to the cart, you must reevaluate its subtotal. Now, if your calculation logic is in this method, you need to refactor it. It is more intelligent to encapsulate this mathematical computation in a new private method, CalculateSubTotal (which may also be protected, depending on your abstraction model), that can now be easily engaged where required.

The whole point of the Single Responsibility Principle is to ensure that changes made to one part of the system do not break other components, but there are other advantages, too. Encapsulating tasks inside their own, isolated compartments increases quality and simplicity, making the software more sustainable in the long run. Development teams who apply this concept will find that their projects look cleaner and easier to maintain, troubleshoot and extend, as building blocks become more logically organized in the larger context. Ultimately, the primary value is centered on maximizing applications’ service life by adhering to high quality standards that define good code.


About the Author

Luiz Parente is a senior software engineer who is passionate about systems design and technology. Having started his journey in computer programming at the age of 14, his core expertise is centered in solutions architecture with .NET technologies.

Follow Luiz on LinkedIn