Design by Contract (DBC) - Facade

Edit on GitHub

Every method in a facade contains an implicit promise. So a client expects that the behavior does not change in a minor update. Basically, there are two types of possible changes:

  • Changes in the method’s signature—for example, when the name of the method or the order of the parameters changes.
  • Changes in the expected behavior of the method. While a renamed method causes an exception, a change of behavior is much harder to detect.

A contract is a formal and precise specification of a method (or another component). This consists of three parts: preconditions, post-conditions, and invariants. Practically, there is no approach to enforce a contract in PHP. In other languages, there are DBC extensions like iContract for Java (see iContract: Design by Contract in Java from 2001).

Example:

Imagine a signature like this for the method saveCustomer():

<?php
/**
 * @param string $idCustomer
 * @param string $email
 *
 * @return void
 */
public function saveCustomer($idCustomer, $email) 
{
    ...
}

Based on the name, this method “saves a customer”. So the contract likes this:

CONDITION TYPE DESCRIPTION
precondition The email address does not already exist. This constraint is defined by the database schema.There is a customer with the given ID.
Post-condition The amount of customers is incremented by one.
Invariant There are customers with one email address each.

Additional information:

  • The post-conditions are complete. So we don’t expect any other behavior here—for example, this method must not send an email to a customer to confirm the change.
  • This method must not return anything. You could think of a boolean return value if the email cannot be changed. But then this method would do two things. Therefore, it is a better approach to have another doesEmailExist($email) method for the pre-check.
  • If the preconditions are not valid, the method must throw an exception. In this case, if the email address already exists we would throw an EmailAlreadyExistsException.