DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Modern Test Automation With AI (LLM) and Playwright MCP
  • AI-Driven Test Automation Techniques for Multimodal Systems
  • Debugging With Confidence in the Age of Observability-First Systems
  • Accelerating Debugging in Integration Testing: An Efficient Search-Based Workflow for Impact Localization

Trending

  • Unit Testing Large Codebases: Principles, Practices, and C++ Examples
  • Event-Driven Microservices: How Kafka and RabbitMQ Power Scalable Systems
  • Apple and Anthropic Partner on AI-Powered Vibe-Coding Tool – Public Release TBD
  • Secrets Sprawl and AI: Why Your Non-Human Identities Need Attention Before You Deploy That LLM
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. The Single Responsibility Principle

The Single Responsibility Principle

By 
Eyal Golan user avatar
Eyal Golan
·
Feb. 05, 14 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
28.1K Views

Join the DZone community and get the full member experience.

Join For Free

in this post i would like to cover the single responsibility principle ( srp ).
i think that this is the basis of any clean and well designed system.

what is srp?
the term was introduced by robert c. martin .
it is the ‘s’ from the solid principles, which are the basis for ood.
http://en.wikipedia.org/wiki/solid_(object-oriented_design)
here’s the pdf paper for srp by robert c. martin https://docs.google.com/file/d/0byowmqah_nugnhetcu5oekddmkk/

from wikipedia:

…in object-oriented programming, the single responsibility principle states that every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. all its services should be narrowly aligned with that responsibility….

from clean code :

a class or module should have one, and only one, reason to change .

so if a class (or module) needs to be modified for more than one reason, it does more than one thing. i.e. has more than one responsibility.

why srp?

  • organize the code
    let’s imagine a car mechanic who owns a repair shop.
    he has many many tools to work with. the tools are divided into types; pliers, screw-drivers (phillips / blade), hammers, wrenches (tubing / hex) and many more. how would it be easier to organize the tools?
    few drawers with different types in each one of them?
    or, many small drawers, each containing a specific type?now, imagine the drawer as the module . this is why many small modules (classes) are more organized then few large ones.
  • less fragile
    when a class has more than one reason to be changed, it is more fragile.
    a change in one location might lead to some unexpected behavior in totally other places.
  • low coupling
    more responsibilities lead to higher coupling.
    the couplings are the responsibilities.
    higher coupling leads to more dependencies, which is harder to maintain.
  • code changes
    refactoring is much easier for a single responsibility module.
    if you want to get the shotgun effect , let your classes have more responsibilities.
  • maintainability
    it’s obvious that it is much easier to maintain a small single purpose class, then a big monolithic one.
  • testability
    a test class for a ‘one purpose class’ will have less test cases (branches).
    if a class has one purpose it will usually have less dependencies, thus less mocking and test preparing.
    the “self documentation by tests” becomes much clearer.
  • easier debugging
    since i started doing tdd and test-first approach, i hardly debug. really.
    but, there come times when i must debug in order to understand what’s going on.
    in a single responsibility class, finding the bug or the cause of the problem, becomes a much easier task.

what needs to have single responsibility?
each part of the system.

  • the methods
  • the classes
  • the packages
  • the modules

how to recognize a break of the srp?

  • class has too many dependencies
    a constructor with too many input parameters implies many dependencies (hopefully you do inject dependencies). another way too see many dependencies is by the test class.
    if you need to mock too many objects, it usually means breaking the srp.
  • method has too many parameters
    same as the class’s smell. think of the method’s parameters as dependencies.
  • the test class becomes too complicated
    if the test has too many variants, it might suggest that the class has too many responsibilities.
    it might suggest that some methods do too much.
  • class / method is long
    if a method is long, it might suggest it does too much.
    same goes for a class.
    my rule of thumb is that a class should not exceed 200-250 loc. imports included ;-)
  • descriptive naming
    if you need to describe what your class / method / package is using with the and world, it probably breaks the srp.
  • class with low cohesion
    cohesion is an important topic of its own and should have its own post.
    but cohesion and srp are closely related and it is important to mention it here.
    in general, if a class (or module) is not cohesive, it probably breaks the srp. a hint for a non-cohesive class:
    the class has two fields. one field is used by some methods. the other field is used by the other methods.
  • change in one place breaks another
    if a change in the code to add a new feature or simply refactor broke a test which seems unrelated, it might suggest a breaking the srp.
  • shotgun effect
    if a small change makes a big ripple in your code. if you need to change many locations it might suggest, among other smells, that the srp is broken.
  • unable to encapsulate a module
    i will explain using spring, but the concept is important (not the implementation).
    suppose you use the @configuration or xml configuration.
    if you can’t encapsulate the beans in that configuration, it should give you a hint of too much responsibility.
    the configuration should hide any inner bean and expose minimal interfaces.
    if you need to change the configuration due to more than one reason, then, well, you know…

how to make the design compliant with the single responsibility principle
the suggestions below can apply to other topics of the solid principles.
they are also good for any clean code suggestion.
but here they are aimed for the single responsibility principle.

  • awareness
    this is a general suggestion for clean code.
    we need to be aware of our code. we need to take care.
    as for srp, we need to try and catch as early as we can a class that is responsible for too much.
    we need to always look for a ‘too big method’.
  • testable code
    write your code in a way that everything can be tested.
    then, you will surly want that your tests be simple and descriptive.
  • tdd
    (i am not going to add anything here)
  • code coverage metrics
    sometimes, when a class does too much, it won’t have 100% coverage at first shot.
    check the code quality metrics.
  • refactoring and design patterns
    for srp, we’ll mostly do extract-method, extract-class, move-method.
    we’ll use composition and strategy instead of conditionals.
  • clear modularization of the system
    when using a di injector (spring), i think that configuration class (or xml) can pinpoint the modules design. and modules’ single responsibility.
    i prefer to have several small to medium size of configuration files (xml or java) than having one big file / class.
    it helps see the responsibility of the module and easier to maintain.
    i think that the configuration approach of injection has an advantage of annotation approach. simply because the configuration approach put the modules in the spotlight.

conclusion
as i mentioned in the beginning of this post, i think that single-responsibility-principle is the basis of a good design.
if you have this principle in your mind while designing and developing, you will have a simpler more readable code.
better design will be followed.

one final note
as always, one needs to be careful on how to apply practices, code and design.
sometimes we might do over-work and make simple things over complex.
so a common sense must be applied at any refactor and change.

Robert C. Martin Testing

Published at DZone with permission of Eyal Golan, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Modern Test Automation With AI (LLM) and Playwright MCP
  • AI-Driven Test Automation Techniques for Multimodal Systems
  • Debugging With Confidence in the Age of Observability-First Systems
  • Accelerating Debugging in Integration Testing: An Efficient Search-Based Workflow for Impact Localization

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!