As promised in the previous article, let’s apply the multi-tier conceptual approach in a couple of architecture implementations.
Before we begin, a quick note: This article relies heavily on the previous one, so if you haven’t read it, please do so before continuing.
A Simple Multi-Tier Architecture Implementation
The three tiers should be independent from each other so that each block can be reused in a different program. How is this possible? Well, ILE’s modularity allows us to create service programs that aggregate the blocks belonging to each of the three tiers.
Let’s assume that a simple program uses only one block of each tier. Consider the inventory management program I’ve been using as an example in this series. The program allows users to create, update, and delete items from a company’s inventory, via screen interaction. Its implementation in ILE would look like Figure 1.
Figure 1: A simple multi-tier architecture implementation for an interactive inventory management program
In this implementation, the INVMNT module controls the main flow and the screen interaction, calling procedures and functions from the INVBL service program to check if the action requested by a user is valid and possible. It might also call procedures and functions from the INVDA service program, for example to retrieve item descriptions or stock quantities.
The INVBL service program might check whether the user is allowed to delete items from inventory or whether new orders can be accepted from a certain client. The business logic procedures and functions that INVBL contains will, in turn, call INVDA’s procedures and functions to perform the lower-level database operations—such as reading the necessary records from a client’s current account and writing a new record to the order master file—and apply the business logic to the data that was retrieved. Thus, appropriate business decisions (validations, enforcement of business rules, and so on) are made.
If there is a need to print something, a separate program should be built, following the same multi-tier architecture implementation. Some of the functions called by the original program will probably be reused in the new program, such as retrieving item descriptions and client names. Sometimes it even makes sense to transform a “printing program” into a service program, if it gets called by several programs, to avoid mass-recompilation problems.
This is a simplified model, with only one module for each tier. It doesn’t account for the utility, generic, or pure calculation modules that exist in almost every ILE application. I didn’t include them in Figure 1, but they exist in the form of additional modules, bound by copy to the respective service programs, which in turn are bound by reference to the INVMNT program.
A More Realistic Multi-Tier Architecture Implementation
Now, let’s analyze a slightly more realistic example: an order management program. The ORDMNT program, depicted in Figure 2, allows the user to enter new orders, check an order’s status, and perform all sorts of other order-related operations. In an OPM implementation, this would be a huge piece of code, with routines duplicated from other programs, such as inventory and client management programs.
Figure 2: A realistic multi-tier architecture implementation
In an ILE multi-tier architecture implementation, there’s no code duplication, just reuse. I chose to depict program ORDMNT the same way I pictured the ILE program concept in Figure 1 of the previous TechTip to show how the different service programs used by ORDMNT “fit” in the concept.
You’ll notice that service programs INVDA, ORDDA, and CLIDA are connected to the data access tier of the program. These service programs would provide data access functions, in the form of RPG or SQL I/O servers, designed to read and write records to the database.
Service programs INVBL, ORDBL, and CLIBL would supply higher-level procedures and functions like Rtv_Item_Description, Rtv_Order_Delivery_Date, Wrt_Order_Record, Upd_Order_Record, Rtv_Client_Name, Upd_Item_Qty, Clc_Delivery_Fee, Clc_Earliest_Delivery_Date, and Chk_Client_Debt, just to name a few. There are many more procedures and functions involved. Just like in the previous example, I neglected the utility (to send the order confirmation by email, fax, or web service invocation, for instance) and general calculation service programs (such as date operations needed to calculate the actual delivery date assuming it cannot be on a weekend, for example). I also omitted the modules linked to each of the service programs depicted to try to keep things simple. Only the ORDMNT module was depicted to remind you that the ILE program doesn’t contain code, only the respective entry module (ORDMNT, in this case) does.
Program ORDMNT’s binding directory would contain an entry for each of the service programs used. Otherwise, the compiler wouldn’t be able to resolve all of the imports of module ORDMNT. You would be able to compile the module, but you’d fail to create the program.
It’s an interesting approach, right? But you’re probably thinking about its limitations. I’ll discuss those and introduce the MVC concept in the next TechTip!