0

If you had a Service class for every business related module such as UserService. You might have AddProductToBasket() and PlaceOrder().

These methods would rely on lower level modules defined in an IOC container. The PlaceOrder() would not make calls directly to the database or payment service but it would glue all the logic together.

Would this not break the single responsibility principle though. Because even though the Service class is not making direct calls it still carries out many different business functions, and if two business functions change in the same class, then the class has multiple reasons to change therefore.

Would it make sense to have a class for each business function?

2 Answers2

2

You're missing a very important point here: Domain Models and Aggregates. In your example, the AddProductToBasket method should reside on a Basket class.

Multiple business functions might not make sense in that context. Make sure you're separating them properly in the right Bounded Context. For example, if you're using microservices, you might want to have one microservice per Bounded Context.

David Guida
  • 950
  • 9
  • 19
  • 2
    It might be useful to read through this discussion as well: https://stackoverflow.com/questions/8808314/how-single-responsibility-principle-relates-to-anemic-rich-domain-model – Riaan Nel Dec 14 '20 at 06:45
2

I would like to suggest you study this blog:

https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html

As per my understanding, I think that the name is confusing. It is functions that should have only one responsibility.

To me, SRP can be viewed as:

1). The objective of SRP is to achieve cohesion, to put closely related things into one class and the lesser ones to act as dependency and code should try to have zero dependencies if possible though usually not possible.

So, if you use UserService for placeOrder() and addProductToBucket() then your code is less cohesive and thus violates SRP.

Cohesion can be seen with respect to Bounded context as mentioned in @DavidGuida's answer.

2). A class should not contain business logic for multiple Actors( I have explained it in the last paragraph). Actor means a single user or group of users needed to be treated uniformly. Like we can have Admin and simple User as two different Actors.

Hence, the classes should be designed to be loosely coupled, with lesser dependencies, and to handle a single resource. That is UserService should only handle user-specific tasks like registerUser(), updatePassword(), etc.

We can create OrderService to handle placeOrder() and ProductService and BucketService to handle addProductsToBasket().

BucketService can act as a dependency to ProductService or vice-versa.

ProductService Tasks could be:

  • Checking if the product is available or not.
  • Call BucketService to add products into the bucket.
  • Decrease product count.

BucketService Tasks might be:

  • Check if the bucket is full or not.
  • Add product into the bucket.
  • Increase the count for products in the bucket.

However, if placeOrder() can be called by Admin and by common user then SRP will come into play. Then OrderService can act as Facade (rename to OrderFacade) and then it can do similar actions within it and for admin and user-specific actions, it can use Strategy Pattern.

Like We can create an interface OrderService having function create implemented by OrderServiceForAdmin and OrderServiceForUser classes.

Thus for an Admin-related change, we will update OrderServiceForAdmin and for user-related change, OrderServiceForUser will be modified.

References:

The blog mentioned above.

Books by Robert Martin. 1). Clean Code 2). Clean Architecture

NOTE: I am still learning these concepts and thoughts are welcome.

FarazAhmed
  • 43
  • 6