If Facades Ruled The World

Christopher Pitt
5 min readMay 1, 2014

--

After the recent drama about TDD, and some less-recent drama about Laravel daring to use the name Facade for anything GoF have not personally approved, I got to thinking about a utopian state where everyone is happy and gets on with the job at hand.

Edit:

The first version of this article had a slightly skewed example of routing in Aura. I have swapped this out for a fairer comparison.

Disclaimers

This is not about Laravel. I mention it, but the ideas have little to do with Laravel. I will save this post in the Laravel 4 category (on Medium) because that will get it in front of more eyeballs.

This is academic. I am interested in the discussion it generates. It’s not flame-bait. Calm yourself in preparation!

What Do I Mean By Facade?!

It’s probably going to be useful for me to explain what I mean when I call something a facade. From the great repository of irrefutable knowledge. I pulled the definition: “A facade is an object that provides a simplified interface to a larger body of code”.

Uncle Bob refers to the Facade as “imposing policy from above”, which is to say; a class which provides conventional, easy to use, access to some underlying thing that’s bigger and/or more complicated.

Laravel has a set of facades which provide similar functionality. They look like static classes but they’re really just intermediary classes to more traditional class structures.

Instead of doing something like this:

$environment = new Illuminate\View\Environment(...);
$view = $environment->make("path/to/view", $data);

…you can do something like this:

$view = View::make("path/to/view", $data);

It does this with a neat combination of PHP magic methods and a magical Inversion of Control container. So technically it might be better to call them something else, but few people actually care enough to make noise about it. The rest seem to have other things that need doing.

When I talk about facades, I’m leaning towards how Laravel uses the term. I’m not saying they are technically Facade. I’m not saying I care enough to make noise about it either. I guess I want to talk about the idea underpinning the design pattern, and the outcome may look something like Laravel code, but it’s not really.

Why Are Static Classes Bad?

There may be a number of reasons why using them is bad, but I’m going to focus on one. Static classes are hard to swap. Consider the following example:

class Logger
{
public function log($message) {
Filesystem::write("path/to/log/file", $message);
}
}

Say we wanted to test the log() method. How could we do it but by calling the write() method on the Filesystem class? There is an explicit coupling between the Logger class and the Filesystem class.

You could use AspectMock. If you were brave.

If you are using injected dependencies, testing would be a simple case of mocking the Filesystem class and giving that to the Logger class instead of the real Filesystem class. You could do something like this:

class Logger
{
protected $filesystem;

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

public function log($message)
{
$this->filesystem->write("path/to/log/file", $message);
}
}

…and to test this, you could do something like:

class LoggerTest
extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
Mockery::close();
}

/** @test */
public function it_should_write_to_the_filesystem()
{
$mock = Mockery::mock("Filesystem");

$mock
->shouldReceive("write")
->atLeast()->once()
->with("/path/to/log/file", "the message");

$logger = new Logger($mock);

$logger->log("the message");
}
}

Why Are Static Classes Good?

Despite the reasonable proliferation of best practises to the contrary, many would agree that the use of “static” classes make code more readable.

They mean the difference between:

public function modifyWebRouter(Container $di)
{
$router = $di->get("web_router");
$router->add("hello", "/")
->setValues(["controller" => "hello"]);
}

…and:

Route::any("/", "HomeController@index");

These are doing essentially the same, yet the Laravel code is vastly easier to write and read than the corresponding Aura code.

I am a huge supporter of both Aura and Laravel. I prefer Laravel for most of my projects because it’s simply faster for me to develop with. Please don’t misunderstand this as an attempt to promote one at the expense of the other.

This is not to say that Laravel magically avoids the need for bootstrapping the router. It’s just that the entry-point into defining routes (in Laravel) is by use of the Route facade. The only expressed way of “doing” routing, in Aura, is the code I have there.

The Aura team has chosen to eschew any form of the Facade. Should (F|f)acades be kept for frameworks and applications? There’s merit to that argument. But young developers are presented with Aura (the framework) and Laravel. Which do you think will be easier for them. Which do you think is cleaner just for anybody’s application code?

If the idea behind the Facade pattern is to make things quicker and easier by adding a layer of specificity, static classes are the ultimate expression. What can be more specific than User::findOrFail($id)?

A Middle Ground

What if we were to use the following “pattern” of development:

class PosixFilesystem
implements FilesystemInterface
{
// ...do posix filesystem stuff
}

class Filesystem
{
private static $filesystem;

public static function setImplementation(
FilesystemInterface $filesystem
)
{
static::$filesystem = $filesystem;
}

public static function __callStatic($method, $arguments)
{
static::throwUnlessImplementationSet();

$callable = [static::$filesystem, $method];

return call_user_func_array($callable, $arguments);
}

private static function throwUnlessImplementationSet()
{
if (!static::isValidImplementation()) {
throw new LogicException(
"filesystem implementation not set"
);
}
}

private static function isValidImplementation()
{
return static::$filesystem instanceof FilesystemInterface;
}
}

Filesystem::setImplementation(new PosixFilesystem());

The calling code then goes back to:

class Logger
{
public function log($message)
{
Filesystem::write("/path/to/log/file", $message);
}
}

…and to test, we do:

class LoggerTest
extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
Mockery::close();
}

/** @test */
public function it_should_write_to_the_filesystem()
{
$mock = Mockery::mock("FilesystemInterface");

$mock
->shouldReceive("write")
->atLeast()->once()
->with("/path/to/log/file", "the message");

Filesystem::setImplementation($mock);

$logger = new Logger();

$logger->log("the message");
}
}

So now we’re using a static class, which proxies all calls to a traditional (non-static) class, and is swappable when we need to test. This is not much different from the approach Laravel takes, yet it’s an idea that works outside of the Laravel eco-system.

It takes accepting that the explicit coupling is to thin (facade) classes which also form part of your system, for the sake of clean code. Instead of depending on interface-based dependency injection, at a controller level, you’re depending on it at a facade level.

Is this a best-practice approach? No. Might it help to make your code easier to read/maintain? Probably. Does it get in the way of testing? No. Should you do it?

Edit:

Should you do it? Probably not.

--

--