{
"$type": "site.standard.document",
"canonicalUrl": "https://jacob.blog/notes/what-developers-miss-about-the-single-responsibility-principle",
"description": "The real meaning of the \"S\" in SOLID: a module should have one, and only one, reason to change.",
"path": "/notes/what-developers-miss-about-the-single-responsibility-principle",
"publishedAt": "2024-11-05T00:00:00.000Z",
"site": "at://did:plc:ckthoyuvsmkp254fyuinyzb2/site.standard.publication/3mndm6tiamb26",
"tags": [
"software-engineering",
"solid",
"clean-code"
],
"textContent": "I reviewed a PR this week that added some functionality to Medium’s stats related to looking at a reader’s previous 90 days of activity.\n\nThis new function was proposed:\n\nThe function was clean, straightforward, and did a single thing.\n\nI asked for a change to this logic before I approved the PR. The database layer shouldn’t need to know about the logical choice to look back at the past 90 days. That’s a concern of the engagement module that calls the database. GetViews90Days violated the Single Responsibility Principle.\n\nThe “S” in SOLID\n\nThe Single Responsibility Principle (SRP) states that _a module should have one, and only one, reason to change_ (Robert Martin, _Clean Architecture_).\n\nA “reason to change” could mean a host of different things.\n\n- Business requirements shift from 7-day to 90-day windows\n- Client APIs are migrating from REST to GraphQL\n- Internal APIs are migrating from REST to gRPC\n- Database tables need new indexes for faster lookups\n- Slow queries for users with lots of followers need a cache layer\n- Your org signed a vendor deal with GCP and now you need to migrate off of AWS\n\nYou could rewrite the SRP as: _A module should be responsible to one, and only one, actor._ “Actor” here refers to a stakeholder, user, or dependency. Different actors have different reasons driving them. Those reasons should not coexist in the same module.\n\nGetViews90Days in the database module violates the SRP because the database shouldn’t know about the product decision to look back at the previous 90 days. A better function definition (and one that was ultimately accepted) would look like this:\n\nWe can check this against a simple test: If we change the product functionality to look back at a different time window, say 180 days, does this module need to change? Nope! Just the module that defines the product functionality.\n\nGetViews follows the Single Responsibility Principle because it only has one reason to change (in this case, the database).\n\nSRP rhymes with “cohesion”\n\n“Cohesion” is a term closely related to the SRP. A module is cohesive when all the code related to a single “reason to change” lives together.\n\n_The code that changes together stays together._\n\nThe goal of the SRP is to maximize cohesion and reduce unwanted coupling.\n\nA note on coupling and cohesion: I often hear “coupling” and “cohesion” mentioned together, usually in a phrase like “High cohesion, low coupling.” Both are worth defining clearly.\n\n- High cohesion within modules is good. You want code that changes together to live together.\n- Low coupling between modules is good. You don’t want changes in one module to cause changes in other modules.\n\nYou want functionality grouped in a way that you can make changes in as few places as possible. And the fundamental concept that drives this? The Single Responsibility Principle.\n\nIf you’re interested in learning more, I highly recommend reading _Clean Architecture_. It explains the concept in a much more eloquent and approachable way.",
"title": "What developers miss about the Single Responsibility Principle"
}