PHP/Domain models

A while ago, the Python chaps wrote a "complete guide to piano-playing" that went something like:


 * 1) Sit down at the piano;
 * 2) Select the right key;
 * 3) Put it in the piano, and open the lid;
 * 4) Once the piano is fully open, put your fingers on top of the notes
 * 5) Move your fingers about, making sure they hit the right notes in the correct order (like a pianist)
 * 6) Watch your friends be amazed

This article attempts to similarly enumerate the steps that one should go through when designing and writing the domain model portion of a computer program written in PHP (using Composer and PHPUnit). Hopefully your friends will be amazed.

The domain model is the first part of the program that is worked on, after the first requirements have been decided upon. It must be constructed with no regard to anything in the world beyond its borders (no user interface, no database, no files, nothing). The only interaction that the model has with the outside world is when it uses objects passed in to it (and these are all either primitive, i.e. basic or built-in) or are implementations of interfaces that the domain model itself defines.

The domain model is the most important part of a program. Its design is more important than the designs of either the user interface or the database schema (if either exist). A valid and verified domain model will have longer-lasting benefits than these other aspects of a program, because it deals with the real-world details of the domain in question.

Sit down at the computer
Or stand, if a standing desk is more comfortable for you.

Obtain requirements
Obtain (or write from scratch) a list of requirements, or problem statement.

For the purposes of explanation, this article assumes a need to maintain a list of Widgets and some information about them.

Set up test framework
The test framework should be the only non-domain thing in existance, to start with.

To get started with this, make a  file in a new empty directory and in it require PHPunit. Also set up autoloading for the classes' directory.

Then install it:

Also create  in the same directory:

Create a first test in  (a temporary name, and it'll be changed soon enough):

Now test that everything is set up by running:

At this point, development proper can begin. This is also the point to which we return in each development cycle when it is time to begin again (apart from sitting down beforehand).

Write a test
Assume the following simple requirements of the system that is being developed:


 * 1) A list of Widgets must be maintained.
 * 2) A Widget has a name and a type, and the name must be unique for the given type.

This is enough to demonstrate various constraints and the idea of a data repository.

The first task is to draw a class diagram of the desired interface (shown at right). This must know nothing about the outside world. Create it with the words and structures used in the domain in question — this is not really, in one sense, a programming API but rather an expression of the ways in which one can interact with the domain.

Then start testing it. The first test will create a new Widget and give it a name:

Running this will result in a failure, because the Widget class doesn't exist. So, create it (in a new  directory) and write the obvious getter-setter code (this could, if one were being a bit more 'pure' about TDD, be done in multiple steps, but it's quicker to just get the basics out of the way).

The test should now pass:

So far, so good, and nothing really has been achieved. The system is set up now, however, for actual development.

This is usually the point at which a nacent project can be put under version control. Put the domain model (and tests etc.) in their own separate repository, to help maintain the discipline of not developing them in any direction that is tied to any particular storage or interface system. This separate repository can then be added as a dependency in any project's.