Archive for the 'Programming' category

Legacy code is 3rd party code

published on July 19, 2018.

Within the TDD community there’s an advice saying that we shouldn’t mock types we don’t own. I believe it is good advice and do my best to follow it. Of course, there are people who say that we shouldn’t mock in the first place. Whichever TDD camp you’re in I think this “don’t mock what you don’t own” advice has an even better advice hidden in it. An advice that people often overlook because they see the word “mock” in it and go full berserk.

This hidden advice is that we should create interfaces, clients, bridges, adapters between our application and the 3rd party code we use. Will we create mocks from those interfaces in our tests doesn’t even matter that much. What matters is that we create and use these interfaces so that our application is better decoupled from the 3rd party code. A classic example of this in the PHP world would be to create and use an HTTP client within the application that uses the Guzzle HTTP client, instead of using the Guzzle client directly in the application code.

Why? Well, for one, Guzzle has a much bigger public API than what your application (in most cases) needs. Creating a custom HTTP client that exposes only the required subset of Guzzle’s API will limit what the application developers can do with it. If Guzzle’s API changes in the future, we’ll have to change how we call it in only one place, instead of trying to make the required changes in the entire application and hope that we broke nothing. Two very good reasons and I haven’t even mentioned mocks! gasp

I don’t think this is that hard to achieve. 3rd party code lives in a separate folder from our application code, usually in vendor/ or library/. It also has a different namespace and naming convention than our application code. It is fairly easy to spot 3rd party code and with a bit of a discipline we can make our application code less dependant on 3rd parties.

What if we apply the same rule to legacy code?

What if we start looking at our legacy code the same way we look at the 3rd party code? This might be difficult to do, or even counterproductive, if the legacy code is in a maintenance-only mode, where we only fix bugs and tweak bits and pieces of it. But if we are writing new code that is (re)using legacy code, I believe we should look at legacy code the same way we look at 3rd party code, at least from the perspective of the new code.

If at all possible legacy and new code should live in different folders and use different namespaces. It’s been a long time since I last saw a system without autoloading so this is doable. But instead of just blindly using legacy code within the new code, what if we create interfaces for the legacy code and use those in the new code?

Legacy code is all too often full of “god” objects that do way too many things. They reach out to global state, have public properties or magic methods that expose privates as if they were public, have static methods that are just so convenient to call from anywhere and everywhere. Well, guess what? That convenience got us in this situation in the first place.

Another, maybe an even bigger issue with legacy code is that we are so ready to change it, fix it, hack it, because we don’t see it as a 3rd party code. What do we do when we see a bug or when we want to add a new feature to 3rd party code? We open up an issue and/or create a pull request. What we don’t do is go inside the vendor/ folder and make our changes there. Why would we do that to legacy code? And then we cross our fingers and hope we didn’t break anything.

Instead of blindly using legacy code within new code, let’s try writing interfaces that will expose only the required subset of the legacy “god” object’s API. Say we have a User object in the legacy code that knows everything about everyone. It knows how to change emails and passwords, how to promote forum members to moderators, how to update a user’s public profile, set notification settings, how to save itself, and so much more.

src/Legacy/User.php

<?php
namespace Legacy;
class User
{
    public $email;
    public $password;
    public $role;
    public $name;

    public function promote($newRole)
    {
        $this->role = $newRole;
    }

    public function save()
    {
        db_layer::save($this);
    }
}

It’s a crude example, but shows the problems: every property is public and can be easily changed to whatever value, we have to remember to explicitly call the save method after any change for these changes to persist, etc.

Let’s limit and prohibit ourselves from reaching out to those public properties and having to guess how does the legacy system work any time we want to promote a user:

src/LegacyBridge/Promoter.php

<?php
namespace LegacyBridge;
interface Promoter
{
    public function promoteTo(Role $role);
}

src/LegacyBridge/LegacyUserPromoter.php

<?php
namespace LegacyBridge;
class LegacyUserPromoter implements Promoter
{
    private $legacyUser;
    public function __construct(Legacy\User $user)
    {
        $this->legacyUser = $user;
    }

    public function promoteTo(Role $newRole)
    {
        $newRole = (string) $newRole;
        // I guess you thought $role in legacy is a string? Guess again!
        $legacyRoles = [
            Role::MODERATOR => 1,
            Role::MEMBER => 2,
        ];
        $newLegacyRole = $legacyRoles[$newRole];
        $this->legacyUser->promote($newLegacyRole);
        $this->legacyUser->save();
    }
}

Now when we want to promote a User from the new code we use this LegacyBridge\Promoter interface that deals with all the details of promoting a user within the legacy system.

Change the language of the legacy

An interface for the legacy code gives us an opportunity to improve the design of the system. An interface can free us from any potential naming mistakes we did in the legacy. The process of changing a user’s role from a moderator to a member is not a “promotion”, but rather a “demotion”. Nothing stops us from creating two interfaces for these two different things, even though the legacy code sees it the same:

src/LegacyBridge/Promoter.php

<?php
namespace LegacyBridge;
interface Promoter
{
    public function promoteTo(Role $role);
}

src/LegacyBridge/LegacyUserPromoter.php

<?php
namespace LegacyBridge;
class LegacyUserPromoter implements Promoter
{
    private $legacyUser;
    public function __construct(Legacy\User $user)
    {
        $this->legacyUser = $user;
    }

    public function promoteTo(Role $newRole)
    {
        if ($newRole->isMember()) {
            throw new \Exception("Can't promote to a member.");
        }
        $legacyMemberRole = 2;
        $this->legacyUser->promote($legacyMemberRole);
        $this->legacyUser->save();
    }
}

src/LegacyBridge/Demoter.php

<?php
namespace LegacyBridge;
interface Demoter
{
    public function demoteTo(Role $role);
}

src/LegacyBridge/LegacyUserDemoter.php

<?php
namespace LegacyBridge;
class LegacyUserDemoter implements Demoter
{
    private $legacyUser;
    public function __construct(Legacy\User $user)
    {
        $this->legacyUser = $user;
    }

    public function demoteTo(Role $newRole)
    {
        if ($newRole->isModerator()) {
            throw new \Exception("Can't demote to a moderator.");
        }
        $legacyModeratorRole = 1;
        $this->legacyUser->promote($legacyModeratorRole);
        $this->legacyUser->save();
    }
}

Not that big of a change, yet the intent of the code is much clearer.

Now the next time you want to reach out to that legacy code and call some methods on it, try and make an interface for it. It might not be feasible, it might be too expensive to do. I know that static method on that god object is really easy to use and will get the job done much quicker, but at least consider this option. You might just improve the design of the new system you’re building a tiny little bit.

Happy hackin’!

Docker containers for PHP with PHPDocker.io

published on March 27, 2018.

This past weekend I was playing around on some pet projects and wanted to get up and running quickly. My initial reaction was to reach for a Vagrant box provisioned with Ansible. After all, that’s what I’ve been using for a really long time now.

Recently I’ve been also learning a bit more about Docker, so I figured maybe this pet project would be a good project to replace the standard Vagrant set up and go with Docker instead. When it comes to Docker, by now I believe I have a fairly good understanding of how it works and how it’s meant to be used in a development environment. I’ve learned a lot about it from Vranac, as well as poked around it on my own.

While trying to write a set of Docker files and Docker compose files for this project, I thought there must be an easier way to do this… And then I remembered that some time ago I came across a generator to generate Docker environments for PHP projects: PHPDocker.io. As they state on their website:

PHPDocker.io is a tool that will help you build a typical PHP development environment based on Docker with just a few clicks. It supports provisioning of the usual services (MySQL/MariaDB, Redis, Elasticsearch...), with more to come. PHP 7.1 is supported, as well as 7.0 and 5.6.

Click-click-click… done.

What I like about PHPDocker is that it takes a couple of clicks and filling out a couple of text fields to get a nice zip with all the things needed to get a project up and running. It has support for a “generic” PHP application, like Symfony 4, Zend Framework and Expressive, or Laravel, as well as for applications based on Symfony 23, or Silex. PHP versions supported range from 5.6 to 7.2 and a variety of extensions can be additionally enabled. Support for either MySQL, MariaDB, or Postgres is provided, as well as a couple of “zero-config” services like Redis or Mailhog.

The zip file comes with a phpdocker directory that holds the configurations for the specific containers such as the nginx.conf file for the nginx container. In the “root” of the zip there’s a single docker-compose.yml file which configures all the services we told PHPDocker we need:

docker-compose.yml

###############################################################################
#                          Generated on phpdocker.io                          #
###############################################################################
version: "3.1"
services:

    mysql:
      image: mysql:5.7
      container_name: test-mysql
      working_dir: /application
      volumes:
        - .:/application
      environment:
        - MYSQL_ROOT_PASSWORD=root
        - MYSQL_DATABASE=test
        - MYSQL_USER=test
        - MYSQL_PASSWORD=test
      ports:
        - "8082:3306"

    webserver:
      image: nginx:alpine
      container_name: test-webserver
      working_dir: /application
      volumes:
          - .:/application
          - ./phpdocker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      ports:
       - "8080:80"

    php-fpm:
      build: phpdocker/php-fpm
      container_name: test-php-fpm
      working_dir: /application
      volumes:
        - .:/application
        - ./phpdocker/php-fpm/php-ini-overrides.ini:/etc/php/7.2/fpm/conf.d/99-overrides.ini

Run docker-compose up in the directory where the docker-compose.yml file is located and it’ll pull and build the required images and containers, and start the services. The application will be accessible from the “host” machine at localhost:8080, as that’s the port I defined I wanted exposed in this case. You can see that in the ports section of the webserver service.

One thing I noticed is that the mysql service doesn’t keep the data around, but that can be fixed by adding a new line to the volumes section of that service: ./data/mysql:/var/lib/mysql. The mysql service definition should now read:

    mysql:
      image: mysql:5.7
      container_name: test-mysql
      working_dir: /application
      volumes:
        - .:/application
        - ./data/mysql:/var/lib/mysql
      environment:
        - MYSQL_ROOT_PASSWORD=root
        - MYSQL_DATABASE=test
        - MYSQL_USER=test
        - MYSQL_PASSWORD=test
      ports:
        - "8082:3306"

Other than this, I didn’t notice any issues (so far) with the environment.

Inside the phpdocker folder there’s also a README file that provides additional information how to use the generated Docker environment, what services are available on what port, a small “cheatsheet” for Docker compose, as well as some recommendations how to interact with the containers.

Happy hackin’!

Bounded contexts and subdomains

published on March 20, 2018.

Back in October last year I wrote that I thought I understood bounded contexts, what they are and why we need them. Ever since realizing that a bounded context is a boundary of how a business sees a specific subject within a section of that business, learning anything and everything DDD became a lot easier.

I see bounded contexts as a big building block without which learning other parts of DDD is pretty much pointless. OK, pointless might be too harsh a word, but to be able to use entities, value objects, domain events, aggregates to their full potential, a good understanding of bounded contexts is needed.

Of course I didn’t stop learning about DDD since writing that post 5 months ago. If anything, I did my best to learn even more by reading books and articles, watching recorded conference talks, and thinking about this subject. A lot.

Uh, phrasing

In my previous post I had this image attached that I used to help explain the difference between a Book in two different bounded contexts. Recently I realized that that image has mistake in it. On that image I used the terms “Publisher” and “Seller” to distinguish the two bounded contexts. A better name for those would probably be “Publishing” and “Selling”.

It is important to get the naming right as it affects the understanding a great deal. It might not be an outright mistake, but a bounded context is probably better off not being named after a thing. Publisher, seller, warehouse, these are the things we model inside our bounded contexts. A bounded context should name in what context do these models apply: publishing, selling, warehousing. Properly naming a bounded context will also help to identify should a model of something be an aggregate (root), an entity, or a value object.

There are probably other things I got wrong in that post, but so far I see this naming issue as the biggest one.

What about subdomains?

One thing I didn’t know and understand when I was writing the previous post was the importance of (sub)domains in connection with bounded contexts. I’m still not 100% sure I do. A business operates within a domain and that’s what we’re trying to design and model with DDD. It has one core domain which represents the reason why the business exists in the first place and at least one more subdomain that supports that core domain. The core domain is the main problem a business is trying to solve and the subdomains are all the other problems that come along with trying to solve the core domain problem.

Vaughn Vernon in his “Implementing Domain-Driven Design” book states (I’m paraphrasing here a bit) that “the subdomains live in the problem space and the bounded contexts in the solution space”. It took me a while to really understand this and what the implications of it are.

When writing software that will support the business and help solving the problems coming from the core domain and supporting subdomains we create models. These models will be “fine tuned” so that they provide the most optimal solution for the problem. But to provide these solutions, we also need to say what is the context of these models in which they help solve the problem.

Imagine a software that is being developed to support a dentist. A dentist has two problems: fixing patients’ teeth and making appointments for the patients. Fixing teeth is the core domain and making appointments is a supporting subdomain. In the core domain the medical staff cares about a patient’s dental history, can they handle general anesthesia or not, what their current problem is, etc. In the subdomain the staff (not necessarily medical staff) cares about a patient’s contact information, a date and a time that best suits both the doctor and the patient, the type of dental work needed, etc. Both domains need a model of a patient, but that model will depend on the bounded context we put in place to ensure the correct information and features are available when solving the problems of each domain.

Subdomains and bounded contexts go hand in hand and I think one can’t be understood without the other. The optimal solution would be to have one bounded context in one subdomain. The world is not a perfect place, software even less so, so it might happen that one bounded context spans multiple subdomains, or that one subdomain has multiple bounded contexts.

Problems and solutions

A key element to DDD is that our understanding of the domain will constantly change, improve, as we learn more about it. That’s one of the reasons why we need to be ready to change or throw away models we came up with. This ever-evolving state means that the subdomains and the bounded contexts can and will change, too.

A bounded context can grow or shrink, split in two, be combined in one, regardless of the subdomain(s) it is in. Taking a different approach in solving a problem doesn’t mean that the problem itself has changed.

On the other hand if the problem changes, the solution should change too. If during development we realize that the core domain can be further split into a smaller, more focused core domain and a new subdomain then the solution to those problems should change. Most likely the models we developed don’t fit the problems any more and the boundaries around our contexts have moved.

This post has evolved, too

Initially this wasn’t the post I wanted to write. I did start writing about bounded contexts, but then I realized I can’t talk about them without talking about subdomains. Both the title and the contents changed at least 3 times. More topics to cover in the future I guess.

Happy hackin’!

Mockery partial mocks

published on January 28, 2018.

In dealing with legacy code I often come across some class that extends a big base abstract class, and the methods of that class call methods on that big base abstract class that do an awful lot of things. I myself have written such classes and methods in the past. Live and learn.

One of the biggest problems with this kind of code is that it is pretty hard to test. The methods from the base class can return other objects, have side effects, do HTTP calls…

A typical example of this would be a base model class that has a getDb() method:

AbstractModel.php

<?php

abstract class AbstractModel
{
    protected $db = null;

    protected function getDb()
    {
        if ($this->db == null) {
            $db = Config::get('dbname');
            $user = Config::get('dbuser');
            $pass = Config::get('dbpass');
            $this->db = new PDO('mysql:host=localhost;dbname='.$db, $user, $pass);
        }
        return $this->db;
    }
}

which can be called in child classes to get access to the database connection:

ArticleModel.php

<?php

class ArticleModel extends AbstractModel
{
    public function listArticles()
    {
        $db = $this->getDb();
        $stmt = $db->query('SELECT * FROM articles');

        return $stmt->fetchAll();
    }
}

If we want to write unit tests for this listArticles() method, the best option would probably be to refactor the models so that the database connection can be injected either through the constructor, or with a setter method.

In case refactoring is not an option for whatever reason, what we can do is to create a partial mock of the ArticleModel using Mockery and then mock (well, stub to be more precise) out only the getDb() method that will always return a mocked version of the PDO class:

tests/ArticleModelTest.php

<?php

use Mockery\Adapter\Phpunit;

class ArticleModelTest extends MockeryTestCase
{
    public function testListArticlesReturnsAnEmptyArrayWhenTheTableIsEmpty()
    {
        $stmtMock = \Mockery::mock('\PDOStatement');
        $stmtMock->shouldReceive('fetchAll')
            ->andReturn([]);
        $pdoMock = \Mockery::mock('\PDO');
        $pdoMock->shouldReceive('query')
            ->andReturn($stmtMock);

        // Create a partial mock of ArticleModel
        $articleModel = \Mockery::mock('ArticleModel')->makePartial();

        // Stub the getDb method on the ArticleModel
        $articleModel->shouldReceive('getDb')
            ->andReturn($pdoMock);

        // List all the articles
        $result = $articleModel->listArticles();
        $expected = [];

        $this->assertSame($expected, $result);
    }
}

When we tell Mockery to make a partial mock of a class, any method on that partially mocked class that has expectations set up will be mocked, but calls to other methods Mockery will pass through the real class. In other words, even though the ArticleModel is a partial mock, anytime we call the listArticles() method Mockery will pass that call to the original method, and only the calls to the getDb() method are being mocked.

Using partial mocks should probably be an option of a last resort and we should always aim to refactor code to be easier for testing, but there are cases when they can really help us in testing legacy code.

Happy hackin’!

Build and run Golang projects in VS Code

published on January 24, 2018.

I’ve been using VS Code for my Golang development needs for a few months now. Minor kinks here and there, nothing serious, and the development experience gets better with every update. I have also tried out IntelliJ Idea as the editor, and one feature that I’m missing in Code from Idea is the build-run-reload process. I thought to myself, that’s such a basic feature, it should be possible to have that.

And it is! VS Code Tasks to the rescue!

These tasks allow us to run different kind of tools and, well, tasks inside VS Code.

Go to Tasks -> Configure Default Build Task and then select the “Create tasks.json file from template” in the little pop-up window, and after that select the “Others” option. This tasks.json file will live inside the .vscode directory.

For my overcomplicated d20 roller, which is my first website built with Golang, I have the following content for the tasks:

.vscode/tasks.json

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build and run",
            "type": "shell",
            "command": "go build && ./d20",
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

What this one task does is that it runs go build to build the project and then runs the generated executable, which for this project is d20.

I guess providing a standardized name to go build with the -o flag this could be made more portable so that the command part reads something like go build -o proj && ./proj, but I’m ok with this for now.

And now just type Ctrl+Shift+b and Code will execute this “Build and run” task for us! Hooray! The terminal window in Code will pop-up saying something like:

> Executing task: go build && ./d20 <

By going to http://localhost:8080 I can see that my little website is up and running. Cool.

But if we want to restart this taks, running Ctrl+Shift+b again won’t work and Code will complain that the “Task is already active blablabla…”.

Looking at the Tasks menu, we can see that there’s a “Restart running task…” menu entry. Clicking that, it pops up a window with a list of running tasks. In this case there’s only one, our “Build and run” task. Clicking through the menu every time would be boring, so let’s add a keyboard shortcut for it.

Go to File -> Preferences -> Keyboard shortcuts (or just hit Ctrl+k Ctrl+s), search for “Restart running task” keybinding, and set it to whatever you like. I’ve set it to Ctrl+Alt+r.

Finally, the flow is Ctrl+Shift+b to start the taks for the very first time, code-code-code, Ctrl+Alt+r to re-build. Sweet. Now the only annoying bit is that I have to pick out that one running task from the list of running tasks when restarting, but I can live with that. For now.

Happy hackin’!

Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2018
Get the feed