Home » Code » Encapsulating your application’s business rules

Encapsulating your application’s business rules

Posted by on August 18th, 2014

Encapsulating your application's business rules
Over the last couple of week’s we’ve looked quite extensively into integrating Doctrine 2 into a Laravel project as well as the unique characteristics and functionality Doctrine 2 offers us as the ORM layer to our applications.

Doctrine 2 is an implementation of The Data Mapper pattern. The Data Mapper pattern promotes the separation of your application’s business rules from how the data is persisted to the database. This is in contrast to the Active Record pattern (What’s the difference between Active Record and Data Mapper?), where the two are coupled together.

So far in this little exploration of Doctrine 2 we’ve covered:

Whilst getting a grasp of how Doctrine works and how it is different to Eloquent is important, we haven’t really touched upon the main reason why you would want to choose Doctrine 2 in the first place.

That reason is how you encapsulate the business rules of your application.

And so that will be the focus of today’s article.

What are business rules?

The business rules of an application are essentially what makes that application unique.

If you were developing an application for an existing company, the company is likely going to already have business rules that define how the company operates.

For example, if you were developing an application to manage the internal company projects, you might have to adhere to the following business rules:

  1. Only Project Managers can create new Projects
  2. A Project must have a completion date
  3. A Project must have an assigned Client
  4. A Project must have one or more Milestones
  5. A Project must have a status

Each one of these business rules are extremely important to adhere to because they are critical to how the business operates.

Each different application will have a unique set of business rules. Typically applications that are built to streamline existing processes will already have strict business rules in place. But even for greenfield projects, the application will typically have a number of business rules that define how it should operate.

Having a good idea of the business rules of a proposed application will be a good starting point to developing a new application. Getting to that point is out of the scope of this article, but I’ll cover it in a future post.

Where should you define business rules?

As I’ve mentioned in a couple of previous posts, knowing where to define the business rules of an application can be tricky to get your head around.

For many types of application, defining business rules in the Active Record model is fine.

I’d even go as far as saying for certain types of simple web application, defining certain business rules in the controller is probably fine too.

However for bigger or more complex applications you should be defining your business rules within your project’s domain.

It is the domain of your application that makes it unique. Business rules should be encapsulated in entity and value objects that have no dependency or knowledge of the outside world.

Domain and Model are pretty loaded terms in the world of computer programming. Domain in this case is the rules around how the business operates, whereas Model is the code that you write to provide a solution to the client.

This is kind of an abstract topic unless I really get into what each of these concepts mean and how they work together in a cohesive application. If you are little bit fuzzy on what this all means, don’t worry! I’ll be covering each of these topics on Culttt in the coming weeks.

A note about this project

This building Cribbb series of tutorials is a hopefully a learning experience for both you and I. By documenting each step in the process hopefully you will pick up a lot of the tools, techniques and experience that is required to build and launch an application.

With that being said, the project so far has been pretty unstructured. There have been a number of times when I’ve advocated one approach and then just a couple of weeks later I’ve ripped it out and implemented a different approach.

There is no plan with this series and so I’m just making it up as I go along. This is probably annoying for you, the reader, but hopefully you will see it as a learning experience. Rather than you building your own cookie cutter version of Cribbb, you will learn how to build your own web applications.

Today’s tutorial marks another shift in direction for this series. From now on I’m going to be exploring a much deeper Domain Driven Design approach to developing Cribbb. This means that a lot of the code up until this point can just be deleted.

With this new direction I’ve also changed the directory structure of the application. I’d advise that you take a browse through the Git repository to see what’s changed.

The biggest change I’ve made is to move the Cribbb folder from the app directory, and into a src directory. Now all my Cribbb specific code will be kept separate from the Laravel specific code.

Within the src/Cribbb directory I’ve created two directories for Domain and Infrastructure.

The Domain directory will be house my domain related code such as the User entity or the UserRepository interface. These files will be stored under a further directory of Model.

The Infrastructure folder will house the code that will implement Cribbb, but is not directly a concern of the application. For example, I might use a UserDoctrineRepository or a SendGridMailer class.

Under the Model directory I will further split my application into further sections of related code. For example, the code in this tutorial will sit under a Users directory.

If you are unsure about the reasoning why I’ve set up the project like this, don’t worry. I will be exploring the reasoning behind these decisions in the coming weeks.

Defining Cribbb’s business rules

The first aspect of Cribbb’s business rules that I’m going to tackle is the logic around users of the system. At the minute I’m only really thinking about the foundational aspects of being a “user” of Cribbb. The rules and logic about posting or joining a Cribbb can wait until another day.

So the rules around being a user of Cribbb are:

  1. A user must have an Email, Username and Password
  2. An Email should be valid and unique
  3. A Username should only contain alpha-numeric characters, as well as dashes and underscores, and it should be unique
  4. A Password should be more than 8 characters long

Encapsulating business rules in objects

There are many different ways in which you could enforce the business rules I’ve outlined above.

However when using an Object Oriented approach, it makes the most sense to use Object Oriented methods.

An Email, Username and a Password could all be considered Value Objects within our application (What is the difference between Entities and Value Objects?). Two emails addresses are conceptually the same when you analyse them in isolation.

By creating Value Objects out of each of these user requirements we can encapsulate the business rules around each item within the confides of a dedicated PHP object that has the sole responsibility of being an instance of that thing.

This means whenever we need an instance of an email address, we can create a new Email object like this:

$email = new Email('name@domain.com');

The Email object has the responsibility to ensure that the email address is valid. This means we encapsulate the business rules of our application within the Email class.

Creating an Email class allows us to create Email objects where we are confident that the object is valid.

When you do something like this:

$email = 'name@domain.com';

The $email is just a dumb string, so you can’t be sure that it is a valid email address without running it through some kind of validation.

By creating a Email object we can encapsulate the rules of a “valid” email address within the object. The rules around what is valid and not valid are kept internal to the class, so the outside world never needs to be concerned.

Writing the tests for the Email Value Object

So the first thing I’m going to do is to write some tests to define how I want my Email object to behave.

Create a new file called EmailTest under test/Cribbb/Domain/Model/Users and copy the following code:

<?php namespace Cribbb\Domain\Model\Users;

class EmailTest extends \PHPUnit_Framework_TestCase {

}

You will notice that I’m not extending the usual TestCase class that you normally see in Laravel based projects. None of my domain related code will have anything to do with Laravel so we don’t need to load the framework for these tests.

The first test should ensure that an Email object should require an email address to be passed in through the constructor. This is easy enough to implement because we can just define the email address as a dependency of the constructor method and PHP will deal with throwing an exception if it is not satisfied. Here is the test:

/** @test */
public function should_require_email()
{
  $this->setExpectedException('Exception');
  $email = new Email;
}

You will notice that I’ve diverged from the usually naming convention of PHPUnit tests. Normally PHPUnit requires that your test names are in the form of testShouldRequireEmail. However I’ve picked this alternative convention from Mathias Verraes. This is totally optional and comes down to your personal preference, but in my opinion the naming convention I’ve used above is more readable.

Next I want to ensure that the Email object will only accept valid email addresses. Here is the test:

/** @test */
public function should_require_valid_email()
{
  $this->setExpectedException('Assert\AssertionFailedException');
  $email = new Email('this_is_not_a_valid_email');
}

You will notice that in this test I’m expecting a AssertionFailedException. I’ll explain what kind of Exception this is when we come to implement the code.

And lastly I will write a test to simply validate that everything works as expected by passing in an email address that is valid and asserting that the Email object is instantiated correctly:

/** @test */
public function should_accept_valid_email()
{
  $email = new Email('name@domain.com');
  $this->assertInstanceOf('Cribbb\Domain\Model\Users\Email', $email);
}

Implementing the Email object

Now that I’ve got the tests in place I can implement the code to make them pass.

Create a new file called Email.php under the Users directory under src/Cribbb/Domain/Model and copy the following code:

<?php namespace Cribbb\Domain\Model\Users;

use Assert\Assertion;

class Email {

}

You will notice that I intend to use Assert\Assertion. This is a PHP package that can be used to “assert” that a value is of a specific type, you can find it on GitHub.

This means instead of having the following code to assert that an email address is a valid email:

if(filter_var($value, FILTER_VALIDATE_EMAIL) !== false)
{
  $this->value = $value;
}

We can simply write:

Assertion::email($value);

The Assert package is used to prevent you from having to litter your code with these if blocks. It is specifically design for libraries and application low-level code and so it has no dependencies.

Now you could argue that there should be no third-party code in your Domain related code. I agree with this statement, but I also tend to err on the side of pragmatism. If PHP had a native Assert class I would use it, so I think using this third-party package in this instance is fine. Personally I would rather have a simple one line assertion than have if statements all over the place.

The Email is going to be really simple for the time being as the only responsibility it has will be to ensure that the email address it is created with is valid.

First define a property on the class to hold the $value that is passed through the constructor:

/**
 * @var string
 */
private $value;

I will probably also want to cast this object as a string, so we can implement the __toString() magic method (What are PHP Magic Methods?):

/**
 * Return the object as a string
 *
 * @return string
 */
public function __toString()
{
  return $this->value;
}

Finally we can implement the __construct() method to accept the $value and validate it:

/**
 * Create a new Email
 *
 * @param string $value
 * @return void
 */
public function __construct($value)
{
  Assertion::email($value);

  $this->value = $value;
}

If the $value is not a valid email address, the Assertion class will throw a AssertionFailedException exception which will halt the application and jump to the surface (When should you use an Exception?).

If the email address is valid we can simply set it as a property of the class.

Now if you run the tests you should see them all pass.

Conclusion

In this tutorial we’ve looked at encapsulating the business rules of an application inside Value Objects within the project’s domain. By utilising the inherent power of object oriented programming we can write code that is expressive, easy to work with and satisfies our requirements.

You will have noticed that I’ve not walked through implementing the Username and Password objects in this tutorial. The principle behind those two Value Objects is the same as the Email Value Object and so I will leave that as something you can think about. If you get stuck you can always take a peak at the Git repository.

The theory and the implementation that I’ve covered in this tutorial is heavily inspired by a fantastic talk by Mathias Verraes called Unbreakable Domain Models. If you need clarification on anything that I’ve wrote about today I would highly recommend taking an hour to watch that talk. I guarantee you will walk away more knowledgable than when you started.

You will also notice that I’ve not covered ensuring that email addresses and usernames are unique within the context of the application. The implementation of ensuring uniqueness is slightly different from what we’ve covered today, so I’ll leave that as something to cover next week.

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

To view a full listing of the tutorials in this series, click here.

Philip Brown

Hey, I'm Philip Brown, a designer and developer from Durham, England. I create websites and web based applications from the ground up. In 2011 I founded a company called Yellow Flag. If you want to find out more about me, you can follow me on Twitter or Google Plus.

  • W. van Dam

    Hi Philip,

    Thanks for continuously writing interesting articles. I’ve seen the Domain Driven Design being mentioned before, but never found the time to look up a good explanation. Your example along with the talk by Mathias Verraes make the benefits quite clear. I may take a shot at it in the second stage of my current project.

    Cheers,
    Wouter

    • Yeah, there is a lot to learn! But once it starts coming together I think you look at building applications in a whole new light :)

      • Guest

        Yes Philip,

        Very useful, and any future article will be very well received.

        Have a nice day.

  • codeatbusiness

    Great article Philip,

    At this moment I’m learning about DDD from the Vernon’s book and I have many doubts. I’m expecting your new DDD articles for re-design my web applications more efficiently.

    Some terms as: bounded context, specifications, domain services and how manage value objects could be useful for many users.

    Thanks newly for sharing your knowledge with us.

    Cheers.

    • Yeah I plan on writing in depth tutorials on each of those areas as I couldn’t really find much information when I was researching.

      Glad you are finding them useful :)

      • codeatbusiness

        Yes Philip,

        Very useful, and any future article will be very well received.

        Have a nice day

  • Pingback: Implementing The Specification Pattern | Culttt()

  • MP

    Have you been able to persist these in Doctrine? I’ve tried using the new Embeddables, but without much success.

  • Pingback: The User Entity and The Ubiquitous Language | Culttt()

  • Konstantin Starojitski

    Great series! One thing that struck me is your use of the word “orientated” instead of “oriented”

    • Haha, oops, writing isn’t my strong point :p Thank you Konstantin :)

  • Pingback: Defining the building blocks of Domain Driven Design | Culttt()

  • Pingback: Implementing Domain Events | Culttt()

  • Emk

    Nice Tut. Please i will like to use http://laravel.com/docs/4.2/validation inside the Email class. Also can i check if a giving email already exists inside the Email classs

  • Pingback: Creating Domain Services | Culttt()

  • Pingback: Creating and Using a Command Bus | Culttt()

  • Pingback: Failing Domain Rules and Validating User Input | Culttt()

  • Pingback: 6 Principles for Writing Maintainable Code | Culttt()

  • Edward

    Hi Phillip, Thanks again for these amazing tutorials. I have a quick question for you. I’m having a strange problem with my unit tests.

    This Test

    public function should_require_email()
    {
    $this->setExpectedException(‘Exception’);
    $email = new Email;
    }

    Is failing with the error:

    Missing argument 1 for CribbbDomainModelIdentityEmail::__construct(), called in…

    If I change to
    $email = new Email(”);
    Test passes

    It’s probably something basic that I’m overlooking, but I thought I would post just to see if anyone would have any ideas what it could be.

    • It’s because your constructor is expecting an argument and so PHP is throwing the error. That would be the expected behaviour.

      • edward

        Right, but I was thinking the phpunit test should ‘pass’ because it is expecting the exception?

        $this->setExpectedException(‘Exception’);

        All of my other tests that rely on setExpectedException ‘pass’ the unit test because the exception is thrown in the code. I can’t figure out why this one is failing the unit test. Am I missing something really basic?

        • edward

          Just been messing with it a little more. found out that if I change the expected exception to ‘PHPUnit_Framework_Error’ it passes, but if I change the expected exception back to ‘Exception’ the unit test fails.

          $this->setExpectedException(‘PHPUnit_Framework_Error’);
          $email = new Email;
          //PASSES

          $this->setExpectedException(‘Exception’);
          $email = new Email;
          //FAILS

          I believe it should be handling the missing argument as an exception but instead it is handling as an error. Maybe whatever turns the error into an exception in laravel 5 isn’t set up properly? I’m not really sure at this point.

          • Ah right, sorry I see what you mean now. So this isn’t working for you? https://github.com/yellowflag/cribbb/blob/master/tests/Domain/Model/Identity/EmailTest.php#L8-L12

            Have you tried running my test file and seeing what the difference is?

          • edward

            Got it! For some reason I was loading

            “phpunit/phpunit”: “~4.0”,

            instead of

            “phpunit/phpunit”: “4.0”,

            One little tiny tilde. Hours of frustration. With my min-stability settings it was apparently loading an unstable version of phpunit. All better now though. Thanks!

          • Ah yeah, you don’t need to be careful when pulling in third-party code. I’ve felt that frustration myself! Glad you got it sorted :)

  • Jebb

    @philip_brown:disqus nice article! By the way, how will you implement a Value Object in MongoDB, let’s say thru Doctrine MongoDB ODM?

    • The Value Object isn’t concerned with the method of data storage, so it would just be a regular PHP object.

      • Jebb

        Just like an Entity in a Data Mapper pattern it’s also not concerned about data storage but it is mapped as a document in a MongoDB, a Value Object can be a part or considered as an attribute or property of an Entity (which is mapped), if an Entity class has mappings to a MongoDB Document how will you map its Value Object as part of that Entity (Document)?
        Unless a Value Object is implemented as an Embedded Document but I don’t think that’s the case. Anyway, I saw your implementation of Value Object in http://culttt.com/2014/12/15/using-entities-different-bounded-contexts, that’s nice.

  • milad rey

    Hi Philip.
    How about checking email is unique? how you will handle that.