This document has been superseded by '3 Tiers, 2 Models, and XML Streams'
In a system which is built around the 3-Tier architecture the components are arranged into layers, as shown in the following diagram:
Figure 1 - the 3-Tier Architecture
The user interacts with the system via the Presentation Layer (PL), which is why it is sometimes referred to as the User Interface (UI). All business logic and data validation is moved into a Business Layer (BL), while all communication with the physical database is moved into a Data Layer (DL). The idea behind this concept is that components in the data layer can be shared by components in the business layer, and components in the business layer can be shared by components in the presentation layer. This sharing of components is supposed to reduce the amount of duplicated code, thus speeding up development time and also making changes easier to implement.
It should also be possible to change the presentation layer from client/server forms to web pages, thus sharing the existing components in the other layers.
The standard method of implementing this architecture in UNIFACE is as follows:
Figure 2 - the 3-Tier Architecture in UNIFACE
Compuware supply a variety of database drivers for communicating with different DBMS’s, so it should not necessary to write any code for the data layer. The only problem arises when using a file system for which there is no UNIFACE driver, but that situation is so rare it is insignificant.
A separate object service is created for each entity within the application model, although certain one-to-many relationships can be combined into a single object service. These can be created easily from component templates which are supplied by Compuware. Provided that the data access flag for each entity is switched to ‘object service’ in each form before it is compiled all accesses of that entity will be routed automatically through the specified object service.
All that remains is to modify each object service so that it performs the necessary processing of business rules. This can be done by inserting the necessary code into the validation triggers within the object service itself, or by putting the code into service components which are called from the object service. I have tried both methods with great success, but I would not advise attempting to access an object service from within an object service.
In UNIFACE the application model used in the presentation layer is exactly the same as the one used in the business and data layers. This can be represented in the following diagram:
Figure 3 - The Single Application Model
This has worked successfully for years, but it does mean that any changes to the model may affect components throughout the system, requiring recompilations at the very minimum. However, some of the latest methodologies advocate the use of a separate model for the presentation layer, thus shielding those components from changes in the physical database.
This is an interesting idea, but how can it be implemented in UNIFACE? In the current project I am involved in the designers (no names, no pack drill) have insisted on a 3-tier architecture with a separate application model for each of the presentation, business and data layers. In order to achieve this they have ignored a lot of the standard functionality within UNIFACE, including object services and (would you believe it) the <read> and <write> triggers, and replaced it with a huge amount of very inefficient code. Using their method it takes a week or more to create a working form where I am used to completing forms in hours.
Having decided that what they have produced is a dog’s dinner (that’s the polite description - in reality it more closely resembles what comes out the rear end of a dog, not what goes in the front end!) I decided to see if I could coax one or two of my remaining brain cells into life and come up with a better, more easily implemented and usable solution. As I am basically a lazy programmer I always seek to achieve a result with the minimum amount of effort, so I made one golden rule from the start - if I am going to implement a 3-tier architecture then I will use object services. I have used them, I like them, and there is no viable alternative that I have seen. This would result in a structure that can be represented in the following diagram:
Figure 4 - The Dual Application Model
‘PL Entity’ refers to an entity defined in the application model used by the Presentation Layer (PL).
‘DL Entity’ refers to an entity defined in the application model used by the Data Layer (DL).
Note that I do not attempt to use a third application model for the Business Layer (BL).
This type of object service therefore has to contain code which transfers data between the PL and DL entities, mainly using putlistitems and getlistitems. The main problem with this idea is that no occurrences of the PL entity are actually retrieved from the database, therefore $dbocc
is never true, therefore the standard object service cannot return these occurrences to the calling component. In my experiment I had to replace the standard contents of the <read> trigger with some custom code to get round this limitation. I also had to include dummy fields called U_DBOCC and U_REMOCC to help identify database occurrences and occurrences to be removed. Another problem I found is that stepped hitlists cannot be supported, so all occurrences have to be fetched in a single operation.
These limitations aside I did manage to produce a working set of forms which demonstrate the functions of search, list, add, update and delete. One of the PL entities is actually constructed from two DL entities, with multiple occurrences from the second entity. Some of the validation actually requires multiple occurrences and multiple entities, but I managed to get it all working.
The code that I have produced succeeds in demonstrating the feasibility of the Dual Model approach, but due to the limitations that I have found I don’t think it is quite ready to be incorporated into a live system. It would need co-operation from Compuware to adjust their product to remove the limitations, which is why some while ago I added a request for a set $dbocc=true
function to my wishlist. This would allow constructed occurrences to be marked as database occurrences and remove the need for custom code in the <READ> trigger. If the necessary functionality could be incorporated into the standard product I think it would add a truly great feature.
If anybody is interested in examining my sample code please contact me at the address given at the end of this document. Any comments would be welcome. If enough people think that the idea has merit then perhaps Compuware can be persuaded to adopt it and make it part of standard UNIFACE. What do you think?
The main objective is to shield components in the presentation layer from any peculiarities in the physical implementation. The PL model could thus be considered as a logical view of the data while the DL model represents the physical implementation. This enables certain complexities in the data to be handled within the business layer, thus keeping the presentation layer as simple as possible.
One example of this is where the arrangement of fields on a form results in overlapping entity frames. The solution would be to merge all the fields from the various DL entities onto a single PL entity, then put code in the object service to transfer the data from these other entities.
Another example is where certain fields do not actually exist on the database but are constructed at run time. Instead of duplicating the necessary code in every PL component it can instead be defined once in the object service. Do not worry about constructing this data even if it is not wanted - the object service makes use of the selectlist which identifies which fields are actually used on the form. If the field is not in this list then do not construct it.
A third example is one where most people struggle to find a solution. It concerns what some people refer to as a ‘many-to-many’ relationship but which is actually implemented in the database as follows:
Figure 5 - A complex relationship
In this example ‘Parent 1’ can be any kind of object while ‘Parent 2’ is a list of all available options with ‘Child’ containing only those options that have been selected. Now imagine the following requirements for a form - "For an occurrence of Parent 1 show a list of all occurrences of Parent 2 with a checkbox indicating if a corresponding occurrence of Child exists or not. The user may add or remove occurrences of Child merely by clicking the checkbox on or off." Those of you who have tried dealing with this in a single component will appreciate the complexities.
Now imagine how it could be done with two application models:
The way in which this dual model facility could be used to move complexity from the presentation layer down to the business layer is therefore limited only by your imagination.
Tony Marston
20th May 2000
mailto:tony@tonymarston.net
mailto:TonyMarston@hotmail.com
http://www.tonymarston.net