When and How to Upgrade Code

I work on code that, when I came to work for my client, was essentially RPGIII/RPG400 or older. Some of the code had been implemented way back in the 1970’s and was migrated forward as newer machines were installed. And the code showed it. (I have found interesting the large number of 80 and 96 byte files in some of the systems, remnants of old punchcard processing programs.) You haven’t lived until you’ve attempted to update a program that has grown over the years to be a 10000+ line, indicator-laden monster. If you’ve been away from the program awhile and you need to make a non-trivial change, you need to spend part of a day, at least, reviewing the program’s processing.

I am normally conservative about program changes. I generally do not rip apart code and rewrite it, especially if it is not broken. But if a program is to be revised, I do generally at least convert it to RPGIV before making even a minor change. As a phrase used by one of my favorite literary characters (Anne of Green Gables) says, doing this allows “more scope for imagination”.

I was making code changes for a conversion project I was working on when I came across a particular program I had seen before and shook my head at. But for some reason, this time something snapped. I just HAD to change a particular chunk of code, even though the code in fact worked. No errors. But how far to change it? I will explain what I did. In the end, what I do will likely be seen as good by some, too intrusive by others, and  not radical enough by still others.

The original routine is designed to accept as input the job date (UDATE) and put out a date in the format “January 31, 2009″. As I said before, it works. It uses a technique I myself have often used in the past in RPGII/RPGIII/RPG400 to build a character string: Create an array of 1-byte elements equal to the length of the string, then piece together the string using MOVEA (move array) statements based upon a moving index (in this case, I). You then use another MOVEA statement to move the contents of the array to the field.

Anyone at all familiar with  RPGIV knows there are now better ways to handle this. Before RPGIV, using an array was probably the most elegant way to do it, if not the only possible way. But what caused my resistance to change to finally snap was seeing, one more time (I had read the code before) that hideous 12-deep stack of IF-ENDs to pull the month name into the array and set the index in place to insert the day number. It violated my sense of programming elegance.

The following is the code that left me foaming at the mouth:

C                       MOVE        UMONTH         MM    2 0

C      MM               IFEQ        01

C                       MOVEA       'January '     AR,1

C                       Z-ADD        9             I     2 0

C                       ELSE

C      MM               IFEQ        02       

………  and so on.

Multiply the above by 12, and you get the picture. I might revise this later and show the entire routine in full, if I can get a copy of it.

It depressed me that someone who obviously knew how to use RPG arrays didn’t implement a simple array-based technique that required definition of two compile-time arrays: MO (12 elements, 9 bytes each, and IN (12 elements, 2 positions, 0 decimal places). Filling the arrays would require 3 lines for MO (the month names) and 2 lines for the index, using the values contained in the existing code.

With the above definitions as a basis, only TWO lines can replace that entire monster:

C           MOVEA MO(UMONTH)   AR 
C           Z-ADD IN(UMONTH)   I         

(No error is checking on UMONTH is needed; it is a system value that will always be between 1 and 12.)  Why anyone would write that long, mind-numbing chunk of code instead of my two lines is totally incomprehensible. But then, I never could understand why, at other times, a programmer would write a string of 50 lines of code all conditioned by the same three or four indicators plus another two that changed every once in a while.

Do we leave it at this? I decided that since we have gone this far, we might as well go the rest of the way. Here is the final result:

C                EVAL     OUTDATE= %TRIM(MO(*MONTH))  + ' '

C                         + %CHAR(*DAY)  + ', '  + %CHAR(*YEAR)   

We have discarded the array-to-field concept entirely and defined it directly by piecing the string together using the EVAL statement and the %CHAR opcode, while using the month list (MO) we defined previously. Why %CHAR instead of *YEAR and *DAY by themselves? Because *YEAR and *DAY are numeric fields; to use them in this form of the EVAL statement requires that the numbers be converted to strings. As it happens, the %CHAR BIF strips the leading zero of days 1 through 9, whereas the original routine would present the ninth of January as January 09 instead of January 9. I felt this was a fortunate side effect of the %CHAR built-in function (BIF).

And why *YEAR instead of UYEAR? Because UYEAR gives a 2-digit year, while *YEAR gives us a 4-digit year; this way, I no longer need to insert the two digits (20) for the century.

But should I stop here? A logical next step would be to use ILE facilities and make my routine into a separate module that any program could access.  You could then, after linking programs and modules, be able to call the routine, sending it the parameter of any date in any desired format and output the string like this:   EVAL    printdate= datertn(sysdate)

I have written in previous blog entries about my lack of enthusiasm for modular programming. In this case, I can write it as I have, with one calculation statement and a month table directly in the program. Or I can write a module using the same table and statement, create prototypes to be inserted in the calling and called program, compile the pieces separately (CRTRPGMOD twice), then combine them into one program (CRTPGM). The idea that I would be creating something special, that I can generate something that looks like a function,  is less than exciting. I would just as soon do it the simple way, cutting and pasting if by some chance I came across another program that could use the idea.

Some might say that I should set it up for reuse by someone else, or even by myself at some future time.  But why? Remember, some of the code in the system is over 30 years old, and a lot more is over 20 years old. This installation is not big on innovation for innovation’s sake. It is not a rapidly changing business. It is on the Internet as much as it sees a need to be. Perhaps the main thing is that there are not going to be a lot of new programs written for this system. And this business is prospering even in these hard economic times, so it’s not like it will take an large degree of bleeding-edge IT-innovative thinking to make the business work. This is not a large programming shop; we three programmers sit within a radius of about 10 feet, and we are not in cubicles; if we have a programming question about a piece of code, we either look up or turn around. It will be a long time before all the code is rewritten in RPGIV, let alone have a substantial set of service programs in place.

Just cleaning up all the indicators will take a number of years, especially if there is not a need to work on the indicator-laden programs. One of my pet peeves right now are programs that say “  26    GOTO    NEXT”, then every line between there and the NEXT TAG is conditioned on N26 (not 26) ! About 50 lines of code! Didn’t they realize that indicator 26 will NEVER be on in that code sequence, so N26 is totally unnecessary, and all they are doing is junking up the program?

It’s mind-numbing. With these kinds of issues, why should I be concerned about modules, when I would be much better off cleaning up existing code when I can?

So we will leave the code as I described above. I had the chance, because I was in the program anyway, to make substantial improvements. I will get the chance again. It is a big project.

One Response to “When and How to Upgrade Code”

  1. codingRPGfor30yrs Says:

    there’s about 80 ways to code what you just showed. I have worked in RPG from 1979 until the present and have seen everything. Code is code, whether indicators used or bifs or whatever.. if you are under the gun to produce changes and create aps, you just code the crap like it currently exists, for readability, not because you like to look up something and decide to put it in a program where the next guy will have to debug it to figure out what its doing..indicators are a reality and we know everything can be done without them..but what is the purpose of re-write if your just adding a screen. Ive seen a program where all *in have been used two times (saved off and reused, all 198 of them) ..ive seen blocks of code commented out with if *inlr *inlr etc….

    SO do new stuff in free form, use %bifs, clean up when time permits, imbed SQL whenever possible, test it thoroughly and move on to the next change. be consistent with the code that already exists unless the change is substantial.

Leave a Reply