Why and How to decouple your classes
with a real decoupling example
Found a typo? Edit meThere are some ways to couple your code, some frameworks like Laravel embrace you to do using their own façades or
even using ORM as ActiveRecord, but this is also possible using PHP native methods like time()
beyond others.
Unfortunately, in the long run, if you don't invert the dependencies, the code will get messy faster/easier, hurting your application. To avoid this, you must write tests. Writing tests help you realize how coupled is your business logic to infrastructure code.
Examples of classes that should be decoupled
Belongs to the Programming language itself like
- I/O functions like
fopen()
,file_exists()
,file_put_contents()
… - Network related like
curl_init()
,http_response_code()
,setcookie()
… - Relative to time like
date()
,time()
,microtime()
… - System like
getenv()
,exec()
,system()
…
Belongs to the infrastructure code like
- Framework classes like Laravel Façades
- Database (Active Record or raw queries instead of
Repository
pattern) - Third-party services like
Monolog
,Mandrill
,Salesforce
…
Decoupling a real example
For the next example, let’s try to use a Laravel facade and a PHP function.
Imagine we have the following service, and we really want to invert the dependencies. As you can see, we have the
trans()
facade and the date()
PHP function.
;
The first thing we should do is to move the trans()
Laravel function logic to a different place, in order to do that,
we have to invert the dependencies introducing a new interface as follows:
;
{
;
}
And place in a new class (which belongs to infrastructure layer) the original Laravel implementation.
;
From now on, we are able to switch the translator implementation between Laravel or a third-party one by implementing
the Translator
interface.
We can inject the new LaravelTranslator
service in our WelcomeService
defining in the service container
which implementation we want to resolve when the framework faces the Translator
in the constructor.
;
The next step is to do the same but with the date()
method.
;
{
;
}
And the PHP implementation:
;
Let’s do the same as we did previously, but this time we can inject our own SystemDate
implementation through the
Date
interface.
;
Finally, we can create a test for the WelcomeService
injecting the required dependencies.
Ideally we should write the test first, later the real implementation
Conclusion
Decoupling your classes is a good practice that will help you to maintain your codebase in the long run.
It will also help you not only to switch between different implementations of the same interface in case you decided to
change the framework or the third-party service but also to test your code in a more efficient way.