Showing posts with label style. Show all posts
Showing posts with label style. Show all posts

Sunday, August 28, 2016

From Bad to Good: DI, DIC and Services

In this post, I intend to touch the concepts of:

Even though these terms seems scary at first especially to new-comers but are really easy to understand and help write quality code that is easy to understand and extend. We will take a ^legacy code^ and convert it into object-oriented one by using these principles.

Suppose we have simple application that sends newsletter email to all its subscribers, here is the legacy code:

// file: index.php or could also be considered as Controller file in MVC paradigm

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;

$dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
$pdo = new PDO($dsn);

$mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

$sql = 'SELECT * from subscribers';

foreach ($pdo->query($sql) as $row) {
    $mailer->sendMessage(
        $row['email'],
        'This is the email body',
        $row['name'],
        'info@example.com'
    );
}

Right now above code smells and has these problems:

  • Logic is mixed up, SQL queries, sending emails database configuration is all in one file

To fix this, first instinct is to convert it into class:

class SubscriberMailer
{
    public function sendEmails()
    {
        $dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
        $pdo = new PDO($dsn);

        $mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

        $sql = 'SELECT * from subscribers';

        foreach ($pdo->query($sql) as $row) {
            $mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

This looks good to eye but it has more problems:

  • Logic is still mixed up, SQL queries, sending emails database configuration is all in one file
  • It has hard-coded dependencies (tight-coupling) on PDO and Mailer class, what if we wanted to change Mailer class ?
  • It is hard to unit-test because of tight coupling

Let's try to fix these problems. We can see that this class has dependency on PDO so instead of hard-coding it inside SubscriberMailer class, we can ^pass^ it via its constructor which now makes the class:

class SubscriberMailer
{
    protected $pdo = null;

    public function __construct($pdo)
    {
        $this->pdo = $pdo;
    }

    public function sendEmails()
    {
        $mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

        $sql = 'SELECT * from subscribers';

        foreach ($this->pdo->query($sql) as $row) {
            $mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

This is a bit better, the class doesn't care where PDO objects comes from, it just needs one to operate and you can't instantiate the class without providing one so it makes its intention clear. So this is what is called Dependency Injection, no need to fear even though the term sounded scary initially (read my previous article on more ways of injecting dependencies). Here is how we use above class at this point of the time:

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;
use Demo\Mailer\SubscriberMailer;

$dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
$pdo = new PDO($dsn);

$subscriberMailer = new SubscriberMailer($pdo);
$subscriberMailer->sendEmails();

This is starting to look better compared to first snippet of code. However, we still have a problem in that we have hard-coded smtp config into our class, what if we wanted to change the smtp config without touching the class ? Or what if we had different setup of smtp config for development and production ? Remember a class should be a black-box which simply does its job without editing it again and again, you can only extend it not edit it. So this reasoning hints us that like pdo, we should also pass smtp config via class's constructor and move it from the class itself.

class SubscriberMailer
{
    protected $pdo = null;
    protected $smtpConfig = [];

    public function __construct($pdo, array $smtpConfig)
    {
        $this->pdo = $pdo;
        $this->smtpConfig = $smtpConfig;
    }

    public function sendEmails()
    {
        $mailer = new SmtpMailer(
            $this->smtpConfig['host'],
            $this->smtpConfig['user'],
            $this->smtpConfig['password'],
            $this->smtpConfig['port']
        );

        $sql = 'SELECT * from subscribers';

        foreach ($this->pdo->query($sql) as $row) {
            $mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

Usage:

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;
use Demo\Mailer\SubscriberMailer;

$dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
$pdo = new PDO($dsn);

$subscriberMailer = new SubscriberMailer($pdo, [
   'host' => 'smtp.example.com',
   'user' => 'user',
   'password' => 'password',
   'port' => '465',
]);

$subscriberMailer->sendEmails();

This is better, we can now readily change smtp config in one place and we don't have to touch our class. It still has these problems though:

  • It is tightly coupled to SMTP mailer, what if we wanted to change mailer from smtp to another one like sendmail ?
  • SQL is still written in our class, logic is mixed up, our mail class shouldn't know about users or interact with database, it just needs to send emails !

Hint: The new keyword is considered code-smell, whenever you encounter it, it means it is something you should pass via dependency injection.

So by now we know that to remove hard-coded dependency or tight-coupling, we should pass it instead via dependency injection. So instead of passing mailer config, we should pass mailer object:

class SubscriberMailer
{
    protected $pdo = null;
    protected $mailer = null;

    public function __construct(\PDO $pdo, SmtpMailer $mailer)
    {
        $this->pdo = $pdo;
        $this->mailer = $mailer;
    }

    public function sendEmails()
    {
        $sql = 'SELECT * from subscribers';

        foreach ($this->pdo->query($sql) as $row) {
            $this->mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

Usage:

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;
use Demo\Mailer\SubscriberMailer;

$dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
$pdo = new PDO($dsn);

$mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

$subscriberMailer = new SubscriberMailer($pdo, $mailer);       
$subscriberMailer->sendEmails();

This is better, we removed hard-coded dependency to smtp mailer and notice that we have also type-hinted the PDO and SmtpMailer in the constructor of our class, this is extremely helpful because:

  • Our class makes clear intention that it needs a PDO and SmtpMailer to work properly
  • If somebody passes something other than these two dependencies, they would get clear error message
  • Type-hinting makes our code self-documenting
  • It makes IDE auto-completion

Right now our mailer class knows it needs an instance of SmtpMailer to work and it should have a sendMessage method. Remember, we refactored our code in hope that we might use some other type of mailer like sendmail but problem is that it might not necessarily have the sendMessage method which means we cannot use it. So how do we solve this problem to be able to use some other type of mailer implementation ? Well the answer is to use an interface/contract and use that instead:

// app/Demo/Contracts/MailerInterface.php
interface MailerInterface
{
   public function sendMessage($email, $body, $subject, $from);
}

// app/Demo/Mailer/SmtpMailer.php
use Demo\Contracts\MailerInterface;

class SmtpMailer implements MailerInterface
{
    public function sendMessage($email, $body, $subject, $from) {
        // code to send email
    }
}

// app/Demo/Mailer/SubscriberMailer.php    
class SubscriberMailer
{
    protected $pdo = null;
    protected $mailer = null;

    public function __construct(\PDO $pdo, MailerInterface $mailer)
    {
        $this->pdo = $pdo;
        $this->mailer = $mailer;
    }

    public function sendEmails()
    {
        $sql = 'SELECT * from subscribers';

        foreach ($this->pdo->query($sql) as $row) {
            $this->mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

Just like every step that we are performing, this step also has nice advantages:

  • Our SubscriberMailer class is now greatly expandable since it now accepts ANY object that implements MailerInterface that has sendMessage method
  • It documents our code a bit more, it is clear now how an object should be constructed that implements the MailerInterface

All well and good so far. We now see that in our class has SQL to get users. Again it should not care about talking to database, it just needs users' emails to send emails to. To fix this, we need use the Repository Pattern which is essentially a class talking to database to manipulate specific entity, in this case users. So we can pass UserRepository as dependency that has a method to get all users:

// app/Demo/Mailer/SubscriberMailer.php
use Demo\Contracts\MailerInterface;
use Demo\Repositories\UserRepository;

class SubscriberMailer
{
    protected $mailer = null;
    protected $userRepository = null;

    public function __construct(MailerInterface $mailer, UserRepository $userRepository)
    {
        $this->mailer = $mailer;
        $this->userRepository = $userRepository;
    }

    public function sendEmails()
    {
        $users = $this->userRepository->getAll();

        foreach ($users as $user) {
            $this->mailer->sendMessage(
                $user->email,
                'This is the email body',
                $user->name,
                'info@example.com'
            );
        }
    }
}

Usage:

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;
use Demo\Mailer\SubscriberMailer;
use Demo\Repositories\UserRepository;

$mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

$subscriberMailer = new SubscriberMailer($mailer, new UserRepository);    
$subscriberMailer->sendEmails();

Awesome! our SubscriberMailer class now does not have any mixed-up logic, it is complete black-box whose task is to send emails to provided users. It doesn't need to care about how you pass MailerInterface or UserRepository, it just needs them to operate. It has only one task of sending emails. Not to mention that our class is also easy to be unit-tested. Notice also that we removed PDO as dependency since it is now job of UserRepository to give us the users.

We can now call our class a Service that performs one and only one task without any coupling. If you have heard about Service-Oriented Architecture, this is what it is, a collection of service classes with one and only one responsibility each without any hard-coded dependencies.

At this point of the time, we are all good with our class but one of the downsides of Dependency Injection is that all the complexity of creating and configuring objects is your job. Now this isn't that bad since it happens at one place and gives you the control but it is something which we can still improve.

To do this, we need to leverage what is called Dependency Injection Container (DIC). The job of DIC is to create and configure objects for us. There are many DIC out there for PHP but let's see our modified code using famous Pimple container, here we wrap the dependencies or services into Pimple container. I am not going into details of how to use it, you should refer to its documentation.

// file: container.php

use Demo\Mailer\SmtpMailer;
use Demo\Repositories\UserRepository;
use Pimple\Container;
use Demo\Mailer\SubscriberMailer;

$container = new Pimple();

// container can also hold configs - ideally should be put in separate file...
$container['smtp_config'] = [
   'host' => 'smtp.example.com',
   'user' => 'user',
   'pass' => 'password',
   'port' => '465',
];

$container['mailer'] = $container->share(function(Pimple $container){
   return new SmtpMailer(
      $container['smtp_config']['host'],
      $container['smtp_config']['user'],
      $container['smtp_config']['pass'],
      $container['smtp_config']['port']
   );
});

$container['userRepository'] = $container->share(function(){
   return new UserRepository();
});

$container['subscriberMailer'] = $container->share(function(Pimple $container){
   return new SubscriberMailer($container['mailer'], $container['userRepository']);
});

// file: index.php

require __DIR__ . 'vendor/autoload.php';
require __DIR__ . 'container.php';

$subscriberMailer = $container['subscriberMailer'];
$subscriberMailer->sendEmails();

Notice how clear and concise our index.php code is now compared to initial version.

Using the DIC provides us with these advantages:

  • Wrapping our object creation in container's anonymous function makes object creation lazy which means object isn't created only until needed and if we never reference our SubscriberMailer class, those objects are never created at all saving us memory !
  • Using the container's share method means no matter how many times we need, it will always give us same original object instance. If we need to send many emails, we don't need many instances. This also makes code a bit more faster.
  • All the logic of which objects depend on other objects is abstracted away into container itself, we don't need to worry how they are created or what their dependencies are, we just use our services straight away out of container.
  • If we ever need to change config or something, we only edit it at one place, nobody needs to know about this change.

In conclusion, no matter which framework you use, these principles can be applied to make code which is easy to understand, extend and test.

Monday, December 28, 2015

Coding to Interface

One of the nicest things you can add to your programming skills is coding to interface. One of the five principles of S.O.L.I.D is Dependency inversion principle which states:

In object-oriented programming, the dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details. The principle states:1

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on abstractions.

Pretty formal definition hun ? let's understand through example actually.

Imagine we have rudimentary MySQL wrapper class:

class Mysql
{
    protected $db = null;

    public function connect($dsn, $user = '', $pass = '')
    {
        $this->db = new PDO($dsn, $user, $pass);
    }

    public function query($query)
    {
        return $this->db->query($query);
    }
}

Pretty common and valid code in old days we used to be proud while writing such class. There are couple of problems associated with it though:

  • The class Mysql has implicit dependency (tight-coupling) on the PDO class. All dependencies should always be explicit not implicit.
  • It is hard to unit-test due to implicit dependency

Let's use above class:

class User
{
    private $database = null;

    public function __construct()
    {
        $this->database = new Mysql();
        $this->database->connect('mysql:host=localhost;dbname=test', 'root', '');
    }

    public function getUsers()
    {
        $users = $this->database->query('SELECT * FROM users ORDER BY id DESC');
        print_r($users);
    }
}

$user = new User();
$user->getUsers();

Again pretty common piece of code but again this one has even more problems:

  • The class User has implicit dependency (tight-coupling) on the Mysql class. All dependencies should always be explicit not implicit.
  • It is hard to unit-test due to implicit dependency
  • If we wanted to change database credentials, we need to edit the User class which is not good; every class should be completely modular or black box. If we need to operate further on it, we should actually use its public properties and methods instead of editing it again and again.
  • Let's assume right now class is using MySQL as database. What if we wanted to use some other type of database ? You will have to modify class.
  • The User class does not necessarily need to know about database connection, it should be confined to its own functionality only. So writing database connection code in User class doesn't make it modular. This defeats the Single responsibility principle.

You might wonder above code has problems but these days we write code based on MVC design pattern and follow best practices and write modern code but I am sure below code is pretty common even today using any framework you use:

class UserController extends Controller
{
    public function actionListAllUsers()
    {          
       // fetch all users from database
        $users = User::model()->findAll();

       // show them on screen
        print_r($users);          
    }
}

If you analyze this has same problems again in that class UserController is tightly coupled (implicit dependency) with User model class which also makes it hard to unit-test.

This means:

Coupled Code is Evil BIG DOT

So what's the solution ?

The solution is Dependency Injection (see my previous post Dependency Injection in PHP). The idea behind Dependency Injection is that instead of writing implicit dependencies, we should pass/provide those via constructor or setter method or even interface.

Let's refactor User class code and pass our dependency via constructor instead of hard-coding it inside User class method:

class User
{
    private $database = null;

    public function __construct(Mysql $database)
    {
        $this->database = $database;
    }

    public function getUsers()
    {
        $users = $this->database->query('SELECT * FROM users ORDER BY id DESC');
        print_r($users);
    }
}

$database = new Mysql();
$database->connect('mysql:host=localhost;dbname=test', 'root', '');
$user = new User($database);
$user->getUsers();

This is much better! We no more have implicit dependency on Mysql class which also makes our User class easier to unit-test. The class makes clear intention that it needs some sort of Mysql class. It also doesn't know (or care) where Mysql will come form, it just needs one to operate. The User class is now completely modular and follows single responsibility principle (that of manipulating users).

In the similar way, we can also improve our modern code:

class UserController extends Controller
{
    protected $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function actionListAllUsers()
    {          
       // fetch all users from database
        $users = $this->user->findAll();

       // show them on screen
        print_r($users);          
    }
}

Here again we pass dependency (User class) of UserController via its constructor making it much better. So all good ? Not really...

We still have a problem

One problem with User class which still persists is that it is tied to specific type of database (Mysql). What if we wanted to use some other database like Sqlite or SQL Server or some other ? Well this is where dependency inversion principle comes into play.

To overcome this problem, we need to create an interface (abstraction or contract - see definition of DIP above) which would allow us to use any database with User class. Here is our interface that all databases would implement:

interface DB
{
    public function connect($dsn, $user = '', $pass = '');
    public function query($query);
}

Here is Mysql class now implementing above interface:

class Mysql implements DB
{
    protected $db = null;

    public function connect($dsn, $user = '', $pass = '')
    {
        $this->db = new PDO($dsn, $user, $pass);
    }

    public function query($query)
    {
        return $this->db->query($query);
    }
}

Another database class implementing above interface:

class Sqlite implements DB
{
    protected $db = null;

    public function connect($dsn, $user = '', $pass = '')
    {
        $this->db = new PDO($dsn);
    }

    public function query($query)
    {
        return $this->db->query($query);
    }
}

As you can see both Mysql and Sqlite implement methods imposed by the interface. Finally here is our User class:

class User
{
    private $database = null;

    public function __construct(DB $database)
    {
        $this->database = $database;
    }

    public function getUsers()
    {
        $users = $this->database->query('SELECT * FROM users ORDER BY id DESC');
        print_r($users);
    }
}

Notice that in constructor of above class, we are now passing interface rather than specific type of database.

Now we can use any database for the User class, here is example of Mysql:

$database = new Mysql();
$database->connect('mysql:host=localhost;dbname=test', 'root', '');
$user = new User($database);
$user->getUsers();

And example of Sqlite database class:

$database = new Sqlite();
$database->connect('sqlite:database.sqlite');
$user = new User($database);
$user->getUsers();

Amazing! we can now readily change database to be used with our User class, our User class is much more flexible by following the dependency inversion principle. If client requires to use some other database, no problem we implement one and specify to User class in similar fashion!

As you can see we took basic and common example of code and converted it into re-usable, flexible, modular and testable piece of code.

You might want to read more about S.O.L.I.D principles to write pleasant code and as bonus avoid S.T.U.P.I.D code.

Popular Posts