The first refactor in the user registration use case

It is a myth that we can get systems “right the first time”.

This post is based on two other posts. Check them first for a broader understanding:

This post will provide you an update about the changes that I made in my project. These changes are in this commit. And I’ll also talk about:

  • Single Responsibility Principle
  • Entities
  • Test Driven Development and Unit Tests

The problem

While writing my last post in this project, I realized that my user registration use case had more than one responsibility. And this breaks the first SOLID principle, the Single Responsibility Principle. The use case had the complexity to validate data and deliver data across other layers.

Data validation
Delivering data across other layers
It is a myth that we can get systems “right the first time.” Instead, we should implement only today’s stories, then refactor and expand the system to implement new stories tomorrow…
Martin, Robert. “Clean Code” 2008

So, with all my tests passing, is time to refactor.

Single Responsibility Principle

The Single Responsibility Principle (SRP) states that a class or module should have one, and only one, reason to change.
Martin, Robert. “Clean Code” 2008

Analyzing the use case code, I have identified the following responsibilities:

  1. E-mail format validation
  2. Name format validation
  3. Password format validation
  4. Manage input data

Four reasons to change is too much. And except the last item, all others are not related to the use case context, and could be easily delegated to other classes.

But why having multiple responsibilities is not a good thing? Because the more reasons you have to change, the greater the chances to mess up something else. Besides that, it is harder to test a class with more than one responsibility.

Refactoring

Lets do this delicious refactoring

Now that I already know where the responsibilities are, it’s time to extract the code and test it. The code responsible to make format validations will be extracted to small classes, that will be responsible for a single purpose. These classes are called Entities.

Entities encapsulate Enterprise wide business rules. An entity can be an object with methods, or it can be a set of data structures and functions…
…They encapsulate the most general and high-level rules. They are the least likely to change when something external changes.
Martin, Robert. “The Clean Architecture” 2012

I’ll show just the ValidateEmailEntity. Because the other entities follow the same process. So I started with the entity tests. The first scenario is very simple, it’s just an assert by an empty e-mail, that should be invalid.

And to make this test run with success. The code below is quite enough.

After this simple scenario I started to increase the test complexity. Making asserts by email with invalid characters, without provider, incomplete, and with special characters.

And fortunately a simple regex (found on Stack Overflow 😆) made all scenarios pass. The code below shows how the ValidateEmailEntity got.

After creating an entity for each data format validation, I’ll go back to the use case and make use of these entities. Below is the old use case with multiple responsibilities:

The old use case

And after the refactor (13 additions and 24 deletions) the use case is cleaner and easy to understand:

As you can see I also created a protocol that had a isValid property to facilitate error validation. And another to get the respective error.

As it’s possible to note I also created a protocol to keep some pattern and this was useful to filter just the invalid inputs and I also created an error property.

And because I am testing the validations separated from the use case, It’s not necessary to test all data variations at the use case level anymore. So I ran the tests and all tests are green, with this the refactor is completed successfully.