Visualising Website Performance with Flame Graphs
Using Multi-Byte Character Sets in PHP (Unicode, UTF-8, etc)
ENUMs, User Preferences, and the MySQL SET Datatype
Installing Xdebug for use with Eclipse or Netbeans on Linux
Development Resource Project
Nice n' Easy JQuery Image Rotator

Book Review: How to Implement Design Patterns in PHP

Sunday, 31 October 10, 10:29 pm
Matt Zadstra's book, PHP Objects, Patterns and Practice, aims to give an overview of sound OOP design in PHP applications, with a direct focus on Design Patterns. Design patterns describe high-level algorithms that form part or all of the application's software architecture.

Software Architecture

Software architecture relates to the high-level view of a system:
  • how it is organised into components
  • the relationships between the components and each other and the environment
  • the principles governing the system's design and evolution
In practice, the architecture of a system exists in the minds of the developers working on it, it is the expert devs' shared understanding of the system design. There may be documents and charts describing the architecture here and there, but these are often only an approximation or a subset of the true architecture which exists in the devs' heads. So architecture in the real world is a social thing, because it's that fuzzy understanding that's important.

Good architecture is important for the long-term success of a project. You could have two systems which both perform the same functions with the same reliability and speed, where one of them has a good architecture and the other does not. To the end user, there is not much to choose between two systems. It is as a project grows that the importance of a good architecture - that is, a good shared understanding of the design - becomes apparent, because it allows the system to be extended more easily and more robustly to better match the end users' needs.

Another definition you may come across for software architecture is "the decisions which need to be made early on". In practice, we don't know enough of the system early on to make the perfect design, so instead this might be better written as, "the decisions which you wish you could get right early on". More usefully, we can rephrase this as the decisions which are hard to change.

The Design Process

Until PHP5, OOP was not really possible with the language. Object and class support was sketchy, in many ways little more than a clumsy afterthought. Even now, the OOP mechanisms that exist are not complete, however they are at last adequate for the implementation of an entirely OOP design.

When starting the design process for new software, we usually start with a requirements analysis, where we examine what the system must achieve, what its scope will be (the domain it will operate on), and what its outputs should be.

In an OO system, we have a structure that lends itself to atomicity, encouraging us to divide and conquer our problem. We think about the data domain each object must work on, which often guides us when defining the object properties, and we focus on how our classes interact externally, which will often have some correspondence with the methods we finally implement.

The external interactions are our focus at this early stage, as opposed to the internal implementation which we worry about later. We can boil these interactions down into a defined interface that each class must conform to.

The interface defines a type, a class, and may itself use other types defined elsewhere.

We can also use inheritance where classes share qualities or behaviours to enhance the maintainability of our design.

In addition to these, there are many different types of relationship that we might define for our classes during the design process. A particular class might be composed of other classes or might manage a collection of another class. (see pp 98)

With OOP, we can break away from the rigid top-down, sequential control flow of yore and embrace more distributed organic arrangements.

Class Design

In OOP, we shouldn't get too hung up on a direct correspondence between objects in our system and the real world objects our system must deal with. While this often has some validity, and certainly can be a useful starting point, it can lead to clumsy bloated code as we try to make each object deal with everything required by its real-world counterpart.

For instance we may try to shoe-horn functionality for accessing a supplier's web service into a Product class that is already dealing with tracking inventory.

A better approach is to be clear on a class's primary function and to ensure it stays focussed on that. One rule of thumb is to keep your description of the class less than 25 words, avoid the use of 'and' or 'or'. If this becomes difficult, it's probably time to split functionality out into more classes.

Coupling

Coupling is used when discussing how intertwined elements of a system are with other elements. In a highly coupled system, changes in one area will frequently lead to changes in many other areas, scattered around the system as a whole.

Cohesion

A system with high cohesion is one where logically related functionality is physically grouped together. In OOP this generally means each class defies all the operations with clearly related logic.

Orthogonality

A well designed OOP system tightly defines the responsibility of all the components (ie classes) in a system and each component is logically independent of the system as a whole. This principle, of loose coupling and high cohesion, is termed 'orthogonality'.

Orthogonality is good, because it facilitates re-use without the need for refactoring the code. It also makes maintenance safer, because changes are localised to the components directly affected.

This localisation also serves to make the system more robust, as bugs should be limited in scope. How useful this is in practice is arguable however, as in certain cases at least, this property will tend to conceal bugs that would have been more obvious in a procedural system.

Polymorphism

Polymorphism is not just a silly word, it's also a cool and powerful tool in the OOP developer's workshop.

The principle is that a single interface is implemented by a whole set of classes.

This enables the whole family of classes to be handled by the same code - for instance, all can be accepted as an argument to a single method. (p104, and p129 ch8)

The Design Patterns

The principle of the Design Pattern is borrowed form the world of architecture, where they first appeared in the 70s.

The basic idea is that there are recurring themes which resurface in the solutions to many different problems, and these can be abstracted out to make them easier to apply by identifying their essential features. These recurring themes are formalised into the Design Patterns, and the concept was famously applied to the domain of computing problems by the Gang of Four.

Zadstra's book groups the patterns it looks at into 5 broad categories.

Patterns that Generate Objects

Singleton
Factory Method
Abstract Factory
Prototype

Patterns that Organise Objects

Composite

In the most general sense, Composition describes a data type that contains (ie is composed of) other data types. Classes themselves are examples of composition as they are usually made up of member variables of varying types. Object Composition is where objects contain instances of other objects, typically as private instance variables. It is often contrasted with inheritance, and is generally considered a preferable method of object organisation.

Decorator

The decorator pattern provides a flexible means to extend functionality of existing classes without the need for inheritance. The basic idea is to decorate another class, which can exist and be usable alone, by wrapping it inside the decorator class. The decorator attaches additional features to the wrapped class dynamically. The wrapper class can itself be wrapped inside another decorator of the same type in order to add multiple features to the wrapped class. Architecturally, the wrapped class will implement an interface (or an abstract class), and the interface (or abstract class) that the decorators implement will itself implement the wrapper interface.

Façade

Task-orientated Patterns

Interpreter

Strategy

In the strategy pattern (also known as the Policy pattern), the algorithm used is selected at runtime. These algorithms take the form of classes implementing a single interface.
Typical uses: Validation

Observer

An object, called the subject, keeps a list of its dependents - which are the Observers - and notifies them of any state changes. Typically this notification is done through a method on the observer.
Typical uses: Event handling in event driven software, where the subject is usually called an "event stream" and the observers are the "event sink".

Visitor

This pattern is suited for applications where you have a structure of unrelated objects - that is, a graph where nodes are represented by unrelated objects - and new types of operations to perform on each node are frequently added. This pattern allows you to add these new operations without making any changes to the classes that the nodes implement.

You create a visitor class for each of these operations and then traverse the object graph calling a method on each object, passing in the visitor. The visitor has one method for each type of object in the structure.

Command

In this pattern, the command object encapsulates all information needed to perform an action at a given time. When the command object wants to perform such an action, it invokes a method on the receiver object. An invoker object executes the command, and all three - command, receiver and invoker - are stored in a client object.

Enterprise Patterns

Registry
Front Controller
Application Controller
Page Controller
Template View and View Helper
Transaction Script
Domain Model

Database Patterns

Data Mapper
Identity Map
Unit of Work
Lazy Load
Domain Object factory
Identity Object
Selection Factory and Update Factory

Overall this is a good book that really gets you thinking about how you approach coding problems. It's well written and accessible, Zadstra comes across as an authoritative yet approachable author and he presents many ideas without waffle.

PHP Objects, Patterns and Practice, by Matt Zadstra, 2010, published by Apress.

Please enter your comment in the box below. Comments will be moderated before going live. Thanks for your feedback!

Cancel Post

/xkcd/ METAR