Jeremy Bush's Tech Dump

A dump of my tech ramblings. May or may not be useful to you.

Well-designed-application-architectures-part-3

Last time we talked about how your business logic should look. It was a high level overview of the architecture. This time we’ll actually put that into practice and write some code. We’ll be using BDD (Behavior-Driven-Development) to design the application.

We’re going to be using Behat to run these features. So let’s start a new project!

mkdir sample-app; cd sample-app
git init

We’ll use composer to install Behat:

composer.json
1
2
3
4
5
6
7
8
{
  "require": {
    "behat/behat": "2.4.*@stable"
  },
  "config": {
    "bin-dir": "bin/"
  }
}

And let’s install it:

1
2
3
4
curl http://getcomposer.org/installer | php
php composer.phar install --prefer-source

bin/behat --init

So where do we start? BDD says we should start from the outside and move our way in. So, we’ll start with some Gherkin. I’ll make up some requirements that you might receive from a product manager:

features/register_account.feature
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Feature: User Registration

  Scenario: User Registers With Valid Data
    Given I am an unregistered user
    When I register with the following information:
      | first_name | foo         |
      | last_name  | bar         |
      | email      | foo@bar.com |
      | password   | foobar      |
    Then I should be registered
    And I should receive a welcome registration email

  Scenario: User Registers With Invalid Data
    Given I am an unregistered user
    When I register with the following information:
      | first_name | foo         |
      | last_name  | bar         |
      | email      | foo@bar.com |
      | password   |             |
    Then I should not be registered
    And I should see the following errors:
    """
    password is required
    """

Now let’s run it:

1
bin/behat

You’ll see a bunch of undefined steps with some snippet code. Let’s paste these into our context file (features/bootstrap/FeatureContext.php) and rerun behat. Now we’ll see some TODOs! Time to actually write code! We’ll start from the top:

1
Given I am an unregistered user

This is going to be a no-op. We don’t need to do anything here, so let’s just remove the PendingException in the step defintion:

1
2
3
4
5
6
/**
 *  @Given /^I am an unregistered user$/
 */
public function iAmAnUnregisteredUser()
{
}

Now that step should be green when we re-run the behat steps. We’ll move on to the next step. Here’s where the real meat will start. Since we are writing our business logic, we’ll start with defining the interface we want to work with, and write the code we wish we had.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * @When /^I register with the following information:$/
 */
public function iRegisterWithTheFollowingInformation(TableNode $table)
{
  $parsed_data = [];
  foreach ($table->getNumeratedRows() as $row)
  {
    $parsed_data[$row[0]] = $row[1];
  }

  $register = new Account_Registration;
  $result = $register->execute($parsed_data);
}

This might be something we would want. Instantiate a new use case class (Account_Registration), and call it’s execute() method with our registration data.

Let’s run this in behat:

1
PHP Fatal error:  Class 'Account_Registration' not found

Now we are blocked, we have an error in our tests. So let’s make this thing pass:

classes/Account/Registration.php
1
2
3
4
5
6
7
8
9
<?php

class Account_Registration
{
  public function execute($params = [])
  {

  }
}

Also make sure you require this file in your FeatureContext class.

1
require 'classes/Account/Registration.php';

Now if you run behat, we’ll have the next step green in both scenarios.

Let’s move on to the next step. What do we do here? How do we assert the account was created? Simple. We want to use Dependancy Injection, and inject a repository object into the use case class. The use case will then use that repository to persist the data. We will use a mock object to keep track of this. We don’t want to use the real thing because we don’t care about the database right now (we will later, and we’ll replace this code later). We’ll need to modify our last step definition:

1
2
$this->account_repo = new Mock_Account_Repository;
$register = new Account_Registration($this->account_repo);

Now when we run behat, we’ll get a fatal error about this Mock class not existing. So let’s just create it at the end of the file.

1
2
3
4
5
6
7
8
9
10
11
class Mock_Account_Repository implements Account_Repository
{
  public $create_called = FALSE;
  public $create_data = NULL;

  public function create($data)
  {
    $this->create_called = TRUE;
    $this->create_data = $data;
  }
}

And we’ll need to define that interface. Let’s do that in our classes folder:

classes/Account/Repository.php
1
2
3
4
<?php
interface Account_Repository {
  public function create(array $data);
}

Make sure you require that file right above the Mock_Account_Repository class defined above. Now we need to assert that our class does what we want. So in our next step definition, we’ll inspect that mock object:

1
2
3
4
5
6
7
8
/**
 *  @Then /^I should be registered$/
 */
public function iShouldBeRegistered()
{
  Assertion::true($this->account_repo->create_called);
  Assertion::same($this->data, $this->account_repo->create_data);
}

Now when you run this, it should fail. So let’s make it pass.

classes/Account/Registration.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

class Account_Registration
{
  protected $_account_repository;

  public function __construct(Account_Repository $account_repository)
  {
    $this->_account_repository = $account_repository;
  }

  public function execute($params = [])
  {
    $this->_account_repository->create($params);
  }
}

On to the next step! We want to send an email out to the user after they register. We need to abstract out the email handling, so let’s make a mock class for that too.

1
2
3
4
5
6
7
8
9
class Mock_Email_Sender implements Email_Sender
{
  protected $sent = array();

  public function send_mail($to, $from, $subject, $body)
  {
    $this->sent[] = array('to' => $to, 'from' => $from, 'subject' => $subject, 'body' => $body);
  }
}

And the interface for this class:

classes/Email/Sender.php
1
2
3
4
5
6
<?php

interface Email_Sender
{
  public function send_mail($to, $from, $subject, $body);
}

And let’s add this to the step definition:

1
2
3
4
5
6
7
/**
 *  @Given /^I should receive a welcome registration email$/
 */
public function iShouldReceiveAWelcomeRegistrationEmail()
{
  Assertion::same($this->email, $this->email_sender->sent[0]['to']);
}

You’ll need to modify some previous steps for this. When you are done, you should get an error like:

1
Notice: Undefined offset: 0 in features/bootstrap/FeatureContext.php line 81

So we just need to make this pass. Easy:

classes/Account/Registration.php
1
2
3
4
5
public function execute($params = [])
  {
    $this->_account_repository->create($params);
    $this->_email_sender->send_mail($params['email'], 'donotreply@foo.com', 'Welcome!', 'The body');
  }

Sweet! Our first scenario passes! You should be able to implement the rest of the second scenario fairly easily.

This concludes our tutorial on creating a basic Interactor class. It doesn’t do much right now, but next time we’ll add in some validation, and do some other fun stuff with phpspec.

Well Designed Application Architectures - Part 2 - Business Logic

Last time we talked about what MVC really is, and how to use it properly. It didn’t really mention much of anything about how/where to put the code that makes your site tick. This code is called your application. It’s the business logic that, you know, actually does the real work on the site.

If you recall from last time, I said that this code should live far, far away from your delivery mechanism (your MVC layer). That’s pretty abstract. Where should it really go? How do you write it?

A lot of people look at me funny when I say “do not write your business logic with a framework”. They think “how on earth will I get anything done?”. It’s actually very easy, and not time consuming at all if you do it right.

Language

I’m going to be using PHP for my code examples here. I prefer Ruby, but it seems that it’s “harder” to do this in PHP, so I want to show that it’s actually not.

File Organization

First off, put your business logic into it’s own repository. This will make the separtion clear and force you to not muck the separation of concerns together. You’ll also be able to recognize your application’s purpose from it’s file structure, as described in the Uncle Bob talk from last time.

People in the PHP world seem to like the PSR-0 standard for file and class naming so we’ll use that, but not the silly PSR-1 and PSR-2 “standards”.

Components

Below are the components that we’ll be using to design our application.

Use Cases

Back in school you learned about a Use Case, right? Well, they aren’t useless after all. Use cases are the backbone of how your application works. We’ll be using a use case driven architecture from now on.

Why? They let us define our classes in a structured way, and let any reader of our code know exactly where to go when they need to look at some functionality. Need to know about how a user registers? Simply go to the Register_User class, all the code is there.

DCI vs Interactors

I prefer to use the DCI pattern for describing my use cases in code. However, it’s not clear how to implement DCI in many languages. Because of this, I’ll just be describing interactors, which are a similar but simpler way to write use cases.

DCI makes a lot more sense overall, but in some languages (especially php), it’s just impossible to implement properly. You basically would need the ability to assign traits to objects at runtime (at the minimum), and php is certainly not capable of that.

An interactor is just a class that describes your use case. It has the following properties:

  • It has a single public entry point, execute()
  • All other methods are protected or private
  • It raises exceptions when an error occurs
  • It returns normalized data (like an array) for a query operation, and returns nothing for a write operation
  • It injects all it’s dependancies. I like to use factory methods for these, so I’ll do that in my examples later on

Database Access

So where does your database access come into play in all this? A lot of frameworks make you think about the database entirely too early. The database is just a detail about where/how your data gets persisted. Don’t worry about it too much yet. Just worry about defining your Data Objects first. We’ll use a repository pattern to send those data objects to be persisted, and it doesn’t really matter to anyone but the repository class on how that’s done.

Data Objects

Your data objects classes that model your business objects. They don’t extend anything, they don’t connect to a database. In php, they are just POPOs (Plain old php objects). Here’s a good example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

class User
{
  public $id;
  public $email;
  public $password;
  public $first_name;
  public $last_name;

  public function __construct($data)
  {
    $this->id = $data['id'];
    $this->email = $data['email'];
    $this->password = $data['password'];
    $this->first_name = $data['first_name'];
    $this->last_name = $data['last_name'];
  }
}

Easy.

Repository Classes

A repository class is an object that persists and retrieves data objects. That’s all it does. Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

class User_Repository_Database implements User_Repository
{
  protected $_db;

  public function __construct(Database $db)
  {
    $this->_db = $db;
  }

  public function create(User $user)
  {
    $this->_db->insert('users')->values($user->as_array());
  }

  public function find_by_id($id)
  {
    return $this->_db->from('users)->where('id', '=', $id)->as_object('User');
  }
}

The repository class should take data objects in, and spit data objects back out. That’s it.

Next time we’ll start building an actual interactor.

Well Designed Application Architectures - Part 1 - MVC

I’ve been dumping my brain about this topic in IRC for about 3-4 months now, and I figure it would just be easiest to do a dump here and link people to it. This series will probably be a few parts, I’m just going to do parts of the dump for a few days.

If you have feedback for me, please use twitter (on the right over there) to do so.

Before I begin, you should watch this (I’m basically going to be rehashing it and adding my own notes):

MVC

So, lets start with MVC. Web-based MVC (yes, not the “real” kind). “What’s wrong with MVC?”, you might ask? Well, nothing, as long as you use it for it’s strengths: as a delivery mechanism pattern. We’ll get into what a delivery mechanism is in a bit. So, how do you use MVC effectively? Well, lets start with the different parts of the acronym:

Controller

Your controllers are thin, right? Do they contain only http logic? If they contain any business logic at all, they are not thin. Just because it’s not database calls doesn’t mean you can throw it in the controller. The controller shouldn’t know anything about your domain logic. It should just know:

  • How to parse incoming request data
  • How to send that data to your business classes
  • How to send the output from the business classes to the view

That’s it! What do you gain from doing this?

  • Your controllers are even thinner
  • Your controllers are probably testable in isolation, so you can test your http interactions quickly, and without a real web server or framework loading up

Views

When I say “view”, does “class” also come into mind? Are you doing all your presentation logic in your templates? Stop it! You can’t test that. Use something like Mustache. What do you gain by using Mustache?

  • Logicless templates
  • Testable views
  • Portable templates (you can reuse your same templates in both your server and client).

Logicless templates let you start your views with tests (You do TDD, right?). It keeps your views more maintainable and lets you be more confident that the logic contained in them actually works.

When you write your view classes, they should only accept input from the outside world. They should not be reaching into the database, they should not be instantiating any classes (especially not models!). All they should be doing is accepting input from the controller and formatting that input for display. This display can be anything: html, json, xml, etc. This is another advantage of using mustache: it lets you easily adjust your output template, and not change your logic that parses the data. Reuse people!

Model

Wow, what a big area. Basically anything that isn’t a controller or view goes here. That is A LOT. This is the first problem with using MVC 100% to design your application. If you subscribe to the “thin controller, fat model” approach (as just about all web frameworks out there teach you), you will end up with an unmaintainable mess of an application.

Why? Well, first off, you’ll be combining your domain logic (since your controllers are thin, right?) and your persistance logic (just about every framework tells you to put queries in a model) in the same layer. This is very bad for many reasons:

  • Hard to test
  • Slow to test
  • Tests will do too much

A lot of the topics in this series will revolve around testing. How can you make your application easier to test? How can you start with tests?

So what can we do? Easy: Don’t use models. Just don’t. Models don’t belong in your MVC delivery mechanism. In this sense, I suppose I should be calling it CVT (Controller-View-Template).

Delivery Mechanism

What’s this “delivery mechanism” thing, anyway? A delivery mechanism is:

A framework of classes that easily let you redistribute your business logic (your application) in a format specific way, over a specific medium.

Your application is not made up of controllers and views. That stuff is all part of your delivery mechanism. So from here on out, I’ll be refering to your business logic as your application.

You do need these things. You don’t want to be writing http request and response classes. That crap is already done, and it’s a lot of work.

A delivery mechanism’s sole purpose is to call your application, and send it’s output to a specific format. It could be an html website, a JSON based REST API, or a console based binary. All three of these could be delivering the exact same business logic. All three of these could be different frameworks, because your application is completely decoupled from your delivery mechanism.

Your delivery mechanism should not know anything about your business rules, except how to call the application. It consumes your application, and spits out the data.

Ever cry when your favorite framework released an upgrade, and it broke the old API? Separate your application from your delivery mechanism, and upgrading to a new version (or a completely different) framework becomes much easier. The framework code no longer has it’s slimy tentacles embeded inside your code. That means less code to change.

This brings me to a related topic: You should try like hell to never have your business logic classes extend a third party class. Don’t let someone else taint your class’s API with theirs. You’ll just end up in a similar situation to the framework problem above. I’ll go into more details on this in a future post.

Business Logic

“If we can’t use models, then were the hell does the business logic go?” You might be asking. Easy:

Far, far, far, far away from your MVC layer. We’ll get into the details on this next time.