Expressive Code & Real Time Facades

Recently, I worked on some code that surfaced my most common use-case for Laravel 5.4’s “real-time” facades. If you’re not familiar with this feature, it allows you to use any of your application’s classes as a Laravel “facade” on-demand by prefixingFacades to the namespace when importing the class. This is not a feature that is littered throughout my code, but I find it occasionally provides a clean, testable approach to writing expressive object APIs.

I’ll use Laravel Forge terminology to illustrate an example. When using Forge, you can link your server provider accounts to your Forge account. A server provider is an infrastructure provider such as DigitalOcean, Linode, or AWS. These are the providers that host the actual servers managed by Forge. So, imagine our application has an Eloquent model named Provider. The Provider model has a type column that indicates which type of server provider it represents (DigitalOcean, Linode, etc.):

Of course, Forge needs to actually be able to create servers on these providers. I typically encapsulate all of my external API calls in classes that reside in an App\Services directory. So, imagine we have a “service” class for each provider. For example, A DigitalOcean service might look something like this:

Next, we need to be able to resolve the service class for a given provider based on the model’s type column. We can make a simple factory to generate services from providers:

Now, there are multiple ways we could tie these things together in order to create a server. Let’s assume we’re going to consume this code from a controller. We could inject the factory into the controller and consume it like so:

However, I don’t really like this approach as it’s a little cumbersome to have to inject a factory instance into every class that utilizes the provider service. Ideally, I would like to have syntax like the following:

In the example above, we simply call the service method on the Provider instance in order to access that provider’s service. In fact, I find this is the natural way people tend to think about code when they have a new idea, but they just aren’t sure how to get there and still maintain testability. So, what are some ways can we implement this? Without using real-time facades, we might implement it like so:

However, the problem with this approach is, since the factory is instantiated directly in the method, it is impossible to mock calls to the external service. Since I don’t want to create servers on DigitalOcean every time I run my tests, I will definitely need to be able to mock these calls. So, let’s use real-time facades to make it testable:

Now, not only do we have a simple, expressive way to access a provider’s external service provider, our code is dead simple to test using facade’s built-in access to Mockery:

I find real-time facades most useful for building clean object APIs such as this one without sacrificing testability. Hopefully this gives you some fresh ideas for your own applications! Enjoy!

Show your support

Clapping shows how much you appreciated Taylor Otwell’s story.