Question

In other words, is DRY (don't repeat yourself) applied at a class level a subset of SRP (single responsibilty principle)?

What I mean is that while SRP states that each class should have only a single responsibility ( ie. class should only have one reason to change ), is it the application of DRY at class level that prevents two classes from having the same responsibility ( thus it is DRY that prevents the repetition/duplication of same responsibility in two different classes )?

Thank you

Was it helpful?

Solution

What I mean is that while SRP states that each class should have only a single responsibility ( ie. class should only have one reason to change ), is it the application of DRY at class level that prevents two classes from having the same responsibility ( thus it is DRY that prevents the repetition/duplication of same responsibility in two different classes )?

No. You can still not repeat yourself but violate single responsibility. Likewise, you can repeat yourself but classes only have a single (duplicated, but subtly different) responsibility.

While the two guidelines can and will tend to overlap, they are orthogonal concepts.

OTHER TIPS

SRP means that your class should have only a single responsibility, so you can easily name your class, and you can tell only by reading the name, what it does.

DRY means that you should not repeat yourself, so by maintaining your code you don't have to override the same code twice or more.

They have certainly a connection, because both of them are about maintaining the code. DRY is a low abstraction level tool to do that, because it has no clue about what the code does. SRP is a high abstraction level tool to do that, because it is about responsibilities and not the code itself. So you should use both concepts together by developing your application. Based on every case I met until now, I recommend the SRP over DRY rule. So by any conflict between the two principles you can decide which one to use.

For example, where A and B are responsibilities:

If you have a DRY code which does not meet SRP:

class AB
    doSomethingArelated()
    doSomethingBrelated()

you can split it up the following way, so it will meet with DRY and SRP as well:

class A
    doSomethingArelated()

class B
    doSomethingBrelated()

If you have a DRY code, but A and B use the same properties:

class AB
    x
    y
    doSomethingArelatedToX()
    doSomethingBrelatedToXAndY()

then if you want to meet with DRY and SRP at once you should use polymorphism. You should use composition over inheritance by that, because it is easier to maintain.

class AB
    a
    b
    doSomethingArelatedToX()
        a.doSomethingArelatedToX()
    doSomethingBrelatedToXAndY()
        b.doSomethingBrelatedToXAndY()

class A
    c
    doSomethingArelatedToX()
        c.doSomethingGeneralToX()

class B
    c
    y
    doSomethingBrelatedToXAndY()
        c.doSomethingGeneralToX()
        doSomethingToY()
    doSomethingToY()

class C
    x
    doSomethingGeneralToX()

In really special cases SRP can override DRY:

class AB
    a
    b
    doSomethingArelatedToX()
    doSomethingBrelatedToXAndY()

class A
    x
    doSomethingArelatedToX()

class B
    x
    y
    doSomethingBrelatedToXAndY()

This happens by DDD when you have properties related to multiple bounded contexts. The most common thing is the aggregate id in here, but for example by a webshop the product size or weight can be important in the delivery and inventory contexts either.

Some design patterns could allow you to have simpler class by sharing the common routine.

If for example, you have to do a discount calculation on sales and in the sales report, instead of having the same code in both classes, you could have a third, more specific class, that does that calculation.

This way, your class that compute the sale, could rely on the third class to get the final price, as could the sale report class.

See the Strategy Pattern and Composite pattern as starter examples

Licensed under: CC-BY-SA with attribution
scroll top