This column is not about what is the "Single Responsibility Principle". There are a lot of other places you can read all about it. Robert Martin's blog is a good place to start.
It is also not about how strict you should be applying single responsibility.
This column is about how following this principle will make your code better. Your code will be shorter, simpler, maintainable, testable, and various other adjectives.
Imagine a hamburger cookbook. It tells you what you need to make the patty, how to grill it, how to make and bake the buns, and how to put it all together. Now imagine that it is all on the same page.
The ingredients list is long and difficult to understand what goes in the bun and what in the burger.
The preparation guide tells you how to do everything combined. The steps jump between the patty and the bun - it's time saving because while the bun bakes, the next couple of steps is about the burger. But it is also comprised of dozens of steps.
Why do cookbooks separate the items? It is much better to do all at same time, plus it saves paper because there is less white spaces. They separate it to make each part easier to follow and understand. It also makes it harder to confuse the ingredients.
Your class/function/file becomes simpler to follow because it focuses on one subject. You can feel safe that your backend API controller only handles defining the API and validating the inputs. Nothing more and nothing less.
With the same example of the cookbook: instead of a single recipe taking three pages, you get two parts - each taking two pages. Combined you might end up with more pages, but each component of the hamburger is shorter.
In the cookbook, though it has more pages, it is easy to find what you are looking for. It has a structure and logic to it.
True, you will end up with more files in your repository. But each one is shorter, and the entire thing is organized and structured so anything you need, you know where to look.
If you use the bad cookbook to make your burger and confuse the seasoning between the bun and patty, you could get a salty hamburger and tasteless bun, because a portion of the salt that was meant for the bun is in the patty.
If you use the normal cookbook, you might get a poorly seasoned hamburger, but it will not impact how the bun ended up.
Problems are easier to find because they are contained.
Your API responded with an error. It responded, so the controller got the message. You look at the body and all the fields have the correct type and length. Like before, the controller only defines the API and validates inputs.
Together that automatically means there is no reason to investigate the controller.
When your class has a single responsibility, it depends on other components for any other functionality it requires.
The class handles some logic, which means it does not handle creation of its dependencies. Hence, your class gets the dependencies from outside.
When your class does that, it becomes easier to inject fake dependencies - which is exactly what you need to unit test.
From the function level, to your folder structure, having "things" be responsible for one thing makes it easier to name them.
A component that does one specific thing, can have an equally specific name, at the same abstraction level.
When the class encapsulates HTTP calls to get and set
Contact from a DB, it becomes clear that it should be named
The folder that contains all the components and logic that handles the login page, would probably be named
When your library handles thread pools using a SQL server, it would probably be named
Now that your class does one thing, and is named to match, you'll find yourself following established design patterns. When you separate the modeling of a graph from the algorithm that traverses it, you end up with the
Strategy class and the context it operates on.
The graph is comprised of individual nodes, each encapsulating its data and logic. Congratulations! You are using the
Composite design pattern.
When you combine all of the above, you get code that is shorter, highly focused, with lower cyclomatic complexity. Plus, the code is easy to find.
These are all things that every developer will appreciate. Think of the times where you had to juggle multiple trails of thought to try and figure out why something does not work right.
Because it helps generate code that is easier to maintain, test, refactor, and extend.
Maintainable code is critical for allowing your project to continue consistent and fast development.
SRP helps you make better hamburgers.