Remove the Magic with Functional PHP - Part I

This is part one of a three part post based on a presentation I plan to give at some meetups or conferences this year. The slides for this presentation can be seen here: http://slides.com/davidcorona/remove-magic-functional-php/live

QUICK NOTE: This presentation and blog post series was inspired by the keynote called "8 lines of Code" that was given by Greg Young at QCon London in 2013. http://www.infoq.com/presentations/8-lines-code-refactoring. It’s a good one. Check if out when you get a chance.

I also really like this post as well. http://www.kenneth-truyers.net/2014/02/20/simplicity-in-software-what-you-see-is-not-what-you-get/. It's got some other nice thoughts on simplicity. Some of which I took inspiration from for my presentation.


Magic. Everyone likes magic. I like magic, you like magic, we all like magic. So why am I telling you to get rid of it? Where’s the fun in that? Magic is fun, just not when it comes to writing software. In this post, I am going to be talking about magic in programming. Why it's bad, and how we can reduce the amount of magic we put into our code.

All our applications are full of magic

As programmers today, we have access to more tools than ever. While that’s a great thing, we need to be careful about which tools we choose to use in our applications. Magic is always there lurking in the shadows trying to obfuscate your code with all kinds of tricks like reflection and magic methods. We have to constantly be on our toes to keep it at bay. Maybe that is an obvious concept, but one that cannot be stressed enough.

How do we fight the magic?

By leveling up our magic resistance, of course! We have to learn how to write our software in a way that does not need all kinds of magical items. Luckily, we have two weapons at our disposal to help us in this fight.

Simplicity (+10 MR)

Our first weapon of choice. Simplicity. This should be our ultimate goal when writing software. Simplicity will help us and the next person to more easily understand our code. How do we achieve simplicity? Well, we have to write more code. Luckily, this won't be an issue.

Typing is not the bottleneck - Michael Hill

I like this line. I read it a few months ago and it really stuck with me. I’m not sure who to attribute it to, but I think it’s this guy. When we are writing code, we are only typing code maybe 1/10th of the time. We read a lot more code than we actually write. I don’t know have any numbers, but let’s just say it’s a lot more. The bottleneck isn’t typing. Making things more simple sometimes involves typing more code, but don’t worry, this won’t slow us down. Let’s take a look at a few examples of things that are magical and might create complexity.

Convention over configuration

This is a good one. Convention over configuration. It sounds so nice when you say it right? It just rolls off the tongue. Convention over Configuration.

This is bait. Its an evil succubus who wants to lure you in, and when you are not looking puts all kinds of magic into your program. It’s very tempting. Who wants to write long configuration files or setup code? Instead just do this thing a certain way and magical things will happen. When you are ramping up someone in your project, what do you tell them when they need to add a new feature to your app? “Oh, thats easy! Just add this file here and name it like this. Then add a function with this name and this comment attribute and boom it works! Pretty sweet huh?”

No, thats not sweet. Why does that work? How was I supposed to know that I needed to do that? Ok, I did all of that and it’s still not working. Now what? “uhhh. hmmm. I’m not sure about that one, it should just work.” “It should just work”. The 4 words most commonly used when the magic stops working. What are we supposed to do when the magic stops working? I don’t know. That’s what magic is. We don’t know how it works. It’s magic. How am I supposed to debug something like this when it’s running through 1000s of lines of framework code just to call the one function I just wrote? You got me. I think I’ll go back to writing my setup and configuration code.

ORMs

They are pretty common these days. Almost every large framework has some type of ORM built-in. They sure do make your life easier... until they don’t.

How many times have you found yourself writing a sql query manually because your ORM was being dumb? It was probably a lot easier and quicker too.

Here is a common query you might write using your ORM. It is finding all accounts in order whose name is Bob Sacameno, is not deleted and has other matching IDs. Nothing too complicated.

$results = $accounts
    ->where("first_name = 'Bob'")
    ->andWhere("last_name = 'Sacameno'")
    ->andWhere('deleted IS NULL')
    ->andWhere('ref_id = 2')
    ->not()->andWhere('other_id = 3')
    ->orderByDesc('created')
    ->limit(10)
    ->getResults();

Here is the same query if you would have written manually. You might be using something like PDO, but you get the idea.

$results = mysql_query("SELECT * FROM accounts
    WHERE first_name = 'bob' AND last_name = 'Sacameno'
    AND deleted IS NULL AND ref_id = 2 AND other_id <> 3
    ORDER BY created DESC LIMIT 10");

I tell you what, it was a lot easier for me to write the second one. I didn’t have to import a large library, and read through the docs to figure out how to write a SQL query.

Now imagine you wrote this query, but for some strange reason it’s not working quite right. I mean it looks pretty straight forward. "It should just work" right? Which one would you rather debug? Have you ever seen the queries that ORMs can spit out? Yikes!

Dependency Injection

Dependency Injection is also pretty common. Any application of a certain size is probably using some type of dependency injection. You may be using it for testing to inject mock and stubs. They sure make managing your dependencies easier... until they don’t. Usually you declare all of your dependencies up front in a config file or class.

$container->bind('iFooContext', '\Foo\Context');
$container->bind('iBarController', '\Controllers\BarController');

This is actually quite nice, because we are explicitly defining what our dependencies are and how to resolve them. When I use DI frameworks, I stick to these explicit definitions. You might be using constructor injection which does some auto-injection of dependencies based on what objects your constructor needs. Probably using reflection or some other magical incantations. Now, what happens when a dependency is not getting injected properly? How do you figure out where the magic stopped working? Maybe you just push some code around and hope it works, or you ask the Google and hope someone else is having the same problem. Imagine if we could just inject all of our dependencies ourselves instead of relying on a framework to do it for us? That would be pretty sweet eh?

Automappers

Here is another good one. Automapper is a pretty popular library in the .net world. I have used it several times myself. Until I realized I didn’t need it. What this thing does is it takes a data model from your database and it maps it onto your business logic model. The idea is sound. You don’t want to be writing your business logic directly against the database schema, because database schemas tend to change over time. So, you need a way to map fields back and forth between these two models. Say you have an account model class:

class Account {
    public $id, $name, $email;
}

These mapping libraries love to use convention over configuration to map your data, so you can just map it like this.

$account = Mapper::map('Account', $databaseAccount);

Seems simple enough. I only needed to write one line of code. These libraries will use some reflection magic to figure out which fields should get mapped to what, but it can’t figure out everything. What if we need to define some custom mappings? We have to start writing code like this:

Mapper::createMap('Account')->forMember('name', function($a) {
return $a['first_name'] . ' ' . $a['last_name'];
});
Mapper::createMap('Account')->forMember('email', function($a) {
return strtolower($a['email']);
});

Whew. Yikes. The simplicity starts to break down pretty quickly. If we were doing it manually, we might add a function like this to our account model class:

public function map($account) {
    $this->id = $account->id;
    $this->name = $account->first_name . ' ' . $account->last_name;
    $this->email = strtolower($account->email);
}

Then call it like this:

$account->map($databaseAccount);

Thats pretty simple too. We just wrote a function on our model that can map a data object. Then we called it. We had to write a little extra code though. Luckily that didn’t slow us down. We didn’t have to read through pages of documentation to figure out how to map our data model. Now, what happens when your data model isn’t getting mapped properly? A field keeps getting left out or it’s not getting mapped properly. Which one would you rather debug?


These tools have something in common. They help us write less code, but they are not reducing our codebase. We are not reducing 20 lines of code down to 2 lines by using that mapping library. We are increasing that 20 lines of code to 1000+ lines. As soon as you bring that library into your project, it becomes your code. You are responsible for it. Your manager or customer is not going to care that there is a bug in your ORM. They are not going to understand that the bug was fixed, but you can’t use it yet because the next version hasn’t been released.

So, how can we write our programs in another way so we don't need to rely on so many of these tools? Well, in the next post, we will look to our second weapon in this fight against magic. Functional Programming.