SOLID: The Single-Responsibility Principle (SRP)

 This Object Oriented Programming principle states that each module or class should be responsible for only one part of the functionality. 

By saying this, we are stating that each subsystem, module, class or function should have just one reason to change. 

How do we accomplish this? By developing small service classes with enclosed objectives. 

What is it that we want to accomplish through this strategy? 
  1. More cohesion and less resistance to change.
  2. Allow the composition of classes (or class injection) which deserves a extended post in this blog.
  3. Avoid duplicity and copy-pasting portions of code.
Now, that seems fairly simple but, as with any theoretical principle, the problem is usually visualizing with an example what the theory is suggesting and, even more than that, in which cases should we apply this theory. Of course, it's not the same developing a small online shop for a cousin who produces and sells hand made costume jewelry, than developing  an app for the creation of a Logistics department within a Company which has seen a huge increase in its volume of work. If there is something that I have learned by developing is that there is never one only solution and that one solution, as much as it can be considered a good practice, is not valid for every problem. 

This principle is not about having tiny classes, or having classes with just one method. It's not about dramatically reducing the size of your classes. What it really is about is limiting the impact of change by identifying functionalities belonging to different layers or modules, and separating them into different classes. That way, we are modularizing according to likely sources of change. Any change we introduce in our app will probably mean changing different parts of our code, but if we have properly encapsulated and delimited functionalities, we will be able to easily identify the changes to be made without disturbing the rest of functionalities, reducing this way the inactivity periods needed to fix bugs derived from the change.

Uncle Bob described this in a beautiful way with just one sentence. 

"Gather together those things that change for the same reason, and separate those things that change for different reasons."

 So, as you can see, we are talking all the time about the same criteria to decide whether or not applying this principle to our code and where: predicting change. Again, the app we design for our cousin (aka, the jeweler of the family) is not likely to need a bunch of changes, other than adding new business lines, like, for example, adding jewels for men, or a specific jewels collection for babies. On the other hand, in the case of the app created for the newly implemented Logistics department for a flourishing company, changes are more than likely to happen within a short period of time.

 And before finishing, I'll leave in here part of my own code that I think could be refactored using this principle:


public function register(Request $request, UserPasswordEncoderInterface $passwordEncoder )
    {

        try {
            if ($this->isUserAlreadyLoggedIn()) {
                $this->throwAlreadyLoggedInUserMessage();
                return $this->redirectToRoute('profile');
            }
            $this->generateForm($request);
            if ($this->form->isSubmitted() && $this->form->isValid()) {
                $this->createNewUserEntityService($passwordEncoder);
                $this->createNewGameSessionService();
                $this->createNewGameHistoryEntryService();
                $this->createSuccessfullyRegisteredNewUser();
                return $this->redirectToRoute('app_login');
            }
            return $this->render('registation/index.html.twig', [
                'form' => $this->form->createView(),
            ]);
        } catch (\Exception $exception) {
            $this->createErrorMessage($exception);
            return $this->render('registation/index.html.twig', [
                'form' => $this->form->createView(),
            ]);
        }

    }

As you can see, the Register controller here does 3 things:
  1. Create a new User
  2. Create a New Game Session
  3. Create a New History Entry
As you can imagine, I haven't posted the complete controller as it is 363 lines long and tedious to read. In my opinion and after taking courses on SOLID Principles, Orient Oriented Programming and Clean Code, NewUser, NewGameSession and NewHistoryEntry could be split into three different classes injected into this register function. And further thinking, We could isolate the persisting to database function passing the new object created as a parameter. 
Not surprisingly, this code, which seemed nailed to me a month ago, has now plenty of refactoring possibilities. 
I must confess I feel a little bit shy about sharing my code. All friendly comments, reviews and suggestions are more than welcome. Luckily, I am still learning everyday and enjoying it as a child. 

Happy coding everyone!

Comments

Popular posts from this blog

Symfony HTTP client

Inheritance: Abstract classes and interfaces