The 3-Tier Architecture - some criticisms of Compuware's approach

Tony Marston - 2nd May 2002
Amended 27th June 2002

What does '3-Tier architecture' mean?
How does the '3-Tier architecture' work?
What are the advantages of the 3-Tier software architecture?
My personal criticisms of Compuware's approach
a) The loss of functionality in the Client/Server implementation
b) The use of a single application model for both the presentation and business layers

What does '3-Tier architecture' mean?

If you are not sure what the term '3-Tier architecture' actually means you should first read the following articles:-

This particular article is referring to 3-Tier software architecture.


How does the '3-Tier architecture' work?

Components in the presentation layer are not connected to the database, so all READ, WRITE and DELETE commands are removed from their respective triggers.

When a presentation layer component wishes to obtain data it activates a GETDATA (or equivalent) operation on a session service, which exists in the business layer. The session service retrieves data from the physical database, then uses the XMLSAVE command to construct an XML stream which it then passes back to the presentation layer component. Stepped hitlists do not exist in this architecture, so the XML stream may contain multiple occurrences, and even multiple entities.

The presentation layer component simply performs an XMLLOAD on this data stream in order to transfer all that data into its own structure. These occurrences will have $OCCSTATUS="est" instead of $DBOCC=TRUE.

Occurrences can be modified, created or deleted in the presentation layer component as normal. However, this component does not perform a STORE, instead it uses XMLSAVE to create a new XML stream, which it then passes to a session service by activating a PUTDATA (or equivalent) operation.

The session service will then perform an XMLLOAD followed by a RETRIEVE/RECONNECT which will identify if occurrences need to be added, modified or deleted. This is then followed by a STORE/COMMIT. Game over.


What are the advantages of the 3-Tier software architecture?

By breaking down an application into 3 distinct and separate tiers (or layers) - the presentation tier, the business logic tier and the data access tier - you gain advantages in several areas. The Compuware Three Tier Development Guide (product code 10117038101-00) identifies the following:-

As a designer/developer I can summarise the benefits as follows:


My personal criticisms of Compuware's approach

I first attempted the 3-Tier software architecture when Compuware provided the functionality for Object Services in version 7.2.04 (see UNIFACE and the N-Tier Architecture). This was superseded in version 7.2.06 when the functionality for XML streams appeared (see 3 Tiers, 2 Models, and XML Streams). This proved to be a far superior approach, and I have successfully taken my sample 2-Tier application (which can be downloaded from my Building Blocks page) and converted it into 3 tiers. If you run the two versions (2-tier and 3-tier) side by side you will find it difficult to spot the differences.

However, in order to produce a 3-tier version which had the same look and feel as the 2-tier version I had to invent some nifty work-arounds for problems I encountered with the Compuware code.


a) The loss of functionality in the Client/Server implementation

Although Compuware state in their Three Tier Development Guide that the presentation layer can be made up of both client/server forms and web pages what they neglect to mention is that forms must now function in the same way as web pages - i.e. any validation performed by the business layer component (session service) cannot be initiated via any field or occurrence trigger, only at the SUBMIT/STORE stage. This means that you have to wait until the entire form contents is sent to the session service for updating on the database before any individual field can be validated. I consider this to be unacceptable, and so does every other person I have spoken to on the matter.

These are the problems I have found, and the work-arounds that I have produced:

1. XMLLOAD sets all modification and validation flags

When you retrieve data into a traditional 2-tier form and allow the user to make changes no field or key validation trigger is normally fired until the user actually makes a change. In a 3-tier form where data is obtained from a session service and loaded using the XMLLOAD statement you will find that all key, field and occurrence modification/validation flags are automatically set. This means that validation triggers will be fired even though data has not yet been modified. This causes existing primary keys to be rejected as duplicates.

I logged a call in September 2001 asking Compuware to include an /init switch on the XMLLOAD statement to prevent these validation flags from being set, but they do not consider it to be of any importance.

I notice from the documentation for version 8 that Compuware now recommend using the RELEASE command to unset the modification flags after loading data from an XML stream. Unfortunately this also clears out the values for $occstatus and $occcrc which are vitally important when attempting to reconnect occurrences to the database. Nice try Compuware, but not good enough!

So what is my work-around? One way to unset all modification and validation flags is to perform the STORE command. This is not normally used in a 3-tier form because:-

However, there are some triggers containing code that should not be fired because of the STORE, but which should be fired if the data is changed. I achieve this with the following code:

$$store_after_xmlload = 1    ; set flag
store/e <entity>             ; clear all modification/validation flags
$$store_after_xmlload = 0    ; unset flag

Any trigger that would normally activate the session service to perform remote validation contains a call to a global proc, and each of these global procs has been modified to test the contents of the $$store_after_xmlload variable before it does anything else. If it is set then the global proc terminates immediately with a zero status.

2. Field errors in remote validation

Remote validation is where the presentation layer component passes data to a session service in the business layer so that it can be validated. Remember that the session service may be running on a remote server and not the client device. The session service will either pass back a zero status, or it will pass back an error message which can be displayed to the user. This is supposed to be achieved by using $OCCPROPERTIES for occurrence errors and $FIELDPROPERTIES for field errors. These will cause the error messages to be included in the valerr attribute of the field or occurrence in the XML stream. When the data is loaded back into the presentation layer component the XMLLOAD command will detect the existence of an error message in the valerr attribute and automatically fire the relevant <ON ERROR> trigger so the message can be displayed.

So what is wrong with this you ask? Quite simply the $FIELDPROPERTIES function cannot be used in a self-contained service. One of the advantages of using the 3-tier software architecture is that it can be deployed on a 3-tier hardware structure with all services and reports running on a remote server. If Compuware state that services which are to be deployed remotely should be self-contained, then why do they prevent remote validation from working in a self-contained service? Where is the logic in that?

I logged this as a fault in May 2001, but it has yet to be resolved.

So what is my work-around? Instead of using $OCCPROPERTIES or $FIELDPROPERTIES to pass error messages from the session service to the form component I use my Message Object instead. This has the advantage that it can deal with any number of error messages at a time. And it works in self-contained services.

3. Obtaining contents of valerr attribute after remote validation

Even if the previous problem did not exist I would still have a problem obtaining the contents of the valerr attribute because I would have to perform an XMLLOAD, and this works by appending to the existing occurrence, not by overwriting it, and thus creating a duplicate. Unfortunately the removal of this duplicate occurrence causes no end of problems:

I logged a call in September 2001 asking Compuware to include an /replace switch on the XMLLOAD statement to prevent these duplicate occurrences from being created, but they do not consider it to be worthy of their attention.

So what is my work-around? Instead of loading the XML stream so I can obtain any error messages from the valerr attribute I ignore the XML stream completely and get any error messages from my Message Object.

4. Updating occurrence after remote validation

It is quite possible that during remote validation some values may be modified in the session service which must then be returned to the presentation layer component. If I return these changes to the presentation layer component in the form of an XML stream then I will have problems with duplicate occurrences, as identified in the previous section.

So what is my work-around? I simply modified my remote validation operation so that it returns any changed data as an associative list as well as an XML stream. It is then a simple matter to use getlistitems/occ to overwrite the current occurrence instead of using XMLLOAD and creating a duplicate occurrence.


b) The use of a single application model for both the presentation and business layers

The approach adopted by Compuware in UNIFACE EIGHT is to use a single application model (which they refer to as the Business Object Model) but to create subtypes of each entity for different types of component. These 'component subtypes' are named according to the following conventions:

They do this so that they can provide different trigger code in each component subtype that is relevant to that type of component. I do not like this method for two reasons:-

Why should this be important? I first came across the idea of using a separate application model for the presentation layer in 1999. By creating a 'logical' model which was separate from the 'physical' model you were supposed to be able to hide any complexities in the physical database from the presentation layer components, which were supposed to be kept as simple as possible. The ability to have a totally separate application model provides the following features:-

In my software I refer to the 'physical' model as the Business Application Model (BAM) and the 'logical' model as the Presentation Application Model (PAM).

'How can you reconcile the differences between the two models?' I hear you ask. When using the XMLLOAD and XMLSAVE commands you have the ability to specify object mapping. This is defined at the DTD level, and provides the ability for objects in the DTD to be mapped to objects inside the component with different names. I use this ability in my session services to access objects with their physical names in the component's structure, but to convert them to their logical names in the XML stream. I do not use this mapping facility in the presentation layer because the object names in the XML stream are exactly the same as the object names in the Presentation Application Model.

Here are some examples which show how this facility can be used:-

1. Moving a field from one entity to another in the PAM

Suppose in the BAM I have an entity called PERSON which contains a foreign key (PERS_TYPE_ID) which links to a foreign entity called PERS_TYPE. If I wish to display the description that is related to a particular value of PERS_TYPE_ID I would normally have to include the foreign entity in my component. However, in my PAM I can add the PERS_TYPE_DESC field to my PERSON entity. The presentation layer does not need to know that PERS_TYPE_DESC has to be obtained from a different entity - this is totally transparent in the presentation layer and only of concern to the session service.

Let me draw you a picture:

The physical database (BAM)
PERSON entity
PERSON_ID primary key
PERS_TYPE_ID foreign key
    
PERS_TYPE entity
PERS_TYPE_ID primary key
PERS_TYPE_DESC description

The logical database (PAM)
PERSON entity
PERSON_ID primary key
PERS_TYPE_ID foreign key
PERS_TYPE_DESC description

2. Creating an entity in the PAM which does not exist in the BAM

This is a relationship between two entities (for example, X and Y), where more than one occurrence of Y can exist for each occurrence of X, and more than one occurrence of X can exist for each occurrence of Y. This is resolved by having a link entity between them to form two one-to-many relationships, as shown in the following diagram:

Entity X
----->
LINK
<-----
Entity Y

A typical form to maintain the contents of the LINK entity may be described as follows:

This can all be achieved by creating an entity in the PAM with the following definition:

The logical database (PAM)
X_ID foreign key primary key
Y_ID foreign key
ACCESS_FLAG checkbox
Y_DESC description for entity Y

The session service contains all the code necessary to construct this PAM entity from the BAM entity, and to create/delete occurrences of the LINK entity based on the new setting of each checkbox once the data is passed down from the presentation layer for updating. The presentation layer component does not know how many entities are involved, all it knows is that there is a checkbox that can be toggled on or off.

3. Creating one PAM entity from two BAM entities

In this example the BAM contains two entities to hold address details - an address header, with each address line held as a separate occurrence in a separate subordinate entity.

ADDRESS_HDR
----->
ADDRESS_LINE

The physical database (BAM)
ADDRESS_HDR entity
PERSON_ID primary key
ADDRESS_NO
PHONE_NO telephone number
START_DATE start date
END_DATE end date
    
ADDRESS_LINE entity
PERSON_ID primary key foreign key
ADDRESS_NO
ADDR_LINE_NO  
ADDR_LINE address line

In the PAM these two are combined into a single entity, as follows:-

The logical database (PAM)
ADDRESS entity
PERSON_ID primary key
ADDRESS_NO
PHONE_NO telephone number
START_DATE start date
END_DATE end date
ADDR_LINE_1 address line 1
ADDR_LINE_2 address line 2
ADDR_LINE_n address line n

It is the responsibility of the session service to merge the two BAM entities into the single PAM entity before the data is passed back to the presentation layer. If the data is updated it must then extract the data from the single PAM entity and write it to the two BAM entities.

4. Adding a field to a PAM entity which does not exist in the BAM entity

There may be occasions when you require to display a piece of data that does not actually exist in the database in that form, but which has to be derived at runtime. This 'derivation' can now be removed from all presentation layer components and performed solely within the business layer.

A typical example is where you have UNIT_PRICE and QUANTITY from which you can derive EXTENDED_PRICE. You can include EXTENDED_PRICE in the PAM entity and have the session service perform the calculation.

Another example is where the contents of several string fields may need to be joined together and presented in a single string field. Thus you might have TITLE, FIRST_NAME, LAST_NAME and INITIALS on the database, but wish to present them in a single field called PERSON_NAME.


Tony Marston
2nd May, 2002

mailto:tony@marston-home.demon.co.uk
mailto:TonyMarston@hotmail.com
http://www.tonymarston.net

Amendment history:

27th June 2002 Added a comment regarding the use of the RELEASE command.

counter