For an example, let's look into the following code and how much better it will become with the usage of SRP and introducing the Use case level.

As you can see, besides the fact that this handler forms the responses for the incoming requests, it holds all the business logic of the user registration process. This code writes responses and breaks other steps every time the previous step fails.

When the change comes, the viscosity symptom will rise up because there is no obvious design to preserve and every change of the code will be some kind of hacking. If it is required to send the notification to the registered user to verify their email, the code will become even harder to understand and test.

See the full code example at github.

The good part about the provided code example is that the previous developer created integration tests for registration requests and it is not a legacy code, which means that it could be refactored.

So let's start some refactoring and apply the Use case level. The first step is the encapsulation of the registration process logic into the Service Object.

The Registrate method has two steps required to register a user in the system:

Validation of the incoming form. Insertion of the model into the storage.

With the introducing of the Service Object, the previously viscous code becomes more obvious to follow and easy to understand. If changes occur, chances are that engineer making it will understand and preserve the existing design.

Changes in pull request.