Design – Single Responsibility Principle Violation

designdesign-patternsobject-oriented-designsingle-responsibility

I recently got into a debate with another developer regarding the below class:

public class GroupBillingPayment
{
    public void Save(IGroupBillingPayment model)
    {
        if (model == null || UserInfo.UserID == 0)
        {
            throw new Exception("GroupBillingPayment object or Current User Id is NULL , Please Contact Administrator.");
        }

        Data.GroupBillingPayment groupBillingPayment = RepositoryManager.GroupBillingPaymentRepository.GetById(model.GroupBillingPaymentID);
        Mapper.Map(model, groupBillingPayment);
        ServiceManager.GroupBilling.IsBillAlreadyCancelled(groupBillingPayment.GroupBillingID, THROW_ERROR);
        groupBillingPayment.UpdatedBy = UserInfo.UserID;
        groupBillingPayment.UpdatedOn = DateTime.Now;
        RepositoryManager.GroupBillingPaymentRepository.Update(groupBillingPayment, false);
        UpdateGroupBilling([Parameters])
    }
}

I believe UpdateGroupBilling should not be called inside the save method as it violates the single responsibility principle. But, he says that each time a payment is made, the billing should be updated. Hence this is the correct approach.

My question, is SRP being violated here? If yes, how can we better refactor it so that both our criteria are met?

Best Answer

I would look at it this way:

A method should either call other methods (in same or other objects) which makes it a composed method or do "primitive calculations" (same level of abstraction).

The responsibility of a composed method is "call other methods".

So if your Save method does some "primitive calculations" itself (eg. checks return values), the SPR might be violated. If this "primitive calculations" lives in another method called by your Save method SRP is not violated.


The updated version of the Save method does not follow the single abstraction layer principle. Since this is the more important problem you should extract that to a new method.

This will convert Save into a composed method. As written, the responsibility of a composed method is "call other methods". Therefore calling UpdateGroupBilling([Parameters]) here is not a violation of the SRP, but a business case decision.