Part 1 - Design Philosophies and Principles

There’s not much code in this part of the book. Sorry, it’s all about the design at this point. Here I’ll discuss general design principles used in building the application.

You may be thinking, “just take me to the code.” For the most part, I concur. It’s often quickest and easiest just to jump in the code and learn by doing. If you understand the concepts: SOLID Object Design, Interface as Contract, Dependency Injection, Decoupling, and Inversion of Control, then skip to Part 2 to begin designing the application.

Chapter 16 - SOLID Object Design

There is a set of principles in object-oriented design called SOLID. It’s an acronym standing for:

  • [S]ingle Responsibility
  • [O]pen/Closed Principle
  • [L]iskov Substitution Principle
  • [I]nterface Segregation Principle
  • [D]ependency Inversion Principle

Together, they represent a set of best practices which, when followed, makes it more likely software you develop will be easier to maintain and extend over time.

This chapter explains each principle in greater detail.

Do me a SOLID?

If a programmer comes up to you and says, “Can you do me a SOLID?” Make sure you understand what you’re being asked.

Single Responsibility Principle

The first letter, ‘S’ in the SOLID acronym, stands for Single Responsibility. The principle states:

“Every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.”

Another way to think about this is that a class should have one, and only one, reason to change.

Let’s say you have a class that compiles and emails the user a marketing report. What happens if the delivery method changes? What if the user needs to get the report via text? Or on the web? What if the report format changes? Or the report’s data source changes? There are many potential reasons for this class to change.

State the class Purpose without AND

A simple way to implement the Single Responsibility Principle is to be able to define what the class does without using the word AND

Let’s illustrate this with some code …

 1 // Class Purpose: Compile AND email a user a marketing report.
 2 class MarketingReport {
 3   public function execute($reportName, $userEmail)
 4   {
 5     $report = $this->compileReport($reportName);
 6     $this->emailUser($report, $userEmail);
 7   }
 8   private function compileReport($reportName) { ... }
 9   private function emailUser($report, $email) { ... }
10 }

In this case we’d break the class into two classes and push the decision as to what report and who/how to send it up higher in the food chain.

 1 // Class Purpose: Compiles a marketing report.
 2 class MarketingReporter {
 3   public function compileReport($reportName) { ... }
 4 }
 5 
 6 interface ReportNotifierInterface {
 7   public function sendReport($content, $destination);
 8 }
 9 
10 // Class Purpose: Emails a report to a user
11 class ReportEmailer implements ReportNotifierInterface {
12   public function sendReport($content, $email) { ... }
13 }

Notice how I snuck that interface in there? Aye, I be a slippery bugger with them thar interfaces.

More Robust Classes

By following the Single Responsibility Principle you’ll end up with robust classes. Since you’re focusing on a single concern, there’s less likelihood of any code changes within the class breaking functionality outside the class.

Open/Closed Principle

The second letter in the SOLID acronym stands for the Open/Closed principle. This principle states:

“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.”

In other words, once you’ve coded a class you should never have to change that code except to fix bugs. If additional functionality is needed then the class can be extended.

This principle forces you to think “how could this be changed?” Experience is the best teacher here. You learn to design software setting up patterns that you’ve commonly used in earlier situations.

Don’t Be Too Strict

I’ve found strict adherence to this principle can result in software that is over-engineered. This occurs when programmers try to think of every potential way a class could be used. A little bit of this thinking is a good thing, but too much can result in more complex classes or groups of classes that have no true need of being so complex.

Sorry if this offends die-hard fans of this principle, but hey, I just calls ‘em like I sees ‘em. It’s a principle, not a law.

Nevertheless, let’s work out a common example. Let’s say you’re working on an account biller, specifically the portion that processes refunds.

 1 class AccountRefundProcessor {
 2   protected $repository;
 3 
 4   public function __construct(AccountRepositoryInterface $repo)
 5   {
 6     $this->repository = $repo;
 7   }
 8   public function process()
 9   {
10     foreach ($this->repository->getAllAccounts() as $account)
11     {
12       if ($account->isRefundDue())
13       {
14         $this->processSingleRefund($account);
15       }
16     }
17   }
18 }

Okay, let’s look at the above code. We’re using Dependency Injection thus the storage of accounts is separated off into its own repository class. Nice.

Unfortunately, you arrive at work one day and your boss is upset. Apparently, management has decided that accounts due large refunds should have a manual review. Uggh.

Okay, what’s wrong with the code above? You’re going to have to modify it, so it’s not closed to modifications. You could extend it with a subclass, but then you’ll have to duplicate most of the process() code.

So you set out to refactor the refund processor.

 1 interface AccountRefundValidatorInterface {
 2   public function isValid(Account $account);
 3 }
 4 class AccountRefundDueValidator implements AccountRefundValidatorInterface {
 5   public function isValid(Account $account)
 6   {
 7     return ($account->balance > 0) ? true : false;
 8   }
 9 }
10 class AccountRefundReviewedValidator implements
11   AccountRefundValidatorInterface {
12   public function isValid(Account $account)
13   {
14     if ($account->balance > 1000)
15     {
16       return $account->hasBeenReviewed;
17     }
18     return true;
19   }
20 }
21 class AccountRefundProcessor {
22   protected $repository;
23   protected $validators;
24 
25   public function __construct(AccountRepositoryInterface $repo,
26     array $validators)
27   {
28     $this->repository = $repo;
29     $this->validators = $validators;
30   }
31   public function process()
32   {
33     foreach ($this->repository->getAllAccounts() as $account)
34     {
35       $refundIsValid = true;
36       foreach ($this->validators as $validator)
37       {
38         $refundIsValid = ($refundIsValid and $validator->isValid($account));
39       }
40       if ($refundIsValid)
41       {
42         $this->processSingleRefund($account);
43       }
44     }
45   }
46 }

Now AccountRefundProcess takes an array of validators during construction. The next time business rules change you can whip out a new validator, add it to the class construction, and you’re golden.

Liskov Substitution Principle

The “L” in SOLID stands for Liskov substitution principle. This principle states:

“In a computer program if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may be substituted for objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.).”

Huh? I’d hazard a guess that this part of the SOLID design causes more confusion than just about any other.

It’s really all about Substitutability, but if we used the ‘S’ from Substitutability our acronym becomes SOSID instead of SOLID. Can you imagine the conversations?


Programmer 1: “We should follow the S.O.S.I.D. principles when designing classes.”

Programmer 2: “Sausage?”

Programmer 1: “No, SOSID.”

Programmer 2: “Saucy?”

Programmer 1: Calls up Michael Feathers on the phone … “Hey, we need a better acronym.”


Simply stated, the Liskov Substitution principle means that your program should be able to use sub-types of classes wherever they use a class.

In other words if you have a Rectangle class, and your program uses a Rectangle class and you have a Square class derived from the Rectangle. Then the program should be able to use the Square class anywhere it uses a Rectangle.

Still confused? I know I was confused initially because I wanted to say “Duh? This is pretty obvious”, yet I feared there was something I didn’t understand. I mean, why have this as a major tenet of SOLID design if it’s so obvious?

Turns out there are some subtle aspects to this principle stating preconditions of subtypes should not be strengthened and postconditions should not be weakened. Or is it the other way around? And you can’t have subtypes throw exceptions that aren’t the same (or derived from) exceptions the supertype throws.

Wow! What else? There are other details about Liskov’s principle I won’t get into here and I fear I’ve really spent too much time on it.

Liskov’s principle doesn’t matter.

What?

Yeah! I said it. (Technically the principle does matter, so I’m lying to you, but I’ll try to justify my lie.)

In PHP, if you follow three guidelines then you’re covered 99% of the time with Liskov.

1 - Use Interfaces

Use interfaces. Use them everywhere that makes sense. There’s not much overhead in adding interfaces and the result is that you have a “pure” level of abstraction that almost guarantees Liskov Substitution is followed.

2 - Keep implementation details out of interfaces

When you’re using interfaces, don’t have the interface expose any implementation details. Why would you have a UserAccountInterface provide any details on storage space left?

3 - Watch your type-checking code.

When you write code that operates differently on certain types, you may be breaking Liskov’s Substitution Principle (and probably several other SOLID principles).

Consider the following code:

 1 class PluginManager {
 2   protected $plugins; // array of plugins
 3 
 4   public function add(PluginInterface $plugin)
 5   {
 6     if ($plugin instanceof SessionHandler)
 7     {
 8       // Only add if user logged on.
 9       if ( ! Auth::check())
10       {
11         return;
12       }
13     }
14     $this->plugins[] = $plugin;
15   }
16 }

What’s incorrect about that piece of code? It breaks Liskov because the task performed is different depending on the object type. This is a common enough snippet of code and in a small application, in the spirit of getting stuff done, I’d be perfectly happy to let it slide.

But … why should an add() method get picky about what’s added. If you think about it, add()’s being a bit of a control freak. It needs to take a deep breath and give up control. (Hmmm, Inversion of Control)

Interface Segregation Principle

The ‘I’ in SOLID stands for the Interface Segregation Principle. Interface Segregation states:

“No client should be forced to depend on methods it does not use.”

In plain English this means don’t have bloated interfaces. If you follow the “Single Responsibility Principle” with your interfaces, then this usually isn’t an issue.

The app we’re designing here will be a small application and this principle probably won’t apply too much. Interface Segregation becomes more important the larger your application becomes.

Often this principle is violated with drivers. Let’s say you have a cache driver. At it’s simplest a cache is really nothing more than temporary storage for a data value. Thus a save() or put() method would be needed and a corresponding load() or get() method. But often what happens is the designer of the cache wants it to have extra bells and whistles and will design an interface like:

1 interface CacheInterface {
2   public function put($key, $value, $expires);
3   public function get($key);
4   public function clear($key);
5   public function clearAll();
6   public function getLastAccess($key);
7   public function getNumHits($key);
8   public function callBobForSomeCash();
9 }

Let’s pretend we implement the cache and realize that the getLastAccess() is impossible to implement because your storage doesn’t allow it. Likewise, getNumHits() is problematic. And we have no clue how to callBobForSomeCash(). Who is this Bob guy? And does he give cash to anyone that calls? When implementing the interface we decide to just throw exceptions.

 1 class StupidCache implements CacheInterface {
 2   public function put($key, $value, $expires) { ... }
 3   public function get($key) { ... }
 4   public function clear($key) { ... }
 5   public function clearAll() { ... }
 6   public function getLastAccess($key)
 7   {
 8     throw new BadMethodCallException('not implemented');
 9   }
10   public function getNumHits($key)
11   {
12     throw new BadMethodCallException('not implemented');
13   }
14   public function callBobForSomeCache()
15   {
16     throw new BadMethodCallException('not implemented');
17   }
18 }

Ugh. Ugly right?

That’s the crux of the Interface Segregation Principle. Instead, you should create smaller interfaces such as:

 1 interface CacheInterface {
 2   public function put($key, $value, $expires);
 3   public function get($key);
 4   public function clear($key);
 5   public function clearAll();
 6 }
 7 interface CacheTrackableInterface {
 8   public function getLastAccess($key);
 9   public function getNumHits($key);
10 }
11 interface CacheFromBobInterface {
12   public function callBobForSomeCash();
13 }

Make sense?

Dependency Inversion Principle

The final ‘D’ in SOLID stands for Dependency Inversion Principle. This states two things:

“A. High-level modules should not depend on low-level modules. Both should depend on abstractions.”

“B. Abstractions should not depend upon details. Details should depend upon abstractions.”

Great so what does this mean?

High-level
High-level code is usually more complex and relies on the functioning of low-level code.
Low-level
Low-level code performs basic, focused operations such as accessing the file system or managing a database.

There’s a spectrum between low-level and high-level. For example, I consider session management low-level code. Yet session management relies on other low-level code for session storage.

It’s useful to think of high-level and low-level in relation to each other. Session management is definitely lower than application specific functionality such as logging a user in, but session management is high-level to the database access layer.

I’ve heard people say … “Oh, Dependency Inversion is when you implement Inversion of Control.” or “No. Dependency Injection is what Dependency Inversion is.” Both answers are partially correct, because both answers can implement Dependency Inversion.

The Dependency Inversion Principle could be better stated as a technique of decoupling class dependencies. By decoupling, both the high-level logic and low-level objects don’t rely directly on each other, instead they rely on abstractions.

In the PHP world … Dependency Inversion is best achieved through what? You guessed it: interfaces.

Isn’t it interesting how all these design principles work together? And how often these principles bring into play that most unused of PHP constructs: the interface?

The Simple Rule of Dependency Inversion

Make objects your high-level code uses always be through interfaces. And have your low-level code implement those interfaces, and you’ve nailed this principle.

An Example

User authentication is a good example. At the highest level is the code that authenticates a user.

 1 <?php
 2 interface UserInterface {
 3   public function getPassword();
 4 }
 5 
 6 interface UserAuthRepositoryInterface {
 7   /**
 8    * Return UserInterface from the $username
 9    */
10   public function fetchByUsername($username);
11 }
12 
13 class UserAuth {
14   protected $repository;
15 
16   /**
17    * Inject repository dependency
18    */
19   public function __construct(UserAuthRepositoryInterface $repo)
20   {
21     $this->repository = $repo;
22   }
23 
24   /**
25    * Return true if the $username and $password are valid
26    */
27   public function isValid($username, $password)
28   {
29     $user = $this->repository->fetchByUsername($username);
30     if ($user and $user->getPassword() == $password)
31     {
32       return true;
33     }
34     return false;
35   }
36 }
37 ?>

So we have the high-level class UserAuth, relying on the abstractions of UserAuthRepositoryInterface and UserInterface. Now, implementing those two abstractions are almost trivial.

 1 <?php
 2 class User extends Eloquent implements UserInterface {
 3   public function getPassword()
 4   {
 5     return $this->password;
 6   }
 7 }
 8 class EloquentUserRepository implements UserAuthRepositoryInterface {
 9   public function fetchByUsername($username)
10   {
11     return User::where('username', '=', $username)->first();
12   }
13 }
14 ?>

Easy, peasey, lemon-squeezy.

Now, to use the UserAuth we would either construct it with the EloquentUserRepository or bind the interface to the EloquentUserRepository to automatically inject it.

Do not confuse the authentication examples used in this chapter with the Laravel Auth facade. These are just examples to illustrate the principle. Laravel’s implementation, though similar to these, is far better.