Gabriel's Tech blog https://detassigny.net Tech stuff, mostly programming en-US Sat, 02 Mar 2019 12:54:09 +0100 Sat, 02 Mar 2019 12:54:09 +0100 60 Mocking in PHP #1: Writing your own mocks https://detassigny.net/posts/7/mocking-in-php-1-writing-your-own-mocks A good way to vizualize how mocking works in the first place is to implement your own mocks Mocking is a fundamental part of unit testing. Without mocks, you're stuck into writing tests that need to handle all dependencies of your class. Which sometimes means having to interact with the database, a file system, an API... It's simply way to complicated and is outside the scope of unit testing anyway.

In this series of articles called "Mocking in PHP", I will explore different ways of mocking your dependencies when writing PHPUnit test.

While definitely not the most common way of doing this, writing your own mocks can be a great way to understand what a mock is and what it does.

On the following articles, I will then go through different methods, such as :

- PHPUnit mocks: Their syntax isn't very straightforward but they come out of the box with PHPUnit without a need for any other package.

- Mockery: This is probably the most popular PHP mocking library right now.

- Phake: Another mocking library. My personal favourite.

 

Case Study

First, let's define what we'll be testing here.

Let's say we have a service that is used by our application to interact with blog posts:

namespace App;

use Doctrine\ORM\EntityManagerInterface;

class PostService
{
    /** @var EntityManagerInterface */
    private $entityManager;

    /** @var PostRepository  */
    private $postRepository;

    public function __construct(EntityManagerInterface $entityManager, PostRepository $postRepository)
    {
        $this->entityManager = $entityManager;
        $this->postRepository = $postRepository;
    }

    public function createPost(Post $post): void
    {
        $this->entityManager->persist($post);
        $this->entityManager->flush();
    }

    public function getPost(int $id): Post
    {
        /** @var Post|null $post */
        $post = $this->postRepository->find($id);
        if (is_null($post)) {
            throw new \RuntimeException('Post not found');
        }

        return $post;
    }
}

It contains two methods :

- one to create a Post entity

- one to retrieve a Post by a given ID

Our service also has two Injected dependencies:

- Doctrine's entity manager. We need it for persisting our entities into the database.

- Our PostRepository, which is also a doctrine repository. We use that to search for entities.

 

Unit tests

In order to test our PostService class, we will need three different classes :

- one mock class for the repository

- one mock class for the entity manager

- our test suite

 

Mocking the repository

When writing our mock for the repository, we simply need to deal with the methods that our service will interact with, and see what possible outcome we want from our mock.

In this case, the service only uses one method from the repository : find.

Then, we have two different expected behavior we want to handle :

- an entity is returned

- null is returned

namespace App\Tests\OwnMocks;

use App\Post;
use App\PostRepository;

class MockPostRepository extends PostRepository
{
    /** @var int */
    private $expectedId;

    /** @var Post */
    private $post;

    public function __construct(Post $post, int $expectedId)
    {
        $this->post = $post;
        $this->expectedId = $expectedId;
    }

    public function find($id, $lockMode = null, $lockVersion = null)
    {
        if ($id === $this->expectedId) {
            return $this->post;
        }

        return null;
    }
}

There are probably many ways to achieve that, but this is a good example.

First, our mock needs to extend the class that we're mocking. Without this, we would get an error that our mock isn't a PostRepository, as we type hinted it in the PostService constructor.

Then, you'll notice we're injecting a post and an expectedId into our mock constructor. Then, once we call find, if the id parameter is the expected one, we return our post. Otherwise we return null.

We can then test both behavior without any real repository implementations (no database calls or complicated logic).

 

Mocking the entity manager

Now, let's have a look at the entity manager! In our PostService, you may have noticed that we actually inject the EntityManagerInterface. This means that our mock will need to implement the interface and all its methods. In this case, there is a lot of them! No problem though, we can simply leave all the ones we're not interested as empty.

namespace App\Tests\OwnMocks;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\ResultSetMapping;

class MockEntityManager implements EntityManagerInterface
{
    private $persistedObject = null;
    private $flushed = false;

    public function persist($object)
    {
        $this->persistedObject = $object;
    }

    public function flush()
    {
        $this->flushed = true;
    }

    public function isPersisted($object): bool
    {
        return $this->persistedObject === $object;
    }

    public function hasFlushed(): bool
    {
        return $this->flushed;
    }

    /** Defining all remaining EntityManager methods below */
    public function getCache() {}
    public function getConnection() {}
    public function getExpressionBuilder() {}
    public function beginTransaction() {}
    public function transactional($func) {}
    public function commit() {}
    public function rollback() {}
    public function createQuery($dql = '') {}
    public function createNamedQuery($name) {}
    public function createNativeQuery($sql, ResultSetMapping $rsm) {}
    public function createNamedNativeQuery($name) {}
    public function createQueryBuilder() {}
    public function getReference($entityName, $id) {}
    public function getPartialReference($entityName, $identifier) {}
    public function close() {}
    public function copy($entity, $deep = false) {}
    public function lock($entity, $lockMode, $lockVersion = null) {}
    public function getEventManager() {}
    public function getConfiguration() {}
    public function isOpen() {}
    public function getUnitOfWork() {}
    public function getHydrator($hydrationMode) {}
    public function newHydrator($hydrationMode) {}
    public function getProxyFactory() {}
    public function getFilters() {}
    public function isFiltersStateClean() {}
    public function hasFilters() {}
    public function find($className, $id) {}
    public function remove($object) {}
    public function merge($object) {}
    public function clear($objectName = null) {}
    public function detach($object) {}
    public function refresh($object) {}
    public function getRepository($className) {}
    public function getMetadataFactory() {}
    public function initializeObject($obj) {}
    public function contains($object) {}
    public function __call($name, $arguments) {}
    public function getClassMetadata($className) {}
}

We implement the two methods used by our service : flush and persist.

Then, as these methods don't return anything, we instead need the ability to check that they were correctly called.

To do so, I added two methods that returns boolean values : isPersisted and hasFlushed.

We then simply set variables in our flush and persist methods, and verify their values in our added boolean methods.

 

Test suite

Now that we have our mocks, let's write our actual tests!

namespace App\Tests\OwnMocks;

use App\Post;
use App\PostService;
use PHPUnit\Framework\TestCase;

class PostServiceTest extends TestCase
{
    private const EXPECTED_ID = 1;

    /** @var Post */
    private $expectedPost;

    /** @var MockPostRepository */
    private $postRepository;

    /** @var MockEntityManager */
    private $entityManager;

    /** @var PostService */
    private $service;

    public function setUp(): void
    {
        $this->expectedPost = new Post();
        $this->postRepository = new MockPostRepository($this->expectedPost, self::EXPECTED_ID);
        $this->entityManager = new MockEntityManager();
        $this->service = new PostService($this->entityManager, $this->postRepository);
    }

    public function testGetPost(): void
    {
        $post = $this->service->getPost(self::EXPECTED_ID);

        $this->assertSame($this->expectedPost, $post);
    }

    public function testGetPost_PostNotFound(): void
    {
        $this->expectException(\RuntimeException::class);

        $this->service->getPost(2);
    }

    public function testCreatePost(): void
    {
        $post = new Post();
        $this->service->createPost($post);

        $this->assertTrue($this->entityManager->isPersisted($post));
        $this->assertTrue($this->entityManager->hasFlushed());
    }
}

We create and inject our mocks via the setUp method of PHPUnit.

Then, we can test how our service methods behave using our mocks.

 

]]>
https://detassigny.net/posts/7/mocking-in-php-1-writing-your-own-mocks Sat, 02 Mar 2019 12:54:09 +0100 Gabriel de Tassigny
You need to write tests https://detassigny.net/posts/6/you-need-to-write-tests Writing unit tests at work should be one of your top priority! In my first ever programming job, I remember hearing about unit tests a lot, but I simply didn't get the importance of them : "Why do I need to waste time writing extra code to test my own code? I know how my code works!!"

It felt completely useless and also extremely boring. But boy, was I wrong! A few years later I progressively realised that unit tests are necessary in having a stable and ever-evolving professional code base.

 

"Any code that isn't covered by unit tests is legacy code"

That's a bold statement, isn't it? I remember hearing it at a tech conference a while ago. For those who may not know, legacy code is basically code that we judge very hard to maintain and change, or even understand. Every tech company has it, to some extend. They're often due to change of mind, emergencies that we didn't clean later, or general bad maintainance of the code base.

But surely you would say, if I write some very clean code right now, it's not legacy code! Even without unit test, right?

Well, actually it is... or more exactly, it will be!

Because, let's say that you write a brand new shiny class and its purpose is very clear... What makes you think that Bob the new software engineer in 5 years will understand it? Especially if you're not around anymore? And what if in those 5 years a lot of bug fixes, edge cases, and extra methods were added in your class? Well, you have it! Congratulations, you created legacy code! Sure, it wasn't ugly at the start, but it became so in the long run!

 

Understanding the purpose of tests

One problem is that junior developers tend to not understand the actual purpose for unit tests. That was my mistake too back in the days.

It's not really about testing right away that your new code works (although it can help you achieve that!). It's about writing a contract on how your code is supposed to behave and what's expected of it. By defining all the expected outcomes of your class / method / function, you simply show what the intent of your code is.

One of the main issue with software engineering is of time : code bases evolve and go through several teams of developers all with different ideas and new tech trends they want to try out. The code gets old, messy, and hard to understand.

Therefore, defining a contract that tells future developers what each part of the code was intended to do is fundamental.

It means that :

- new features added in the code can be done with more confidence as tests might break if bugs are introduced

- refactoring can be done more easily for the same reason

- unit tests can be read to give some context on what to expect (in case the production code isn't clear enough)

 

]]>
https://detassigny.net/posts/6/you-need-to-write-tests Thu, 10 Jan 2019 23:59:33 +0100 Gabriel de Tassigny
I gave up on Android https://detassigny.net/posts/5/i-gave-up-on-android I had been using Google's mobile OS for a while, but now it's time to say goodbye... This is the story of why I used Android phones, and why I recently switched to iOS. Therefore, I will talk about both Google and Apple since they're the only two real options on this market.

Let's be clear, I always enjoyed Apple products. However, they tend to be a bit pricey.

While I'm okay in buying an expensive computer as I tend to use them for work related stuff, I find it harder to justify spending around €1,000 for a phone. Therefore, I used to mostly look at mid-range android phones (from €300 to €500). In theory, they fit my need of a lower price phone that does everything I need well enough. I always found iOS to be the better operating system, however android was good enough for me as I could save €500!

But I give up on that now for multiple reasons... Please note that some of these reasons might not be an issue on very expensive android phones, but as I said, I honestly prefer iOS for a similar price.

Anyway, let's go into details on why I gave up on Android!

 

Google

 

Google Data Monster

Oh, Google... There would be so much to say about this company, but I'm going to be brief. Let's just say that over the years I've tend to lose respect for Google more and more.

This is of course mostly related to the privacy issues. Overall, I feel that I really can't trust this company with my data anymore.

Just have a look over this wikipedia page.

Apple tends to respect more its users so I'm glad to join them on that aspect.

I had a look many times at setting up somehow a Googleless Android, but roms are complicated to install, and not always well maintained depending on your device. Also, some android apps and services may still requires you sign-in using a Google account.

 

A dying phone

 

Moto X play

This is my (now former) android phone: A Motorola Moto X Play.

When I bought it two and a half years ago, it was at a decent price, had some of the best online reviews, and was powerful enough for my needs.

I was really happy with it... for about a year and a half. Then everything progressively started to fall apart!

First and foremost, my micro USB port was getting worse and worse. I had to do this trick I found online of using a sharp stick to replace it properly almost every week so that I can somehow manage to charge my phone. In the last few months, it sometimes took me several minutes for me to manage to find the sweet spot where my phone would accept to charge. And then I had to make sure my phone wouldn't move at all, else I would start over again. And some micro usb cables simply wouldn't work at all anymore! So I sometimes couldn't charge my phone in my friends' house. Extremely annoying!

Speaking of battery, my phone would also randomly shut down saying the battery level was at zero even though I had plenty left. It would then be able to turn back on, so there definitely was some battery left. This would mostly happen when using resource heavy applications (the camera most often triggered it, but Google Maps would do it too sometimes). I like traveling a lot so having my phone shutdown when I'm trying to take pictures in the middle of Kyoto or Seoul was very painful.

Another issue I had was that my flashlight completely stopped working 4 months ago, after an OS update. Thanks for the update Google!

One other time, around 6 months ago, I tried to migrate data from the internal memory towards the micro SD card. I used the system tool that is part of Android for that, so it should be all ok, right? Haha, well no. Actually it failed somehow, but more importantly it managed to make the android back button stop working completely. If you have an android phone, I challenge you to try using yours for an hour without that button. After hours of attempts and online research, I managed to fix it by installing a completely different Launcher... What the hell, Android!

 

Alternatives?

So after all this, I gave up. Sorry Google! It's not me, it's definitely you! You and your lack of respect for my online privacy. You and your OS that seems to mostly work but that gave me so many headaches!

Ultimately, I started to look at alternatives, and let's be honest there is a big lack of alternatives!

There is only one real one in Apple's iOS. I bought an iPhone XR and I like it so far. However, I wish there was some true open source alternative. Basically, what Linux is for computers. Hopefully this will happen some day, but I doubt it...

]]>
https://detassigny.net/posts/5/i-gave-up-on-android Mon, 24 Dec 2018 15:46:33 +0100 Gabriel de Tassigny
Design Pattern #2: Dependency Injection https://detassigny.net/posts/4/design-pattern-2-dependency-injection A very useful pattern to keep your application clean and enable unit testing In the previous design pattern article, I went over the Value Object pattern.

This time I will talk about how and why you should use dependency injection. Personally, this may be the design pattern that I use the most, and it's generally very common so if you don't know it, I strongly encourage you to learn about it!

I'm personally a bit annoyed about articles that uses cats and dogs, or wheels and cars as examples for this kind of stuff. It doesn't reflect what people usually work on. Therefore, I will instead use real life examples, mostly taken from this blog's source code.

What's dependency injection and how do I use it?

Let's say you have a class, and that class has some dependencies on other classes.

In our case, I have a service class to retrieve a blog post (such as the one you're reading right now) for a given ID, and its dependency is a doctrine repository that is in charge of connecting to the database and retrieve that post.

Well, one naive way to have your main class using your dependencies might be to declare its dependency inside it.

Like this :

class PostViewingService
{
    /** @var PostRepository */
    private $repository;

    public function __construct()
    {
        // Create doctrine entity manager, and then get the repository from it
        $config = Setup::createAnnotationMetadataConfiguration([__DIR__ . '/Entity']);
        $em = EntityManager::create(['driver => 'pdo_mysql', 'user' => 'user'], $config);
        $this->repository = $em->getRepository(Post::class);
    }

    public function getPost(int $id): Post
    {
        /** @var Post $post */
        $post = $this->repository->find($id);

        if (!$post) {
            throw new PostNotFoundException("Post with ID {$id} was not found");
        }
        return $post;
    }
}

class PostRepository extends EntityRepository
{
}

That would work! You would be able to use your service, and it definitely has an instance of the repository created in its constructor. However, the constructor is now polluted with all the logic of how to create the repository.

This is how it would look instead using dependency injection :

class PostViewingService
{
    /** @var PostRepository */
    private $repository;

    public function __construct(PostRepository $postRepository)
    {
        $this->repository = $postRepository;
    }

    public function getPost(int $id): Post
    {
        /** @var Post $post */
        $post = $this->repository->find($id);

        if (!$post) {
            throw new PostNotFoundException("Post with ID {$id} was not found");
        }
        return $post;
    }
}

class PostRepository extends EntityRepository
{
}

Isn't that cleaner? Now, of course you'll still need to create the repository somewhere beforehand to pass it into the service.

However, it makes your code way easier to read. And there are more advantages than just code readability too...

Why should I use this?

Centralize your instantiations

One reason you may want to use dependency injection is to have your instantiations written in one place only. Using our previous example, what would happen if I added another service that needs the PostRepository?

If the repository was instantiated in the services constructor as we did first, the new service would need to do the same! It means we would duplicate that ugly code to retrieve the repository from the doctrine entity manager.

However, using dependency injection, we can simply pass the same instance of the repository to both services, and avoid having duplicated code.

Having no duplication of that code means that if we ever need to change how that repository is created, we can change it in one place only.

Now, if you don't know how to handle these instantiations, I suggest having a look at containers, such as this one.

Unit testing

Another huge advantage to dependency injection is that it allows us to unit test our code easily.

Indeed, if you wanted to test the behaviour of the getPost method on our service, you would need to have a database setup for the test, and therefore you would test both the service and its dependency (the repository). While this isn't necessarily a bad idea, it can be quite difficult and slow. Furthermore, it would be closer to an integration test than a unit test.

Instead, dependency injection allows us to use Mocks.

Here is how tests could look like using PHPUnit and Phake as a mocking library :

class PostViewingServiceTest extends TestCase
{
    /** @var PostViewingService */
    private $service;

    /** @var PostRepository */
    private $repository;

    public function setUp()
    {
        $this->repository = Phake::mock(PostRepository::class);
        $this->service = new PostViewingService($this->repository);
    }

    public function testGetPost_NotFound(): void
    {
        $this->expectException(PostNotFoundException::class);

        Phake::when($this->repository)->find(self::POST_ID)->thenReturn(null);

        $this->service->getPost(1);
    }

    public function testGetPost(): void
    {
         $post = new Post();
         Phake::when($this->repository)->find(self::POST_ID)->thenReturn($post);

        $result = $this->service->getPost(1);

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

Here we create a mock of the repository and inject it into our service. This means we don't need any database at all!

We can then define the mocks behaviour in our two test scenarios :

- if the repository returns null, the service method should throw an exception

- if the repository returns a Post entity, the service method should return it

If you're not too familiar with unit tests and mocks, I strongly suggest having a look at them as they're very big parts of software engineering.

]]>
https://detassigny.net/posts/4/design-pattern-2-dependency-injection Thu, 06 Dec 2018 07:32:07 +0100 Gabriel de Tassigny
Managing my passwords with KeePass and OwnCloud https://detassigny.net/posts/3/managing-my-passwords-with-keepass-and-owncloud I had been trying to find the perfect setup for managing my passwords for a while, and I think I'm getting close. If you don't really trust online password managers like me, you might also want to manage your passwords offline.

Enters KeePass!

 

KeePass / KeePassX / KeePassXC

KeePass logoKeePassX logo       KeePassXC

To sum it up, KeePass was originally an open-source offline password manager on windows. It basically created its own format for storing your database file of credentials, and you set up a master password to access the database using the software.

It also allows you to generate random passwords.

KeePassX was then created as an attempt to have a linux version of it. (Although I think that nowadays both KeePass and KeePassX are actually cross-platform applications).

After a while, a big part of the keepass community decided to fork KeePassX and created KeePassXC (for slow development reasons on the former, apparently).

KeePassXC also has a way nicer UI / UX than it's predecessor in my opinion. Furthermore, it runs on Mac OS / Linux / Windows.

The concept is the same : you have a local encrypted database file containing all your passwords and can access them using a master password.

I've been using KeePassXC for a while now on my macbook, and I have to admit that I can't complain about anything. It's a great application!

 

What about smartphones?

Well, I personally own an Android phone (although I'm probably going to switch to iOS soon, but more on that in another post later...)

I am using an application called KeePass2Android. There are others, but that's the one I preferred.

It also uses a local file to store your password.

 

Keep it in sync

Now, you're probably wondering : how do I keep the 2 databases (computer and phone) in sync?

Well, there are multiple solutions for that : Dropbox, Google Drive, BT Sync (now renamed resilio sync)...

I personally used a private owncloud server that I have an access to, but other options can be more straightforward!

Usually, KeePass applications can have two ways of accessing that data :

- they can support directly your specific cloud storage

- they can read from a local file which means you'll have to have another application in charge of syncing to your cloud

I went with the latter simply because my keepass applications didn't support OwnCloud! In any case, once I installed OwnCloud on mac and android and configured them I never had to open them again so it's not so bad.

 

Browser completion

I started looking at browser auto-completion recently and for now I'm using KeePass Tusk (available on Chrome and Firefox).

The big drawback I have with it is that the only way for it to access my database in owncloud is through a publicly available link there, which isn't great. I wish it could either read from the local file on my computer, or connect to owncloud directly.

In practice, it means I wouldn't need to expose the database through an URL. That database is password protected and good luck finding the link, but still, it's not ideal in my opinion!

 

Conclusion

Obviously this is my personal setup and it's not for everyone. Each of the tools I mentioned have some alternatives too! KeePass isn't the only player in the game (I heard pass is very good too).

However, I hope it proves that you can really store and access your passwords the way you want! You shouldn't use a tool you don't feel comfortable keeping your credentials.

 

 

 

]]>
https://detassigny.net/posts/3/managing-my-passwords-with-keepass-and-owncloud Mon, 03 Dec 2018 10:06:19 +0100 Gabriel de Tassigny
Going Frameworkless https://detassigny.net/posts/2/going-frameworkless Why I think everyone should try web developing without a framework About a year ago, I decided that I wanted to start my own tech blog at some point.

But that started in my head a long internal debate : What should I use to write my blog? Should I follow today's trend and use medium.com? Should I self-host a Wordpress blog?

After some thinking, I also realised that I didn't have any side project to work on at the moment, so I might as well write my own blog!

Then came the decision of which languages / frameworks to use? Ruby On Rails? PHP with Symfony? Laravel? Some new trendy language?

After some more thinking, I remembered a PHP meetup I went to in Dublin, where one of the member talked about writing a PHP application without any framework. That's it! Why not write my own blog in PHP 7, but no framework?

Of all the above options, I probably chose the longest to implement...

But in the end, I don't regret it at all!

This is my story of "going frameworkless" and why I think every PHP developer (and perhaps other devs too?) should try it at least once.

 

Composer packages

First of all, I didn't exactly write everything from scratch... Sure, that would be an option as well but I'm not that masochist!

Instead, I used a few composer packages to handle specific tasks that I didn't want to implement myself :

- Doctrine was used for managing entities and DB persistency

- Twig for frontend

- FastRoute for request routing

- phpdotenv for managing env variables

... and a few other ones!

In the end, I spent a good amount of time just writing the glue between these various packages that I chose.

 

What to write vs what to borrow

I think the general advice I would give is to write what you want to write yourself, and use a package for anything else you don't really feel like implementing.

For instance, I wrote my own container to manage my dependencies. I could have used an existing package for that, but I felt interested in writing my own implementation of the PSR-11 Container Interface. My implementation is probably worse than most packages, but I'm still proud of it anyway! And believe it or not, I had a lot of fun writing it!

But if for some reasons you're wondering how you would go at writing your own DB persistency layer, then go ahead! You'll definitely learn a lot!

That's the first and probably the biggest reason I would advise in going frameworkless : You'll have the opportunity to write code you would never write otherwise.

 

Performance

One other reason you might want to avoid using a framework could be performance. I really haven't looked at that too much when writing my blog to be honest, and probably I could spend some time optimising it.

However, you do end up with mostly code that you wrote yourself, or at least specific packages that you cherry picked. It means you know what to expect and you don't have a big overhead that a whole framework could introduce.

 

Writing your own framework

Did you ever think about writing a framework yourself?

If you decide to go frameworkless, ask yourself this question in the end : Did you actually end up writing your own one?

You might actually really like the way you glued all the pieces necessary for your application/blog/website, why not try to make it a separate framework?

I haven't gone that far yet, and probably never will... but it's definitely the only time I've at least considered it. The code I write definitely has some pieces that looks shaped like the beginning of a framework.

I've met developers who attempted to write their own framework before. I truly believe that would be the best way to do so. You need a pet project to determine how your framework would look like!

 

What I've learned

Just to be clear : I really like frameworks! They let you write projects with all the scaffolding already in place and good ones are usually well documented too. I'm not saying you should stop using them completely.

However, the learning experience I've had really makes me think that you should try once not using one!

It gave me the chance to write a lot of PHP code, to discover specific packages for specific tasks (e.g. routing is usually included in frameworks so I never had the chance to discover fast-route before), and also to simply have fun!

I don't think I would have enjoyed as much creating a medium account, or installing wordpress. Developing a blog in Laravel would have been okay, but a blog isn't that complicated so that would have been done quite quickly.

Instead, I spent some time thinking on how to implement specific parts of the system, how to have a container that behaves the way I would expect, how to handle errors, etc.

That would be my final reason for going frameworkless on a side project : Have you ever had a moment where you wanted to work on some programming side project but didn't have any new exciting idea? Well, maybe that could be the one! Just write a simple site or application but without any framework! I guarantee you will have some challenges and some fun!

If you're interested in having a look at the source code of this blog, feel free.

]]>
https://detassigny.net/posts/2/going-frameworkless Sun, 02 Dec 2018 04:12:37 +0100 Gabriel de Tassigny
Design Pattern #1: Value Object https://detassigny.net/posts/1/design-pattern-1-value-object Learn how and why to use this simple yet very effective design pattern! I named this article "Design Pattern #1" because I think it would be cool to write more of these in the future, but only time will tell if I actually commit to it...

In this article I will try to explain how the value object design pattern works and more importantly how you can use it!

First of all, I think this is a very nice pattern because it's equally simple to use and can be very powerful in keeping your code clean.

Why do I need this?

I don't know about you, but one thing that annoys me about some design patterns is that you're never sure if you can actually use them in your day to day programming life! What's the point of learning them if you don't use them in the end?

Well, the good thing is that the value object design pattern is very easy to use and can be used in many situations!

Let's start with an example: Let's say your program contains an email address. You may want to make sure in various part of your system that a specific variable is actually an email address. You'll then have one of this at multiple places in your code :

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    throw new Exception('Houston we have a problem!');
}

  And that will work, but having it everywhere is a bit... annoying, no?

Now you may tell me "but I can put that in a function somewhere and call it everywhere I want!".

Sure, that will work, you could do this : 

function ensureIsEmail($email)
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new Exception('Invalid email: ' . $email);
    }
}

public function functionA($email)
{
    ensureIsEmail($email);
    functionB($email);        
}

public function functionB($email)
{
    ensureIsEmail($email);
    // Do something else with $email
}

if (filter_var($email, FILTER_VALIDATE_EMAIL) !== false) {
    functionA($email);
}

See the problem? Everywhere you passes $email, you need to make sure it's still a valid email. Or you could try to remember if it's been checked before depending on context, but that could become very painful to track in a large system...

But what if instead you had a specific class that encapsulated your $email value? What if the value being in that class meant it was already validated? 

You know where I'm going with this, value object is the answer! If you had such a class, you could do this:

public function functionA(EmailAddress $email)
{
    functionB($email);        
}

public function functionB(EmailAddress $email)
{
    // Do something else with $email
}

try {
  $email = new EmailAddress('myemail@example.com');
catch (Exception $e) {
  // Handle error here
}

functionA($email);

No more checking that the email address is valid! ...Well, not exactly, you still need to do it the first time you instantiate the value object, which means we'll check the value of the variable in the constructor. Let's go over that now.

 

How can I write a value object class?

The rules of a value object are simple : 

- all verification is done in the constructor

- if the value passed in the constructor is not valid, throw an exception

- the value object is immutable (otherwise we could change the value to a non valid one, and that would defeat its purpose)

- there should be a getter of some sort to access the value

Here is how our email address could look like : 

class EmailAddress
{
    private $value;

    public function __construct(string $value)
    {
        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Invalid email: ' . $email);
        }
        $this->value = $value;
    }

    public function getValue(): string
    {
        return $this->value;
    }
}

Now, you can simply instantiate it the first time, catch the exception in case the value isn't valid, and if it is valid you can pass the object anywhere in your system and expect it to stay valid.

How I can use my new shiny value object?

Now, let's have a more practical example on how to use it : Let's say you have an endpoint that sends a password reset email to a user. It means we'll have a controller that reads the parameter, and a service that sends the email.

Obviously I'll emit a lot of code and leave only the parts that we're interested in.

Our controller could look like this :

class PasswordResetController
{
    private $service;

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

    public function sendPasswordResetEmail(string $emailParam)
    {
        try {
            $emailAddress = new EmailAddress($emailParam);
        } catch (InvalidArgumentException $e) {
            // Handle error somehow (display an error page, throw an exception...)
            throw new Exception('Invalid parameter ' . $emailParam);
        }
        $this->service->sendEmail($emailAddress);
    }
}

We can use the EmailAddress value object to verify the formatting of the parameter. Once it is done, we know the rest of the code will have a correctly formatted email address.

In case the email is not valid, we can handle the exception on the controller level and deal with it accordingly.

Now let's have a look at the service called by the controller :

class PasswordResetService
{
    public function sendEmail(EmailAddress $emailAddress)
    {
        mail($emailAddress->getValue(), 'Password reset', 'Your link to your new password is...');
    }
}

This is obviously an overly simple service but you get the idea : the service expects a value object and therefore doesn't need to validate its format. It can then call the getValue method to retrieve its value.

]]>
https://detassigny.net/posts/1/design-pattern-1-value-object Thu, 29 Nov 2018 05:53:07 +0100 Gabriel de Tassigny