In software engineering, a transaction pattern is an approach to constructing user transactions, which are sometimes known as "units of work" or use cases. Transaction patterns deal with the structure and behavior of application components from the user's perspective and are thus geared toward the user interface (UI). This is in contrast with design patterns which are geared toward how those transactions are implemented within the underlying software.

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 it may be possible 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 user transactions, hence the name 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.

An application is made up of a number of components or modules, each of which allows the user to complete a "unit of work" which in the business world is known as a "business transaction". When the first computerised business systems were implemented the term "transaction" was carried forward, and was used to describe a process whether it be performed manually or electronically. The same terminology has been adopted in the database world where a "database transaction" is that part of a computerised transaction which updates the database. These database updates are grouped into a logical unit by surrounding them with "start transaction" and "commit" instructions. Note that the Unit of Work design pattern describes a database transaction and not a business transaction.

A "user transaction" is therefore a module within a computer application which allows a user to complete a unit of work known as a "business transaction", and which may also include a "database transaction".

Bear in mind that unless you are developing software which directly manipulates a real-world object, such as process control, robotics, avionics or missile guidance systems, then some of the properties and methods which apply to that real-world object may be completely irrelevant in your software representation. If, for example, you are developing an enterprise application such as Sales Order Processing which deals with entities such as Products, Customers and Orders, you are only manipulating the information about those entities and not the actual entities themselves. In pre-computer days this information was held on paper documents, but nowadays it is held in a database in the form of tables, columns and relationships. An object in the real world may have many properties and methods, but in the software representation it may only need a small subset. For example, an organisation may sell many different products with each having different properties, but all that the software may require to maintain is an identity, a description and a price. A real person may have operations such as stand, sit, walk, and run, but these operations would never be needed in an enterprise application. Regardless of the operations that can be performed on a real-world object, with a database table the only operations that can be performed are Create, Read, Update and Delete (CRUD). Following the process called data normalisation the information for an entity may need to be split across several tables, each with its own columns, constraints and relationships, and in these circumstances I personally think that it would be wiser to create a separate class for each table instead of having a single class for a collection of tables.

In a typical CRUD application there are a number of form-based transactions which allow the user to view and maintain records within a database using the standard Create, Read, Update or Delete operations. A transaction may deal with a single occurrence from a single database table or may deal with several occurrences from several database tables. It may only read from the database, or it may perform a number of inserts, updates and deletes within a single operation.

Trying to describe an entire application, or the individual transactions which are contained within it in terms of the design patterns which may be used can be a pretty daunting task, similar to describing a physical structure in terms of the nuts, bolts, brackets and beams used in its construction. Design patterns are commonly used to describe individual facets of a transaction, and are primarily associated with just one of the many steps that exist between the user interface and the database. A typical combination is usually model, view, controller and data access object, but there may also be decorators, observers, helpers, singletons, mappers, facades, front controllers, page controllers, factories, proxies, et cetera, et cetera. What is needed is a method of describing a user transaction at a higher level of abstraction, to identify what it looks like and what it does rather than what low-level design patterns are used to implement the individual steps. This new type of pattern, this higher level of abstraction, is known as a transaction pattern.

A pattern is a theme of recurring elements, events or objects, where these elements repeat in a predictable manner. It can be a template or model which can be used to generate things or parts of a thing.

So a pattern can be used to make complete duplicates of something, such as a mould in an industrial process which can reproduce copies of the same shape in large numbers. These things may be finished articles, or may need to be assembled into a finished article. It may take longer to create a pattern than to create a single article, but if you want large quantities of that article then the investment of creating a pattern provides you with the means of creating copies at a higher speed and/or lower cost.

If you need large quantities of something then it is more likely that the use of a template/pattern/mould will provide huge benefits, but even if you may only require the occasional copy, then the use of a pattern will guarantee some level of consistency with the original. If you build something from scratch each time there is the likelihood that it will be different from the original, especially if it is being built by a different person or different team. These differences may seem slight, but they could lead to problems.

Before the benefits of using a pattern can be realised there are certain obstacles that must be overcome:

Recognising that a pattern exists.

Building something, such as a mould or template, that can reproduce copies of that pattern.

If you do not overcome these obstacles then you will be forced to re-invent the wheel each and every time. In the case of software this means writing a new piece of code which does exactly the same thing as another piece of code. At best this may mean copying the original code and putting it in a different place, but at worst this may mean writing a new piece of code from scratch, and this new piece of code may perform differently or produce different results. The biggest drawback is that should it become necessary to change a piece of code then that change must be applied to all the copies of that piece of code, and it may be a difficult process to identify where all those copies exist. If software is written well there is no duplication of code, instead a piece of logic is built into a reusable module so that whenever that logic is required it is referenced from that module. Because there is only ever one copy of this code it means that changes need only be made to that single copy, and all the references to the module will automatically use the latest version.

As mentioned previously a CRUD application is used to maintain the contents of a database, and as a database may contain a large number of tables there may be transactions which do similar things but to different tables. This can lead to the following situation:

Transaction #1 does something to database table 'A'.

Transaction #2 does exactly the same thing, but to database table 'B'.

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:

Structure - what it looks like, how many elements it contains, how they are positioned and how they are related.

Behaviour - what it does, what actions it performs, either automatically or by user selection.

Content - what data from which database table(s) is acted upon within each element.

With these characteristics it is possible to have transactions with the following combinations:

The same structure and content, but different behaviour. Thus an input screen and an update screen look the same but have different behaviour. One starts with an empty screen while the other starts with existing values from a selected database record. One does an INSERT while the other does a READ and an UPDATE. There may also be subtle differences in the validation rules between an INSERT, UPDATE and DELETE.

The same structure and behaviour, but different content. Thus an input screen for 'table-A' is just the same as an input screen for 'table-B', just for a different table and with different columns. There may also be different business rules with each set of content.

The same content and behaviour, but different structure. This is very rare, but possible. It is not usual to provide multiple transactions which perform the same operations on the same data, but with different screen structures.

Each transaction pattern is therefore geared towards performing one or more pre-determined operations on one or more database tables, but the identities of these tables are not supplied until run time. Each pattern will also output its results in a particular format such as HTML, PDF, CSV, or even produce no output at all.

It has been my experience that a particular transaction 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) 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.

As a practical example, an application with many database tables will have a separate transaction to list or browse through the contents of each table. Each of these transactions may have a screen structure which resembles the following:

Each of these areas can be described as follows:

Menu Bar - a series of buttons or links which allows the user to jump to any part of the system. If an option which is selected is a menu the current list of options is replaced with a new list. If the selected option is a transaction then that transaction is activated, which causes the remainder of the screen to change.

Title - a brief description of the current transaction.

Navigation Bar - a series of buttons or links, with a different set for each transaction, which allow the user to jump to a related transaction and to pass context to it. This usually means that the user can select one or more rows from the data area, then pass the identity of these rows to a related transaction for further processing.

Column Headings - a label which provides a heading above each column of data in the rows immediately beneath it. Each label is defined as a button or link which, when pressed, will cause the data to be re-fetched and sorted on that column, toggling between ascending and descending sequence.

Select Boxes - a checkbox in front of each row of data which allows one or more rows to be selected before pressing a navigation button to pass that selection to another transaction.

Rows of Data - each horizontal line shows data from a different record (row) in the database, and is limited to a subset of the available columns (fields) which can fit onto a single line. The number of lines is usually limited to what can reasonably be viewed at a single time, perhaps 10 or 20 or so, and is referred to as a "page" of data. Alternate rows will be shown in different colours.

Message Area - an area which will be used to display any warnings or messages.

Pagination Area - a large volume of data is broken down into smaller "pages" which are displayed one page at a time. The pagination area contains links which allow the user to move backwards or forwards through the available pages.

Action Bar - a series of buttons which perform actions at the transaction level, not at the individual row level, such as CLOSE to terminate the transaction or RESET to set any sorting or selection criteria to their initial values.

When the different transactions are compared the differences can be expressed in nothing more than a few table/column names, so everything else can be deemed to be part of the "pattern" for this kind of transaction. If it is part of a pattern then why should the description of that pattern be duplicated in every transaction specification? Why should the code which supports that pattern be duplicated within individual transactions? By defining all this structure and behaviour into a series of reusable patterns it becomes possible to cut out an enormous amount of duplicate effort simply by referring to a central pattern.

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:

For a compiled language it may be necessary to have a process which takes a pattern, takes one or more table names, then generates the source code which can then be compiled into a working transaction.

For an interpreted language where no pre-compilation is necessary it may be possible to refer to the pre-written code without having to generate a copy.

The disadvantage with the compiled option is that each transaction is actually carrying around a copy of the pattern code, so it may not be possible to incorporate subsequent changes to the pattern into any transactions without going through the generation process again. A better option would be the ability to change the pattern code and to have those changes automatically inherited by the transactions without manual intervention.

With a web application the latter option is eminently possible as each page of HTML is generated completely from scratch instead of being provided in pre-compiled form. Furthermore, by having each page generated by XSL transformations it is possible to have the page layout defined within an XSL stylesheet, and to use the same XSL stylesheet for every implementation of that pattern.

If the framework of the web application is built around the Model-View-Controller design pattern this allows the Structure-Behaviour-Content of each transaction to be defined as follows:

The Model (Content) part can be provided by a separate class/object for each database table. All the code which is common to any database table is defined in and inherited from a superclass. Thus the class for a specific database table contains only the code which is unique to that database table.

The View (Structure) part can be provided by an XSL stylesheet. If the identity of the tables and columns to be displayed can be passed in as data in the XML document instead of being hard-coded in the XSL stylesheet, then no stylesheet need ever be customised for any individual transaction.

The Controller (Behaviour) part can be provided by an object which calls a predetermined set of methods on one or more Model objects. If you consider that via polymorphism it is possible to use the same method names on any object, and the objects can be instantiated from class names which are passed in as parameters, it means that no table or column names need ever be hard-coded into a controller, thus making them totally reusable for any Model within the application.

It is therefore possible to express each transaction pattern as a combination of View (structure) and Controller (behaviour) and a working transaction can be implemented simply by adding in a particular Model (content). If all the Views and Controllers come pre-built into the application framework, then once the Models for each database table are built the construction of individual transactions becomes no more complicated than "use this View and this Controller with this/these Model(s)". Just think how much developer effort that would save! My framework contains just 12 reusable stylesheets and 38 reusable controllers, and using these I have been able to build applications which contain thousands of transactions in a fraction of the time it would take using non-reusable modules.

The Radicore framework includes the ability to generate fully functioning application transactions using this library of transaction patterns - simply select a database table, select a pattern, press a button and all the necessary pieces will be created for you. This procedure is documented in Radicore for PHP - Tutorial in the Generate Transactions section.

By using transaction patterns it is possible to gain the following advantages:

Application design is easier as transactions can be designed around an existing set of patterns, thus avoiding the need to re-invent the wheel.

Program specifications are quicker to write as the details on structure and behaviour are already satisfied by the transaction pattern. All that is necessary is to identify the transaction content and any task-specific behaviour.

Code which is inherited from the pattern does not have to be written again, thus saving development time.

The pattern code has already been tested in other transactions, therefore should not need extensive re-testing, consequently saving more time.

Global updates can be made by modifying the code within a pattern and have that modification automatically inherited by all transactions which are based on that pattern.

Transactions written from patterns will all behave in a consistent manner, which removes a source of annoyance from the users.

Program documentation is easier to write as the features inherited from the transaction pattern do not need to be duplicated.

Some people seem to think that these transaction patterns are very limited in scope and are unable to deal with anything other than the most simple of circumstances. That just shows that they have not examined the wide range of transactions which are built into the Radicore framework to see how they are implemented. Every single transaction is built from a pattern, and some transactions which are built from the same pattern do entirely different things, so how is this possible?

The first thing that is required is an understanding of how a pattern works. A pattern is a combination of a reusable controller and view which acts upon an undefined model. A small number of patterns do not produce visible output, so do not have a view. Each controller calls a different preset series of methods on a model whose identity is not provided until it is incorporated into an actual transaction. The controller and view, because they are unchangeable, contain those functions and features that do not vary between different implementations of the same pattern, which means that any transaction-specific behaviour must be built into the model.

When a controller calls a method on a model this method, which is defined within the abstract table class from which each individual database table subclass is extended, is simply the first in a chain of methods which are called to carry out the required processing. This "chain" of methods, which is pictured in UML diagrams for the Radicore Development Infrastructure, contains some dummy customisable methods which are identified by their "_cm_" prefix. For each operation there is usually a "_cm_pre_whatever" method which is called before the event, and a "_cm_post_whatever" method which is called after the event. Each of these customisable methods is defined in the abstract table class as an empty stub, so by default they do absolutely nothing. However, any one of these empty stubs can be copied into a database table subclass and filled with code, in which case that code will be executed instead of the empty stub. So, by placing customised code into an otherwise empty stub, it is possible for any transaction to execute code which is not contained within the controller. This customisable code may either be executed instead of or in addition to the standard code, so the possibilities are endless.

Take, for example, the following requirement:- the user selects an entry from the ARTICLE table, then presses a button to send an e-mail about that article to all registered users. How can this be done if there is no "send e-mail" pattern? The answer is to modify the custom methods for the UPDATE 1 pattern as follows:

Create a _cm_initialise() method which sets all the fields in the update screen to NOEDIT. This means that the user cannot amend any values, but still has a SUBMIT button. This method can also generate a message to the effect "Press SUBMIT to send an e-mail".

Create a _cm_post_getData() method which examines the selected entry to ensure that the EMAIL_SENT field is FALSE to ensure that the same e-mail is not sent more than once.

Create a _cm_pre_updateRecord() method which reads the table of registered users to obtain their e-mail addresses, constructs and sends an e-mail, then sets the EMAIL_SENT field to TRUE. The following call to _dml_updateRecord() will update the database.

Another transaction which has a different level of complexity is the IMPORT COLUMNS function in the data dictionary. For a given table name it will obtain the current details from the database schema, then issue the necessary INSERT, UPDATE and DELETE statements to keep the dictionary database synchronised. This is achieved by modifying the custom methods for the ADD 4 pattern as follows:

Create a _cm_getInitialDataMultiple() method which gets the current column details from the database schema, then the current column details from the dictionary database. It compares the two and constructs three arrays - one for records to be inserted, one for records to be updated, and one for records to be deleted. The first array will automatically be processed by the standard insertMultiple() method while the others must be stored for later processing.

Create a _cm_post_insertMultiple() method which will be automatically executed after the standard insertMultiple() method. This then takes the other two arrays created previously and passes them manually to the deleteMultiple() and updateMultiple() methods. Note that any or all of these arrays can be empty without causing an error - an empty array simply causes that processing to be skipped.

In a similar vein is the EXPORT TABLE function which takes all the details for a given database table from the dictionary and creates two non-database files. This is achieved by modifying the custom methods for the UPDATE 4 pattern as follows:

Create a _cm_post_getData() method which takes the selected table name, retrieves the relevant data and writes it out to the non-database files. This returns an empty array so that the subsequent call to the updateMultiple() method does not have to do anything.

As you can see this arrangement of standard and customisable methods in each model object leads to endless possibilities, so how can this be described as inflexible?

Some people seem to think that transaction patterns do not exist for the simple reason that the Gang of Four did not write about them. In my opinion such people fall into one of two categories:

Ignorant - they have never written end-user transactions for a database application.

Incompetent - they have written similar transactions for different database tables, but do not have what it takes to abstract out the similarities into describable patterns. Such people often criticise me for not "getting" patterns, yet they are the ones who wouldn't recognise one if it crawled up their leg and bit them in the bottom.

If transaction patterns do not exist then how come I can not only describe them in great detail but also build the means to implement them? Twice. In two different languages.

If you do not believe that transaction patterns actually exist then I dare you to take this challenge:

Build several transactions in the old-fashioned way without the use of patterns.

Use my framework to build similar transactions with the use of patterns.

If you notice a difference would you possibly concede that maybe, just maybe, there might be something in what I have to say?

If you would like to discuss the contents of this article please visit the Radicore forum.