Project

General

Profile

Replacing 4GL Features

Writing FWD code for a new 4GL feature is about modifying the FWD conversion and/or the FWD runtime to support that new feature. In many cases, both conversion and runtime will need work.

In our experience, the work needed for conversion support is usually 25% or less of the total work on a new feature. The runtime support is almost always the largest effort.

The problem is simply that we are writing an implementation that needs to be 100% compatible with the real 4GL behavior, look, feel and operation of the given feature. We are not trying to get "close". We are creating a drop-in replacement for the original environment. Of course, our implementation is written from-scratch in Java, so it is completely different "under the hood". But from a user's perspective, any application code should execute exactly the same as the original. In the UI, this means that every character and every pixel is drawn exactly the same way as in the 4GL. We must duplicate all math, expression processing, block structure, block properties, control flow, transaction processing, undo, retry, infinite loop protection, data types, query sorting, record navigation, error handling... EVERYTHING! Considering that the 4GL has been in development for 35+ years, this is a big task.

Here is the trick of it: deeply and thoroughly explore each new feature using testcases BEFORE EVER WRITING the replacement Java code. Doing this is harder than it seems.

The first place to start is by reading all relevant information in the Progress documentation. This may be spread across multiple books and it may be hard to find. Although the Progress community of developers is small, it is possible to sometimes find something useful on the web or in the Progress 4GL knowledge-base. There are a few Progress 4GL books, but they are rarely good enough to be useful.

You must not assume that the Progress documentation is correct or complete. At a minimum the Progress documentation is usually incomplete, with poor descriptions of parameters and return values, virtually no error handling information, no information about boundary conditions. We have found it to be unreliable at best and completely wrong in many instances. Yes, that is right. The Progress documentation is filled with incorrect and/or misleading information.

At this point you start writing 4GL code to demonstrate the feature.

The tricky part is to try to create the testcases (before starting Java development) that are as complete as possible, including exploring all error processing, boundary conditions and other "edge" behavior. This usually is the hardest part and it often takes multiple iterations, as one finds new complexity in the 4GL API or runtime behavior.

The 4GL is inconsistent and does not have clean language design. Early design decisions include user-defined symbol abbreviations, case insensitivity, thousands of keywords and a wide range of both ambiguous and irregular syntax. The runtime was implemented at a time before modern virtual machines or modern systems design. After many years of faithfully duplicating the insane 4GL functionality which is riddled with hidden/implicit behavior, dependencies on internal state, edge cases, errors, bugs, quirks and other frustrating and inexplicable behavior.

You must think about the testcases with this in mind. That means you must consider block structuring, block properties, transactions, resource scoping (both how this feature might change the scoping of resources and how this feature might be dependent upon scoped resources), internal state, error handling and so forth. You must execute the feature in the original 4GL environment, in all of its different syntax possibilities. You must execute it with different 4GL state, different related functionality and different options being present. Is there a sequence of other language statements that must be executed first? Try these out of order. Are there internal/implicit resources created inside the runtime as part of this? Try different moving the logic between different top-level blocks (external procedure, internal procedure, triggers, functions, methods) and between different "inner blocks" (do, repeat, for and editing blocks) to see if there is any scoping or transactional behavior. Based on the documentation, do they imply that the feature depends on some other state? If so, try executing with different possible state values to see if it affects anything.

You must ask yourself what a 4GL developer could do to exploit this functionality in strange ways? How can you break things but still not abend the runtime? We must duplicate all the error handling and bad behavior just like the 4GL.

Once the testcase set is complete, you should have a roadmap for the functionality and features that are needed. You document the results as a kind of specification. The design and implementation typically come pretty quickly from there. As a side benefit, the testcases can then be converted and executed in FWD to prove that the implementation is compatible. When FWD acts exactly as the original 4GL environment, then you are done with the feature.

Replacing 4GL features is inherently a Test Driven Development process.

DO NOT WRITE JAVA CODE UNTIL YOU HAVE THE 4GL BEHAVIOR FULLY EXPLORED. Otherwise you will end up having to debug, fix and rewrite the Java code many times and it will take MUCH LONGER than if you had just figured out ALL the 4GL behavior in advance. This is THE KEY to getting FWD written quickly.


© 2004-2022 Golden Code Development Corporation. ALL RIGHTS RESERVED.