Design Patterns - a personal perspective

By Tony Marston

13th October 2004
Amended 21st October 2012

Introduction
- Context
- Problem
- Solution
Architectural Patterns
- Model-View-Controller (MVC)
- 3-Tier Architecture
Design Patterns - the theory
- Adapter
- Bridge
- Client-Dispatcher-Server
- Command Processor
- Data Access Object (DAO)
- Decorator
- Dependency Injection (aka Inversion of Control)
- Facade
- Factory Method
- Forwarder-Receiver
- Front Controller
- Iterator
- Master-Slave
- Observer (aka Publisher-Subscriber)
- Proxy
- Singleton
- Strategy
- View Handler
- Whole-Part
Idioms
A personal perspective
- Implementing the 3-Tier architecture
- Implementing the MVC design pattern
- Where are the Transaction Patterns?
- What are the benefits of Transaction Patterns?
Design Patterns - in practice
Conclusion
References
Amendment History

Introduction

The purpose of this document is not to describe individual patterns in great detail, nor is it any kind of tutorial. It is simply to give an overview of some of the various patterns that are available and to give my personal views on their implementation. As this section of my website is devoted to building web applications with PHP I shall concentrate on those patterns which can be readily applied to this environment.

What exactly are patterns? Patterns are supposed to help you build on the collective experience of skilled software engineers. They capture existing, well-proven experience in software development and help to promote good design practise. Every pattern deals with a specific, recurring problem in the design or implementation of a software system. Patterns can be said to exhibit the following properties:

This provides us with the following definition:

A pattern for software architecture describes a particular recurring design problem that arises in specific design contexts, and presents a well-proven generic scheme for its solution. The solution scheme is specified by describing its constituent components, their responsibilities and relationships, and the ways in which they collaborate.

This leads to the adoption of a three-part schema that underlines every pattern:

  1. Context - a situation giving rise to a problem.
  2. Problem - the recurring problem arising in that context.
  3. Solution - a proven resolution of that problem.

Context

Specifying the correct context for a pattern is difficult. It is practically impossible to determine all situations, both general and specific, in which a pattern may be applied. A more pragmatic approach is to list all known situations where a problem that is addressed by a particular pattern may occur.This does not guarantee that every situation in which a pattern may be relevant is covered, but at least it gives valuable guidance.

Problem

Identifying the problem begins with a general problem specification, capturing its very essence - what is the concrete design issue which is to be solved? This may be broken down into the following areas (or forces in the vocabulary of patterns):

These forces discuss the problem from various viewpoints and help in the understanding of its details. Forces may complement or contradict each other. Two contradictory forces are, for example, extensibility of a system versus minimisation of its code size. If you want your system to be extensible you may tend to use abstract superclasses. If you want to minimise code size, for example in an embedded application, you may not be able to afford such a luxury as abstract superclasses. More importantly, however, forces are the key to solving the problem. The better they are balanced, the better the solution to the problem. Detailed discussion of forces is therefore an essential part of the problem statement.

Solution

The solution part of a pattern shows how to solve the recurring problem, or better, how to balance the different forces which are associated with it. In software architecture such a solution includes two aspects:

It is important to note that the solution does not necessarily resolve all forces associated with the problem. It may focus on particular forces and leave others half or completely unresolved, especially if the forces are contradictory.


The accepted definition of design patterns goes something like this:

A pattern provides a solution schema rather than a fully-specified artifact or blueprint. You should be able to reuse the solution in many different implementations, but in a way that its essence is still retained. A pattern is a mental building block. After applying a pattern an architecture should include a particular structure that provides for the role specified by the pattern, but adjusted and tailored to the specific needs of the problem at hand. No two implementations of a given pattern are likely to be the same. It is also possible for a particular pattern to have several variants to cater for different circumstances.

The wikipedia article contains the following description:

In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situations. Patterns are formalized best practices that the programmer must implement themselves in the application.

That is the problem I have with design patterns - they provide descriptions of solutions instead of working code which can either be generated, copied or otherwise reused. They are vague and wishy-washy, without substance, and can be interpreted and implemented in many ways. If something is open to interpretation it is also open to over-interpretation and mis-interpretation. If something can be used it can also be mis-used. If no sample implementation is provided then there is no guarantee that a particular implementation will be effective. In the real world a pattern offers some sort of saving when used to make copies of an original, with each copy taking less time to build than the original. But if each implementation of a design pattern is unique and takes just as much time to build as the original, then where is the saving? Where is the reusability? It is not possible to write a code template for a design pattern and to generate implementations of that pattern from that template, so where is the saving, where is the reusability?

It should also be pointed out that attempting to use a design pattern may not provide beneficial results if the implementation is faulty. A language may provide several different ways of achieving a particular result, so the merits of each need to be examined against the context of the problem in hand - one may be faster, but another may be more extensible or easier to maintain.

You should also be aware that some of these patterns were designed with object-oriented programming languages in mind, so attempting to employ them with a non-OO language may not yield the results you expect. Some of them were designed to deal with the way in which a particular language works (such as a compiled language), so may be totally unnecessary in another language (such as a scripting language).


Architectural Patterns

Viable software architectures are built according to some overall structuring principle. These principles are described as architectural patterns. An architectural pattern expresses a fundamental structural organisation schema for software systems. It provides a set of predefined subsystems, specifies their responsibilities, and includes rules and guidelines for organising the relationships between them.


Model-View-Controller (MVC)

The Model-View-Controller (MVC) architectural pattern divides an interactive application into three components. It was originally developed to map the traditional input, processing and output roles into the GUI realm:

Input --> Processing --> Output
Controller --> Model --> View

Views and controllers together provide the user interface.

The model, view and controller are intimately related and in constant contact. Therefore, they must reference each other. The picture below illustrates the basic Model-View-Controller relationship:

Figure 1 - The basic MVC relationship

design-patterns-01 (3K)

The purpose of the MVC pattern is to separate the model from the view so that changes to the view can be implemented, or even additional views created, without having to refactor the model. Note that the model may or may not reference a persistent data store (database).

Note that although this pattern only shows three components it is possible to divide any one of them into smaller sub-components.

The RADICORE framework contains an implementation of the Model-View-Controller pattern.


3-Tier Architecture

Depending on which document you read the description of the 3 Tier architecture may vary:

  1. Some say that it is 'presentation - function - data'.
  2. Some say that in a client/server context it is 'client + application + database'.
  3. Some say that in a web context it is 'web browser + web application + database'.
  4. Some say that it is three layers of hardware, as in 'web server + application server + database server'.

Taking the last one first, although it is possible to physically deploy a software application over three layers of hardware, you must have divided the application code into three layers of software to begin with so that you actually have something that can occupy each piece of hardware. The former is known as physical 3-tier while the latter is known as logical 3-tier. It should be possible for a logical 3-tier application to be deployed on a single physical device as well as several devices. As hardware issues are outside the scope of this document I shall confine myself to logical 3-tier.

The first time I read about the 3-tier architecture was in 1999, and it is that description that I shall use in this document. It identified the following areas of logic:

These areas are also referred to as layers or tiers.

This pattern can be represented in the following diagram:

Figure 2 - The 3-Tier Architecture

design-patterns-02 (1K)

The presentation layer never talks to the data access layer directly - it talks only to the business layer. The business layer receives requests from the presentation layer, which may be:

Among the advantages of separating the application logic in this manner are:

  1. Maximises code reuse and minimises code duplication. For example, each business entity has a single component in the business layer, and all presentation layer components which want to access this business entity go through the same business layer component.
  2. It is possible to modify the application by making changes to just one tier, leaving the other two unaffected by the change. For example:
  3. As each tier is now independent of the other it becomes possible to use different sets of developers, with different skill sets, for each tier. This may reduce the need for multi-skilled developers. For example, you may have HTML/CSS/JavaScript developers for the presentation layer, and Java/PHP/ASP/whatever developers for the business layer, and SQL wizards for the data access layer.

Note that with this pattern you are not restricted to a single component within each layer. You can divide each layer into as many sub-layers as you wish.

If you think that the Model-View-Controller and 3-Tier patterns are the same thing then please read Aren't the MVC and 3-Tier architectures the same thing?. You can utilise just one of them, or implement both at the same time.

The RADICORE framework contains an implementation of both the 3 Tier Architecture and Model-View-Controller design patterns, as shown in the following diagram:

Figure 3 - MVC plus 3 Tier Architecture combined

model-view-controller-03a (5K)

Here you can clearly see where the two patterns overlap and complement each other.


Design Patterns - the theory

The subsystems of a software architecture, as well as the relationships between them, usually consist of several smaller architectural units. These units are described using design patterns. A design pattern provides a scheme for refining the subsystems or components of a software system, or the relationships between them. It describes a commonly-recurring structure of communicating components that solves a general design problem within a particular context. Design pattern address the sort of problems typically encountered after the overall structure of a software system has been specified.

An important property of all design patterns is that they are independent of a particular application domain. They deal with the structuring of application functionality, not with the implementation of the application functionality itself.

Below are standard descriptions of some common design patterns, which, if implemented properly, should give beneficial results. This is fine in theory, but in practice the results may not be as good as you expect.


Adapter

The Adapter design pattern provides a way for a client to use an object whose interface is different from the one expected by the client, without having to modify either. The Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

This pattern is suitable for solving issues that arise, for example, when:

  1. You want to replace one class with another and the interfaces do not match.
  2. you want to create a class that can interact with other classes without knowing their interfaces at design time.

Bridge

The Bridge design pattern decouples an abstraction from an implementation so that the two can vary independently.

When an abstraction can have one of several possible implementations, the usual way to accommodate them is to use inheritance. An abstract class defines the interface to the abstraction, and concrete subclasses implement it in different ways. But this approach is not always flexible enough. Inheritance binds an implementation to the abstraction permanently, which makes it difficult to modify, extend, and reuse abstractions and implementations independently.


Client-Dispatcher-Server

The Client-Dispatcher-Server design pattern introduces an intermediate layer between clients and servers, the dispatcher component. It provides location transparency by means of a name service, and hides the details of the establishment of the communication connection between clients and servers.

An example of this pattern would be an information retrieval system where the information providers are both on a local network and distributed over the world. To access an individual information provider it is necessary to specify its location and the service to be executed. When an information provider receives a request from a client application it runs the appropriate service and returns the requested information to the client.


Command Processor

The Command Processor design pattern separates the request for a service from its execution. A command processor component manages requests as separate objects, schedules their execution, and provides additional services such as the storing of request objects for later undo.

An example of this pattern would be a text editor which provides a way to deal with mistakes made by the user. A simple implementation would be to undo the most recent change, but a more attractive solution may be enable the undoing of multiple changes.


Data Access Object (DAO)

The DAO design pattern allows data access mechanisms to change independently of the code that uses the data. The Data Access Object manages the connection with the data source to obtain and store data.

An example of this design pattern is where an application might be deployed with a variety of database engines and where each of these engines has its own set of APIs. If all these APIs were to be isolated within a single object, one object per database engine, then switching from one database to another would be as simple as switching from one DAO to another.

Another variation is where the data may come from a variety of differences sources, such as DBMS, LDAP, XML repository, et cetera. By routing all access through a DAO the client need not be concerned about the physical location of the data, or which APIs to use in order to access it.

The Radicore framework contains an implementation of the DAO in the form of a DML Class.


Decorator

The Decorator design pattern dynamically attaches additional responsibilities to an object. Decorators provide a flexible alternative to subclassing for extending functionality.

Sometimes we want to add responsibilities to individual objects, not to an entire class. A graphical user interface toolkit, for example, should let you add properties like borders or behaviors like scrolling to any user interface component. One way to add responsibilities is with inheritance. Inheriting a border from another class puts a border around every subclass instance. A more flexible approach is to enclose the component in another object that adds the border. The enclosing object is called a decorator.


Dependency Injection (aka Inversion of Control)

The Dependency Injection pattern (also known as Inversion of Control) manages the dependencies between objects by creating the dependent objects outside the object which uses that dependency. In other words instead of objects configuring themselves they are configured by an external entity.

If Object A calls Object B, then A is dependent on B. The usual method is to allow Object A to instantiate Object B just before it needs to use it, but this design pattern allows an instance of Object B to be created independently of Object A so it can be "injected" into Object A.

Read why I think dependency injection is evil.


Facade

The Facade design pattern provides a unified interface to a set of interfaces in a subsystem. A facade defines a higher-level interface that makes the subsystem easier to use.

As an example look at the structure of client classes and subsystem classes in the following diagram:

Figure 4 - Interfaces without a Facade

design-patterns-04 (1K)

To simplify access to the subsystem you can route everything through a facade, as shown in the following diagram:

Figure 5 - Interfaces with a Facade

design-patterns-05 (1K)

Factory Method

The Factory Method design pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. The Factory Method lets a class defer instantiation to subclasses.

An example of this pattern would be a class to read image files and make thumbnails out of them, where each type of image file (.gif, .jpg, .png, .tif, et cetera) would require different code. It would be possible to put all the code into a single class, as shown in the following code snippet:

1 - A bad way to design the ImageReader

public class ImageReader
{
  private int FileType;
  private String FileContents;
  private byte[] DecodedImage;

  public ImageReader( InputStream in )
  {
    // Figure out what type of file this input stream represents
    // (eg gif, jpeg, png, tif, etc )
    FileType = file_type;

    decodeFile();
  }

  private decodeFile()
  {
    switch( FileType )
    {
      case ImageReader.GIF:
        // do gif decoding (many lines)
        break;

      case ImageReader.JPEG:
        // do jpeg decoding (many lines)
        break;

      case ImageReader.PNG:
        // do png decoding (many lines)
        break;

      // etc...

    }
  }
}

This method has the advantage of abstracting the file type from the class that calls this ImageReader, but as the number of file types supported gets larger, the code will quickly become huge, unwieldy and hard to maintain. A much better method would be to extract the code for each file type and put it into a class of its own, as shown in the following code snippet:

2 - A good design for the ImageReader: The Factory design pattern

public class ImageReaderFactory
{
  public static ImageReader getImageReader( InputStream is )
  {
    int ImageType = figureOutImageType( is );

    switch( ImageType )
    {
      case ImageReaderFactory.GIF:
        GifReader r = new GifReader( is );
        return( (ImageReader)r );
        break;

      case ImageReaderFactory.JPEG:
        JpegReader r = new JpegReader( is );
        return( (ImageReader)r );
        break;

    // etc.

    }
  }
}

Forwarder-Receiver

The Forwarder-Receiver design pattern provides transparent inter-process communication for software systems with a peer-to-peer interaction model. It introduces forwarders and receivers to decouple peers from the underlying communication mechanism.

Distributed peers collaborate to solve a particular problem. A peer may act as a client, requesting services, as a server, providing services, or both. The details of the underlying inter-process communication mechanism for sending or receiving messages (such as TCP/IP, sockets or message queues) are hidden from the peers by encapsulating all system-specific functionality into separate components. Examples of such functionality are the mapping of names to physical locations, the establishment of communication channels, or the marshaling and unmarshaling of messages.


Front Controller

The Front Controller design pattern defines a single component that is responsible for processing application requests. A front controller centralizes functions such as view selection, security, and templating, and applies them consistently across all pages or views. Consequently, when the behavior of these functions need to change, only a small part of the application needs to be changed: the controller and its helper classes.

This may be useful in interactive Web applications which are composed of brittle collections of interdependent Web pages as such applications may be hard to maintain and extend.


Iterator

The Iterator design pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation. This is useful if an aggregate can exist in several possible forms.

Depending on the form of the aggregate in question, the actual instructions required to navigate through the aggregation may vary. This means that the client code must know which form of aggregate is being used so that it can issue the correct instruction. The Iterator pattern bypasses this requirement by allowing the client to use standard commands, such as NEXT or PREVIOUS, with the Iterator then taking the responsibility of issuing the correct command for that form of aggregate.


Master-Slave

The Master-Slave design pattern supports fault tolerance, parallel computation and computational accuracy. A master component distributes work to identical slave components and computes a final result from the results these slaves return.

An example of this pattern would be the travelling salesman problem, which is well known in graph theory. The task is to find an optimal round trip between a given set of locations, such as the shortest trip that visits each location only once. The solution involves identifying a number of possibilities, then creating a slave component for each of these possibilities. The master component can then examine the results from each of the slaves in order to pick out the best one.


Observer (aka Publisher-Subscriber)

The Observer (or Publisher-Subscriber) design pattern helps to keep the state of cooperating components synchronised. To achieve this it enables one-way propagation of changes; one publisher notifies any number of subscribers about changes to its state.

One dedicated component takes the role of the publisher. All components dependent on changes in the publisher are its subscribers. The publisher maintains a registry of currently-subscribed components. Whenever a component wants to become a subscriber, it uses the subscribe interface offered by the publisher. Analogously, it can unsubscribe. Whenever the publisher changes state, it sends a notification to all its subscribers. The subscribers in turn retrieve the changed data at their discretion.


Proxy

The Proxy design pattern makes the clients of a component communicate with a representative rather than to the component itself. Introducing such a placeholder can serve many purposes, including enhanced efficiency, easier access and protection from unauthorised access.

The generic Proxy pattern can have such variants as:


Singleton

The Singleton design pattern ensures that a class only has one instance, and provides a single point of access to it.

A global variable could be used, but although it does make the object accessible it does not keep you from instantiating multiple objects. A better solution is to make the class itself responsible for keeping track of its sole instance. The class can ensure that no other instance can be created by intercepting requests to create new objects, and it can provide a way to access the instance.

The Radicore framework contains an implementation of the Singleton pattern.


Strategy

The Strategy design pattern defines a set of algorithms, encapsulates each one, and makes them interchangeable. The Strategy pattern lets the algorithm vary independently from clients that use it.

There are several advantages to doing this. First, if you have several different behaviours that you want an object to perform, it is much simpler to keep track of them if each behaviour is a separate class, and not buried in the body of some method. Should you ever want to add, remove, or change any of the behaviours, it is a much simpler task, since each one is its own class. Each such behaviour or algorithm encapsulated into its own class is called a Strategy.


View Handler

The View Handler design pattern helps to manage all views that a software system provides. A view handler component allows clients to open, manipulate and dispose of views. It also coordinates dependencies between views and organises their update.

An example of this pattern would be a multi-document editor which allows several documents to be worked on simultaneously. Each document is displayed in its own window. To use such editors effectively users need support for handling the windows. For example, they might want to clone a window to work with several independent views of the same document. User also often do not close open windows before quitting the editor, so it is the task of the editor to keep track of all open documents and close them carefully. Changes in one window may affect other windows as well, so there is a need for an efficient update mechanism for propagating changes between windows.


Whole-Part

The Whole-Part design pattern helps with the aggregation of components that together form a semantic unit. An aggregate component, the Whole, encapsulates it constituent components, the Parts, organises their collaboration, and provides a common interface to its functionality. Direct access to the Parts is not possible.

An example of this pattern would be a computer-aided design (CAD) system for 2-D and 3-D modelling which allows engineers to design graphical objects interactively. In such systems most graphical objects are modelled as compositions of other objects. For example, a car object aggregates several smaller objects such as wheels and windows, which themselves may be composed of even smaller objects such as such as circles and polygons. It is the responsibility of the car object to implement functionality that operates on the car as a whole, such as rotating or drawing.


Idioms

Idioms deal with the implementation of particular design issues. An idiom is a low-level pattern specific to a particular programming language. An idiom describes how to implement particular aspects of components or the relationships between them using the features of the given language.

Idioms represent the lowest-level patterns. They address aspects of both design and implementation. Most idioms are language-specific - they capture existing programming experience. Often the same idiom looks different in different languages, and sometimes an idiom that is useful for one programming language does not make sense to another. For example, the C++ community uses reference counting idioms to manage dynamically allocated resources, while Smalltalk provides a garbage collection mechanism and therefore has no need for such idioms.

Idioms can also address low-level problems related to the use of a language, such as the naming of program elements, the formatting of source text or the choice of return values. Such idioms approach or overlap areas that are typically addressed by programming guidelines. A collection of related idioms defines a programming style. Idioms demonstrate competent use of programming language features, and can therefore also support the teaching of a programming language. They also ease communication among developers and speed up software development and maintenance.

As this is such a huge topic and very much language-independent I shall not delve into any details.


A personal perspective

My biggest criticism of design patterns is that the are not proper patterns, just descriptions or outlines of possible patterns. The dictionary definition for "pattern" contains the following:

Knitting patterns and sewing patterns are examples of "real" patterns. They are blueprints from which copies can be made. When the original is constructed a lot of effort goes into the making of the pattern so that less effort is required when making each copy.

The authors of design patterns state quite openly that a design pattern is not a template or blueprint, it is just the description of a possible solution which you have to implement yourself. But how useful is that? Are there any actual savings to be made by using design patterns as against not using them? Software development requires program code, yet the implementation of design patterns does not seem to involve the generation of reusable code. This means that different implementations of the same pattern do not have any common code which can be shared, therefore each implementation has to be crafted by hand. If patterns are supposed to provide some element of reusability so that subsequent implementations can be produced with less effort than the first, then where is this reusability provided with design patterns?

I am not the only one to notice this anomaly. The following statement can be found in PatternBacklash:

In software engineering, duplication of something is often considered a sign that more abstraction or factoring is needed. Duplication should generally be refactored into one or fewer spots to simplify the code and localize changes to one or fewer spots. In other words, why do patterns have to be duplicated instead of just referenced for each usage? Do GOF patterns represent unnecessary duplication?

Compare design patterns with a Painting By Numbers kit. In the kit you get sheets of paper on which there are collections of shapes, each containing a number, and a collection of colours which are numbered. All the budding artist has to do is put the right color into each shape and the result is guaranteed. With design patterns you don't get pre-drawn shapes and numbered colours, you simply get descriptions of shapes and colours. The budding artist then has to pick his own shapes and his own colours. How useful is that?

I have never heard of any tool which allows a fully fledged component to be created simply by saying "combine design pattern X with object Y and generate component Z", and this just proves to me that there is very little of any design pattern which can actually be reused - it may describe an outline of a solution, but you still have to build every part of that solution by hand. To circumvent this limitation you need a different sort of pattern altogether, which is where Transaction Patterns distinguish themselves. They are "real" patterns insofar as code templates actually exist, which enables working components to be created simply by saying "combine transaction pattern X with object Y and generate component Z". Most of the component logic is inherited or imported from the original pattern definition, so there is little or nothing left over which has to be crafted by hand. This provides a much higher level of reusability than can ever be obtained from design patterns.

Some people say that design patterns are nothing more than a common language that programmers can use among themselves when discussing their solutions, but this notion falls down on several points:

This means that you can talk to a group of programmers about design patterns and they will begin arguing about their names, which patterns to use to solve a particular problem, and whose implementation is the most "pure" or "correct". Therefore it is safe to say that patterns do not provide a common language which is universally accepted - they are just a source of yet another set of religious arguments.

Although I agree that design patterns have their place (I have to say that as I have used and actively promoted some of them), I do not believe that slavishly following a set of design patterns is necessarily beneficial, just as I do not believe that slavishly following the OO paradigm is the only way to write effective programs. A good design will always be better than a bad design, a normalised database will always perform better than an un-normalised database, structured code will always be easier to maintain that unstructured code, and good procedural code will always be better than bad OO code. So where is the benefit from using design patterns? In my experience all the successful projects on which I worked were not centered around design patterns, yet the one project which was an abject failure was specifically designed to use the architect's favourite set of patterns. So using design patterns can contribute to the failure of a project, and not using design patterns can contribute to the success of a project.

Some of those design patterns have little relevance with PHP. For example, the iterator pattern is hardly relevant as PHP does not have a wide selection of aggregations - it just has arrays. I have heard some people say that the process of pagination in a web page is a prime example of the iterator pattern, therefore it should be implemented in a single class. This is utter nonsense. Pagination requires some processing in each of the presentation, business and data access layers, therefore it cannot be implemented in a single object. See How do you deal with pagination? for details. Some people also say that a database result set is a prime candidate for an iterator object because each DBMS has its own APIs to move through that result set. In my infrastructure the Data Access Object automatically converts the result set into an array before any data is passed back, so any potential problem no longer exists.

Patterns which allow an object to keep multiple views synchronised, such as the observer and view handler patterns, are hardly relevant in a web environment as there is only ever a single view at any one time - the web page (HTML document). If I want the data output in a different format, such as PDF or CSV, then I use a different view object in a different transaction.

Although I agree that the singleton pattern has its uses, I consider the front controller to be a complete waste of time - see Why don't you use a Front Controller? for details.

I have successfully implemented the 3-Tier architecture in two different languages (UNIFACE and PHP), and have implemented the Model-View-Controller design pattern in PHP. I must warn you though that my implementations are totally unique and are not considered to be 'politically correct' in some circles. See below for details.


Implementing the 3-Tier architecture

Some people think that every web application is automatically 3-tier, but that is also complete hogwash. Read Surely every web application is automatically 3-tier? for the reasons why.

Some other people seem to think that it is impossible to implement the 3-Tier architecture in a language that is not object-oriented, but that is complete hogwash. How do I know? Because I have done it.

For many years as a COBOL programmer I was used to developing in a 1-tier architecture where presentation, business and data access logic coexisted within the same program. Then in the early 1990s I switched to a non-OO 4th Generation Language (4GL) called UNIFACE where all data access was performed through an interchangeable database driver. The components we developed consisted of nothing more than presentation and business logic, which made it a 2-tier architecture. There was no easy method of separating these two areas of logic as the methods available to transmit the data between a presentation component and a business component were extremely primitive. Compared with PHP the array processing in UNIFACE is like something out of the stone age. An attempt was made to address this shortcoming in version 7.2.04 when the language authors implemented a type of component for the business layer known as an Object Service. I tried using this within my test environment, but the results were less than satisfactory.

Then in 1999 I was head hunted by a company who were trying to build a new application in UNIFACE using the 3-tier architecture. I was supposedly recruited because of my experience, especially with the creation of development infrastructures, but when I joined the team they promptly ignored everything I had to say. The members of the team were a motley crew:

These six 'experts' spent six months in developing a 3-tier infrastructure that they thought was the best thing since sliced bread. Their design incorporated all the right patterns such as 'controller', 'decorator', 'facade', 'bridge', 'view', 'translator', 'presentation object', 'business object' and 'data access object', so what could possibly go wrong? To quote a famous doctor: The operation was a success, but the patient died. I had warned them beforehand that in my not-so-humble opinion their infrastructure was far too complicated and far too cumbersome and was doomed to failure, but they refused to listen. After all, they were 'experts' and they 'knew best'. What was blindingly obvious to me suddenly became visible to them when it came to build the first live transactions using this infrastructure - the process took far, far longer than they had scheduled. The first two screens to be built were a LIST screen and a SEARCH screen, and it took -- wait for it -- two developers a total of 10 days. With a bit of fine tuning they managed to get it down to one developer for 10 days, but that was the best they could do. When these times were extrapolated across the remainder of the system they suddenly became aware that the project would be 6 months overdue and £2 million over budget. When these figures were relayed to the client he took the first sensible decision in the history of the project - he cancelled it on the spot.

The development team was disbanded, so I was sent back to my company's local office. While waiting for reassignment I decided to update my personal development environment from 2-tier to 3-tier and to replicate those first two live screens. I was so successful that within 2 weeks not only had I got the LIST and SEARCH screens working, but also the INSERT, UPDATE, ENQUIRE and DELETE screens as well. So what those 'experts' had failed to achieve in 3 man-years I managed to polish off in 2 man-weeks. I informed them of my success, but was told your results don't count as your methods are wrong. Not wishing to continue life as a proctologist (someone who works with a***holes) I quit.

How was it that my efforts were a success while theirs were an abject failure? Perhaps it was a total difference in attitude:

After having used a successful implementation of the 3-Tier architecture to develop components I could definitely see the benefits, so when I began developing in PHP I sought a similar architecture. Because there was nothing pre-existing that satisfied my requirements I decided to build my own. My implementation is documented in A Development Infrastructure for PHP.


Implementing the MVC design pattern

If you think that the Model-View-Controller and 3-tier patterns are the same thing then please read Aren't the MVC and 3-Tier architectures the same thing?. You can utilise just one of them, or implement both at the same time.

When I built my original infrastructure using the 3-Tier architecture I ended up with database classes in the business layer, a DML class in the data access layer, but in the presentation layer I avoided classes as I wanted all my HTML output to be generated from XSL transformations. This made the PHP code for each page very simple as all it had to do was as follows:

The advantage of using XSL transformations to build all HTML output is that all the logic for building each web page is entirely separate from the logic which obtains the data to go into that web page. When a colleague looked at my code he remarked that it was a perfect example of the MVC design pattern. At first I disbelieved him because I had seen samples of code used to implement this pattern, and my code was completely different. Then I did some research to discover the principles of the MVC design pattern rather than the details of particular implementations, and I discovered that my code did in fact follow those principles quite closely. I had separate components which could definitely be identified as being part of either the Model, the View or the Controller.

Following a set of principles by inventing my own implementations is nothing new to me. When I documented my method of using classes to access database tables I received a lot of criticism from self-styled OO purists who said your implementation is wrong, real OO programmers don't do it that way. I found their arguments quite amusing, so I put them all, along with my responses, in a document entitled What is/is not considered to be good OO programming.


Where are the Transaction Patterns?

All the patterns mentioned so far fall into one of two categories:

  1. Architectural patterns which provide a framework to contain all the transactions within an application.
  2. Design patterns which may be combined to build individual transactions.

While many people regard design patterns as the ultimate in building blocks for application development, for me they are entirely the wrong level of abstraction as they provide very little in the way of reusable code. A design pattern may describe an outline of a solution, but you still have to build every part of that solution by hand. It may be acceptable to describe an application framework in terms of the design patterns which it uses, but when describing the application transactions which are built on top of that framework I have found that a totally different vocabulary is needed.

A typical CRUD application is made up of a number of different user transactions (application components), each of which has a user interface (UI, page, screen) which allows the user to perform some operation (Create/Read/Update/Delete) on one or more tables in the application database. When describing a transaction to a user, and to the programmer who will build it, it is simply a case of "this is what it looks like and this is what it does", and not "these are the design patterns which it uses".

Although each transaction is different, after having built a number of transactions it may be possible to spot some similarities between one transaction and another. Take the following situation:

That phrase "does exactly the same thing" should trigger in your mind that there is something in common between these two transactions, and you should immediately be asking yourself "how much of the code in transaction #1 can I reuse in transaction #2?" An inexperienced programmer may say that very little is reusable because each piece of code has a different set of object names hard-coded into it, but a wiser programmer will be able to see where that code can be converted into a subroutine which will accept a list of object names as parameters. That single subroutine can then be referenced any number of times with different lists to carry out that common processing on different objects.

Rather than look at the inside of a transaction, the code, for areas of commonality, a different approach would be to look at it from the outside, the user interface. As the same effect can be achieved by any number of variations in the code, looking at the code may result in the situation where you cannot see the wood for the trees, you cannot see "the big picture". If you look carefully at a transaction, any transaction, you should be able to describe it in terms of the following:

A particular pattern can be described in terms of its structure and behaviour, and it can be turned into a working transaction by adding in the missing ingredient, which is content. Using the subroutine analogy, the pattern (structure and behaviour) can be regarded as a subroutine and the content (list of data names and their values) can be regarded as its parameters. The reason for separating structure from behaviour it is to make it possible for different patterns to share the same structure but to have different behaviour. It then becomes possible to define transactions in terms of the transaction patterns which they use, such as:

Some people may be able to see the advantage of being able to describe transactions in this way, but they may not be able to see that any further benefits can be gained, which is where they would be quite wrong. Taking the previous example where transaction #1 is similar to transaction #2, what are the programmer's options for actually building transaction #2? Typically only two options are available:

  1. Write transaction #2 from scratch and ignore transaction #1 completely.
  2. Take a copy of transaction #1, and change all the references for table 'A' to table 'B'.

Does that sound familiar? Option (2) is quicker than option (1) but it still involves a great deal of effort and allows errors to creep in. But supposing there is a third option, one that cuts out all that effort and reduces the possibility of errors? Those of you with more than two brain cells to rub together may be able to see that transaction patterns not only provide a different means for describing transactions, but they can also provide a means of implementing transactions as easily as saying:

Create transaction #27 by implementing pattern L1 with database table 'C'.

This means that the code which implements the pattern does not have to be generated by hand, instead an existing block of pre-written code is referenced, merged with the relevant data, and a working transaction is instantly available. But how can it be possible for patterns to be implemented in such a manner? This depends entirely on the language which is being used:

Do you see the benefit of having such a mechanism? This functionality now exists within the RADICORE framework, and allows the developer to create working transactions in just three simple steps:

  1. Select a database table.
  2. Select a transaction pattern.
  3. Confirm the pattern details and press a button.

This means that starting with nothing more than a database schema it is possible for the RADICORE framework to generate and run all the components for maintaining the tables within that schema without having to write a single line of code. It is possible to customise the generated code afterwards, but at least all the ground work has been done for you.

Where are the code generation facilities with design patterns?


What are the benefits of Transaction Patterns?

A properly crafted set of transaction patterns, with an implementation mechanism, can save time in a large number of different areas:

If you want to obtain the benefits that transaction patterns can provide then the first step you must take is to recognise that they exist. This will be a physical impossibility to those who insist that design patterns are the center of their universe and to even think that something else exists, let alone could be better, is pure heresy.

These points are explored in greater detail in What are Transaction Patterns?


Design Patterns - in practice

Question: What is the difference between theory and practice?
Answer: In theory there is no difference, but in practice there is.

Regardless of how patterns were expected to be used by their designers, it is impossible to guarantee that they will be used only as intended. There are plenty of people out their who have more imagination than intelligence, and even though they may think that they have done a good job in theory by implementing a particular pattern in a particular way for a particular set of circumstances, in practice the results may be less than optimal (which is a polite way of saying "a pile of poo").

Below are some real-world patterns taken from Resign Patterns - Ailments of Unsuitable Project-Disoriented Software written by Michael Duell and published in 1997.

  1. Cremational patterns
    1.1 Abject Poverty
    The Abject Poverty Pattern is evident in software that is so difficult to test and maintain that doing so results in massive budget overruns.
    1.2 Blinder
    The Blinder Pattern is an expedient solution to a problem without regard for future changes in requirements. It is unclear as to whether the Blinder is named for the blinders worn by the software designer during the coding phase, or the desire to gouge his eyes out during the maintenance phase.
    1.3 Fallacy Method
    The Fallacy method is evident in handling corner cases. The logic looks correct, but if anyone actually bothers to test it, or if a corner case occurs, the Fallacy of the logic will become known.
    1.4 ProtoTry
    The ProtoTry Pattern is a quick and dirty attempt to develop a working model of software. The original intent is to rewrite the ProtoTry, using lessons learned, but schedules never permit. The ProtoTry is also known as legacy code.
    1.5 Simpleton
    The Simpleton Pattern is an extremely complex pattern used for the most trivial of tasks. The Simpleton is an accurate indicator of the skill level of its creator.
  2. Destructural Patterns
    2.1 Adopter
    The Adopter Pattern provides a home for orphaned functions. The result is a large family of functions that don't look anything alike, whose only relation to one another is through the Adopter.
    2.2 Brig
    The Brig Pattern is a container class for bad software. Also known as module.
    2.3 Compromise
    The Compromise Pattern is used to balance the forces of schedule vs. quality. The result is software of inferior quality that is still late.
    2.4 Detonator
    The Detonator is extremely common, but often undetected. A common example is the calculations based on a 2 digit year field. This bomb is out there, and waiting to explode!
    2.5 Fromage
    The Fromage Pattern is often full of holes. Fromage consists of cheesy little software tricks that make portability impossible. The older this pattern gets, the riper it smells.
    2.6 Flypaper
    The Flypaper Pattern is written by one designer and maintained by another. The designer maintaining the Flypaper Pattern finds herself stuck, and will likely perish before getting loose.
    2.7 ePoxy
    The ePoxy Pattern is evident in tightly coupled software modules. As coupling between modules increases, there appears to be an epoxy bond between them.
  3. Misbehavioral Patterns
    3.1 Chain of Possibilities
    The Chain of Possibilities Pattern is evident in big, poorly documented modules. Nobody is sure of the full extent of its functionality, but the possibilities seem endless. Also known as Non-Deterministic.
    3.2 Commando
    The Commando Pattern is used to get in and out quick, and get the job done. This pattern can break any encapsulation to accomplish its mission. It takes no prisoners.
    3.3 Intersperser
    The Intersperser Pattern scatters pieces of functionality throughout a system, making a function impossible to test, modify, or understand.
    3.4 Instigator
    The Instigator Pattern is seemingly benign, but wreaks havoc on other parts of the software system.
    3.5 Momentum
    The Momentum Pattern grows exponentially, increasing size, memory requirements, complexity, and processing time.
    3.6 Medicator
    The Medicator Pattern is a real time hog that makes the rest of the system appear to be medicated with strong sedatives.
    3.7 Absolver
    The Absolver Pattern is evident in problem ridden code developed by former employees. So many historical problems have been traced to this software that current employees can absolve their software of blame by claiming that the absolver is responsible for any problem reported. Also known as It's-not-in-my-code.
    3.8 Stake
    The Stake Pattern is evident in problem ridden software written by designers who have since chosen the management ladder. Although fraught with problems, the manager's stake in this software is too high to allow anyone to rewrite it, as it represents the pinnacle of the manager's technical achievement.
    3.9 Eulogy
    The Eulogy Pattern is eventually used on all projects employing the other 22 Resign Patterns. Also known as Post Mortem.
    3.10 Tempest Method
    The Tempest Method is used in the last few days before software delivery. The Tempest Method is characterized by lack of comments, and introduction of several Detonator Patterns.
    3.11 Visitor From Hell
    The Visitor From Hell Pattern is coincident with the absence of run time bounds checking on arrays. Inevitably, at least one control loop per system will have a Visitor From Hell Pattern that will overwrite critical data.

Conclusion

As well as knowing what design patterns are, it is also important to know what they are NOT:

The GOF book actually contains the following caveat:

Design patterns should not be applied indiscriminately. Often they achieve flexibility and variability by introducing additional levels of indirection, and that can complicate a design and/or cost you some performance. A design pattern should only be applied when the flexibility it affords is actually needed.

This habit of (theoretically) solving a problem by adding on another layer of indirection or abstraction is often over-used. A quote usually attributed either to David Wheeler or Butler Lampson reads as follows:

There is no problem in computer science that cannot be solved by adding another layer of indirection, except having too many layers of indirection.

A heavy reliance on design patterns will not necessarily make you a better programmer or make your application a better application. Consider the following:

In the article How to use Design Patterns there is this quote from Erich Gamma, one of the authors of the GOF book:

Do not start immediately throwing patterns into a design, but use them as you go and understand more of the problem. Because of this I really like to use patterns after the fact, refactoring to patterns.

This sentiment is echoed in the article Design Patterns: Mogwai or Gremlins? by Dustin Marx:

The best use of design patterns occurs when a developer applies them naturally based on experience when need is observed rather than forcing their use.

In the blog post When are design patterns the problem instead of the solution? T. E. D. wrote:

My problem with patterns is that there seems to be a central lie at the core of the concept: The idea that if you can somehow categorize the code experts write, then anyone can write expert code by just recognizing and mechanically applying the categories. That sounds great to managers, as expert software designers are relatively rare. The problem is that it isn't true.

The truth is that you can't write expert-quality code with "design patterns" any more than you can design your own professional fashion designer-quality clothing using only sewing patterns.

Just because you implement a pattern written by an expert does not automatically mean that your implementation is exactly the same quality as that which the expert would write. The implementation is yours, not that of the expert, so the quality of the implementation is down to your skills and not those of the expert.

You should also be aware that there is no single collection of patterns that means all things to all men. Many books have been written by different authors, and for a particular problem each book may contain a variety of alternative patterns. Some developers have a tendency to get locked in to a particular set of patterns from a particular author, and they judge other people's work by comparing it with their implementation of these particular patterns. A common criticism of my work by so-called 'experts' is that it fails to implement pattern 'so-and-so' correctly. For a prime example take this comment from lastcraft:

There is nothing innovative in your system except where you have committed some kind of random design error. The table data gateway and row data gateway patterns are the most primitive of all, but somehow you still managed to mix them into a confusing mess. You have used a TransformView over a TemplateView in the one and only set up where it's complete overkill. TransformView is way more infrastructure than templating and poses restrictions on the skills of the developers and designers.

My response to comments such as these is quite simple:

I believe that it is a good idea for every developer to be aware of design patterns, but it is also important to know how and when to use them. If you implement the right patterns in an intelligent fashion then the results can be well worth the effort, but the converse is also true. The wrong pattern, or a badly implemented pattern, may yield little or even negative benefit. A design pattern is not the *ONLY* solution to a given problem, and in some cases it may not even be the *BEST* solution. Instead of solving some hypothetical problems, the use of design patterns may simply move the problem from one piece of code to another, or may even introduce a new set of problems. I have seen cases where a working solution, which was not based on any particular patterns, was turned into a slow-running and difficult-to-maintain mess simply because some idiot-who-should-have-known-better insisted that without the use of design patterns, and lots of them, the solution was not "proper", it was not "pure", it was not "fashionable".

Anything which can be used can also be over-used, mis-used or even ab-used, and design patterns are no exception. Some programmers use a design pattern just because it is there instead of when they have a problem which is addressed by that pattern. I have even heard of programmers whose ambition it is to write a program containing every single design pattern that they know of. Where some patterns are supposed to be appropriate for only a particular set of circumstances, there are some programmers who insist on using those patterns in all possible circumstances. Take the factory pattern for example. This is only supposed to be used when you want to instantiate an object from one of several classes, so why do some programmers insist on using a factory for every object even when there is only one possible class? Why do some programmers never stop with a single factory and think it would be 'cool' to have multiple layers of factory)?

Those programmers who brag about the number of design patterns they use are barking up the wrong tree as far as I am concerned - I am decidedly unimpressed, underwhelmed, uninspired and uninterested. It is not the number of patterns you implement but how you implement them that makes an impact. I consider design patterns to be nothing more than a guide for beginners, much like training wheels on a bicycle or a painting-by-numbers kit for a budding artist. They are there to teach the basics, but once learned they should be discarded otherwise they become a limitation instead of an inspiration.

In my humble opinion those code monkeys who think that design patterns are the best thing since sliced bread are not as clever as they think and are simply using design patterns as a crutch to hide their lack of knowledge and ability.


References

Books:

Internet:


© Tony Marston
13th October 2004

http://www.tonymarston.net
http://www.radicore.org

Amendment history:

21 Oct 2012 Added Design Patterns - in practice.
03 June 2011 Added Dependency Injection (aka Inversion of Control).
18 Oct 2006 Amended Where are the Transaction Patterns? to link to a tutorial which describes the new Transaction Generation procedure within the Radicore framework.
25 May 2006 Amended Where are the Transaction Patterns? to link to a new document entitled What are Transaction Patterns?

counter