In a previous article entitled Design Patterns - a personal perspective I criticised design patterns for not being "real" patterns. The dictionary definition for "pattern" contains the following:
With a "real" pattern you can make duplicate copies using less effort than it took to make the original, but with design patterns there is no such saving. When developing computer software the greatest savings can be made by having pre-written and reusable code at your disposal, but design patterns do not provide any reusable code, only the description of a solution which you have to hand craft yourself. 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. I am not the only one to notice this defect. 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?
Paul Graham, in his essay Revenge of the Nerds, wrote:
If you try to solve a hard problem, the question is not whether you will use a powerful enough language, but whether you will (a) use a powerful language, (b) write a de facto interpreter for one, or (c) yourself become a human compiler for one.
This practice is not only common, but institutionalized. For example, in the OO world you hear a good deal about "patterns". I wonder if these patterns are not sometimes evidence of case (c), the human compiler, at work.
When I see patterns in my programs, I consider it a sign of trouble. The shape of a program should reflect only the problem it needs to solve. Any other regularity in the code is a sign, to me at least, that I'm using abstractions that aren't powerful enough - often that I'm generating by hand the expansions of some macro that I need to write.
In the blog post When are design patterns the problem instead of the solution? Edgar Holleis wrote:
It is logical to use common strategies to solve recurring problems. In really abstract languages it is possible to formalize those strategies and put them into a library. Whenever you need to use them, you merely #include them, instantiate them, expand them, or whatever. C-like languages in contrast do not provide the necessary means of abstraction. That is witnessed by the fact that there exists something like "patterns". A pattern is a common strategy that cannot be expressed by library code and thus has to be expressively written every time it is applied.
Patterns are therefore not "symptoms of not having enough abstraction in your code", but are symptoms of having not enough means of abstraction in your language.
So a design pattern is a common strategy that cannot be expressed by library code and thus has to be expressively written every time it is applied. It is this lack of reusable code which tells me that design patterns are not actually as reusable as some people like to make out. If you are forced to write a new set of code for each implementation of a pattern then where exactly is the reusability?
Is it possible to define patterns which can be given substance in the form of reusable code? If they can be given substance, is it actually possible to create some sort of mechanism that will remove the need to generate by hand the code for each instance of these patterns?
Paul Graham ground to a halt at "some macro that I need to write", but where he faltered I have stepped in and created a completely new family of patterns which provide a far higher level of reusability. It is now possible not only to define the characteristics of these patterns but also to have an implementation mechanism which removes the need to generate by hand the code needed to reproduce them. With Transaction Patterns it is now possible to say "combine transaction pattern X with object Y and generate component Z".
Design patterns are merely abstract designs which require concrete implementations to be of any use, thus forcing the developer to write code in order to produce a working copy of that pattern. Transaction Patterns, on the other hand, are concrete implementations which can be used immediately without the need to write any code whatsoever.
I have been designing and building end-user database applications for over 20 years. By "database application" I mean one that uses a series of online screens or forms which allow the user to interrogate and update the contents of a shared database (which is usually relational). Some of these forms/screens may contain business logic which change the state of an entity, such as progressing a sales order through authorisation, picking from inventory, then shipment to the customer. In all that time my conscious use of design patterns has been virtually non-existent. Other programmers seem to eat, sleep and dream in design patterns, but I do not. In my whole career I can only recall two design patterns which I have read about and then deliberately sought to implement - the 3-Tier Architecture and the Singleton. Although my framework contains an implementation of the Model-View-Controller design pattern, this was by accident, not design. I just don't think in design patterns, I don't talk in design patterns. Why is this? Quite simply because when I am building an application I have found that design patterns are the wrong tool for the job, they are at the wrong level of abstraction. I may use design patterns, albeit unconsciously, to build a framework, but when it comes to building the final application on top of that framework I want something that will help in the construction of the many application components (user transactions), and that something is not provided by design patterns. When you consider that much more time is spent on building applications than on frameworks, it would make sense to have something that can assist in the writing of application components.
Another term that is sometimes used to describe a user transaction is "unit of work". Some people seem to think that just because there is a design pattern with the same name that this means exactly the same thing, and that all my transaction patterns are therefore covered by a single design pattern. If you believe such a thing then you are simply not paying attention.
Those of you who have actually written components for an end-user application will know that each component - or user transaction - has to be initially described from the user's perspective, in other words the user interface (UI). It may be sufficient to describe a framework in terms of the design patterns which it uses, but that does not apply to the application transactions which are built upon that framework. A user transaction is always described from the user's point of view, for example
"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 which deal with a number of database tables an observant programmer should be able to spot some similarities between one transaction and another. These similarities can be organised into recurring patterns, but as they are not the same as design patterns they require a completely different vocabulary, one that is based upon transaction patterns.
As a programmer will spend far more time in developing application transactions than in developing application frameworks, it would make sense to describe those transactions using the most appropriate vocabulary.
Just suppose that, after having written a transaction which deals with a particular database table, the programmer is then asked to write a similar transaction for a different database table. The typical request is:
Program #1 deals with Table 'A'. I now want another program which does exactly the same thing, but for Table 'B'.
Does this sound familiar? The words
"which does exactly the same thing" should immediately tell you that what you have here is some sort of commonality between the two programs, a repeating pattern, something that can be copied, so what do you do about it? The traditional approach is to take a copy of the first program and modify it to meet the requirements of the second. In the act of copying and modifying the code what the programmer actually does is generate by hand another copy of a pattern. Wouldn't it be great if it were possible to generate each copy without all that manual effort? Wouldn't it be great if Paul Grahams mystical "macro" could actually be implemented?
Here is some breaking news! I have actually implemented "Paul Graham's mystical macro". Twice. In different languages.
Patterns or templates are supposed to have the following characteristics:
As far as I can see the only way to create an implementation of a design pattern is to crank out all the necessary code by hand. Not only have I never seen any examples of design patterns which share common code, I have never seen any software which allows a developer to choose a resource, choose a pattern, then create a fully functional implementation of that pattern at the press of a button. It may be possible to have some sort of code generation with some patterns, but this would be the exception rather than the rule. When you consider that a complete user transaction is made up of a number of different design patterns you will see that it is virtually impossible to have the means to choose a resource, choose a pattern, then create a fully functioning user transaction at the press of a button.
It is this inability to create working implementations of complete user transactions at the touch of a button where design patterns fail, and where transaction patterns succeed.
Because a "transaction" contains elements from a collection of different low-level design patterns it can be said to exist at a higher level. A "transaction pattern" is therefore a method of providing a description of this collection of design patterns which are used to satisfy the requirements of a user transaction.
How is it possible to characterise these transaction patterns and to give them substance? If you consider that each program specification is really quite simple - "this is what it looks like and this is what it does" - you may end up with the following headings:
If you look carefully enough at similar programs you should be able to discern that both the structure and behaviour follow similar patterns, and that it is only the content which is different. This means that it is theoretically possible to express any transaction as a combination of pattern (structure and behaviour) and content (the data on which it operates) as follows:
It therefore follows that if a method can be found to implement each pattern with code that does not need to be generated by hand then each transaction can be created with less effort, thus reducing both the costs and timescales in that application's development. Rapid Application Development (RAD) is the Holy Grail of the software world which has been often promised but rarely delivered, so a framework which contains transaction patterns has a far better chance of actually delivering on that promise.
There are two possibilities (that I am aware of) that can be used to create a working transaction from a pattern:
I am aware of those two possibilities for the simple reason that I have used them both. In my previous language each transaction (component) was built on a compiled version of the pattern (template), while in PHP (which is interpreted, not compiled) I have a single set of scripts in a standard library which are referenced, not copied.
All this theory is all well and good, but it is of little use unless it can be put into practice. A working implementation has been achieved in the Radicore framework, which is built around the Model-View-Controller design pattern. This means that the Structure-Behaviour-Content of each transaction can be implemented with the following:
If a transaction is a particular implementation of Model, View and Controller, and if Views and Controllers can be paired to form reusable Patterns, it follows that a transaction is an implementation of a particular Pattern with a particular Model (database table). Different transactions can be created by combining the same Pattern with different Models, or the same Model with different Patterns. In the Radicore framework the Views and Controllers are supplied as pre-built and reusable modules, and the ability to generate a functioning transaction by saying "select table X, select pattern Y, now generate transaction Z" has been built into the Data Dictionary as the Generate Transaction function. This means that starting with nothing more than a database schema, it is possible to generate the Model class for each database table, and the transactions to maintain the contents of each table simply by pressing buttons. Some customisation of the table class may be performed afterwards to include business logic, but the initial working transactions can be created without writing a single line of code - no PHP code, no HTML, no SQL. Can your framework do that?
A properly crafted set of transaction patterns can be great time savers - an essential ingredient in a RAD environment:
Despite the provocative title I am not predicting the demise of design patterns. I am merely pointing out that while they may have a place in the building of frameworks, the building of end-user applications within those frameworks may benefit from a different kind of pattern which exists at a higher level of abstraction. When you consider that more time is spent on building application transactions than on building application frameworks, the savings made by using transaction patterns could be enormous.
Although a framework may be built around the Model-View-Controller design pattern, individual user transactions within the application will require individual implementations for each of the Model, View and Controller. It should therefore be possible to look at similar user transactions and see a different kind of pattern emerging. When you have different user transactions which do exactly the same thing but with different database tables then this is an example of a recurring theme, a recurring pattern.
If you can categorise each transaction into structure, behaviour and content you should be able to see that similar transactions have similar structure and behaviour with the only difference being the content. Because it is the structure and behaviour which is being repeated, it is the structure and behaviour which can described in a transaction pattern. All that is needed is a mechanism which can give substance to each of these patterns so that a new transaction can be built around a transaction pattern which will automatically provide the structure and behaviour elements without them having to be generated by hand. If you can achieve this then you are on the right path to achieving true rapid application development.
Is it possible to build such a mechanism? Yes. How do I know? Because I have done it, twice, in different languages - one for the desktop and one for the web. If you compare the two sets of pattern descriptions you should see distinct similarities, with the only difference being in the method in which they are implemented.
My latest implementation for the web is particularly interesting as it involves the use of XML and XSL which are available in every other web development language, so could be easily ported into any of those languages. Several java programmers have already tried out my patterns in that language and have been so impressed with the results that they are now working to produce full implementations. So if java programmers are impressed with the idea of transaction patterns then it can't be complete rubbish.
|10 Apr 2007||Added What you cannot do with Design Patterns.|
|18 Oct 2006||Amended Turning abstractions into something more concrete by adding a reference to Radicore Tutorial - Generate Transactions.|