Skip to main content

Does SRP feed tight coupling? [Resolved]

I designed a function which, afterwards, I noticed it is clearly doing 2 very different tasks in the same time.

So now I am thinking to split it into 2 different functions, each one of them doing only what it should do (SRP). Obviously, one of these functions will call to the services of the other one.

But I wonder if this is really a good decision because I tend to think this call increases tight coupling as per this (?)

So my question is: does SRP increase tight coupling?

Question Credit: Billal BEGUERADJ
Question Reference
Asked August 26, 2018
Posted Under: Programming
3 Answers

One of the key benefits of low coupling is that it reduces the number of things you need to consider simultaneously to understand a single component of a system -- allowing among other things for easier debugging, easier maintenance, and better extendability. A reasonable way to answer your question is to consider whether or not SRP would improve your code with respect to these metrics.

My claim is that SRP has the ability to reduce coupling, but that reduced coupling is not guaranteed. I'll illustrate this with two scenarios.

Scenario 1 (don't do this)

  • Start with one mega function foo().
  • Note that foo() violates SRP, so re-factor it into bar() and baz().
  • As your application grows, other parts of the code wind up depending on bar() and baz().
  • Customers and use cases change over time, so eventually foo() needs a modification. Most of the logic in foo() is implemented in bar() and baz(), so to change behavior in foo() we change the behavior in bar() and baz() instead.
  • Now everything breaks.

Even though SRP has the ability to reduce coupling (at least I'm claiming it does), in this example the programmer is treating foo(), bar(), and baz() as a single unit AND they have the additional complexity of that unit being split between multiple function definitions and maybe even multiple files. The SRP was in name only and had no real benefits because of how the functions were being used.

Scenario 2 (reduced coupling with SRP)

  • Start with one mega function foo().
  • Note that foo() violates SRP, so re-factor into bar() and baz().
  • As your application grows, other parts of the code wind up depending on bar() and baz().
  • Eventually foo() needs a modification, but we don't have an appropriate low-level component lying around with the desired functionality, so we make a new function bizz().
  • Now foo() consists of bar() and bizz(), and everything else still works fine.

In this example, it is easy to reason about the behavior of foo() because we're treating its two constituent parts as atomic. They have a well-defined behavior, and combined they make up foo(). When those behaviors are insufficient, we make a new atomic component with the desired functionality. This approach easily leads to code re-use and prevents API-breaking changes. Moreover, all the components are small enough and can be easily reasoned about and proven to be correct.

Extras: Even though SRP can decrease coupling in a sense, if functions are not grouped appropriately it has the potential to have every module in an application depending in some way or another on every other module. Designing the entire system to be loosely coupled is every bit as important as designing functions to be loosely coupled, and for roughly the same reasons.

credit: Hans Musgrave
Answered August 26, 2018

From any reasonable point of view, the action of extracting of part of function into another function does not cause any harm which can attributed to a coupling. What may be bad is that later somebody reuses the extracted functions without careful consideration is it really the same functionality (as in scenario described in another answer). So you should consider it carefully, and limit usage of the sub-functions, by using the measures provided by your language (private methods etc.)

credit: max630
Answered August 26, 2018
Your Answer