Best practices working with an .i file & running specific procedures

HT3

ProgressTalk.com Sponsor
Hi All,

I have inherited some code from an old colleague, at the moment it runs 12 different procedures but they are separated by country (I.E. 3 for country A, 3 for country B and 3 for country C).

Two current issues........
The code is 2800 lines (Not large I know).

1. As the procedures are very similar, when making changes I get confused with which country I'm making the amendments for. I find myself making a change in the wrong place. This is slowing me down and I've got to run testing for all countries in case changes have been made to the incorrect procedure.

2. I've got to a minimum of 4 other countries to add... taking my total number of procedures to 28 and increasing the number of lines in the code to 5000.

Due to the reasons mentioned above I think the best way for me to proceed is to separate the procedures into include files by country. I will know I'm making the change in the correct place and reducing my testing.

I'm aware this will be tedious when compiling the code.... :confused:

I know how to call a include file and run it, what I'm struggling with is calling a include file but only running 1 of the three procedures in it. How do I specify the code to run procedure 3 in the include file. I do not want 28 include files....

I'm not set on stone on the above approach, so any advice or thoughts are welcome.

Thanks
 
Warning: coding advice below from a DBA ;)

You don't call an include; it isn't a subroutine. It is a way of encapsulating a piece of code so it can be written once and reused in more than one procedure. These days the common use case is for defining data members like temp-tables or datasets that will be used in several places.

When you reference an include file in some other source file, the code in the include file becomes a part of the code of the parent compile unit at compile time.

E.g.: foo.p:
Code:
/* foo.p */
display "hello" skip.
{include/bar.i}
display "world" skip.

include\bar.i:
Code:
/* start of bar.i */
display "in bar.i" skip.
/* end of bar.i */

compile .\foo.p debug-list foo.dbg

Debug listing for foo.p:
Code:
        1   /* foo.p */
        2   display "hello" skip.
        3
        4   /* start of bar.i */
        5   display "in bar.i" skip.
        6   /* end of bar.i */
        7
        8   display "world" skip.

run .\foo.p
Code:
┌────────┐
│hello   │
│in bar.i│
│world   │
└────────┘

If your parent procedure has an include, and the include file defines internal procedures, the parent code can RUN those IPs just as if they were defined in the parent.

(This can get into discussions and debates on how to encapsulate code, e.g. with classes. You can reads the OE docs for a better explanation of that than I can provide.)

It sounds like you have inherited some redundant code that could be consolidated into a single procedure by parameterizing the country code. If different countries need different handling there are various ways to do that. It could be something simple like a CASE statement that leads to different code blocks, e.g. RUN statements for different internal procedures. But I don't know your requirements so it isn't really appropriate to talk about implementation details. That said, I would avoid using includes for the different pieces of logic.

The point is that you should make your business logic as generic as possible and avoid having a large and potentially increasing number of source files that contain very similar business logic and will be a maintenance headache.
 
FWIW... it is now 2026. Include files do still work but they have not been the primary or best way to accomplish code reuse since about 1990.

Parameterizing your procedures would be much smarter if you have Progress 5 or better.

You can also use parameterized dynamic queries in Progress v9 or better.

If you have OpenEdge 10 or better you can even write object oriented code.

And, if need be, you can get excellent help from AI coding assistants to help guide you through the process. It's ok that they know nothing about Progress. It is very easy to point them at the documentation and get useful results out of them. Just make sure to double check the code and test it as if a wet behind the ears intern who thinks that he knows everything wrote it. (Unlike the intern the AI will actually admit to being wrong...)
 
The best way to handle include files is to burn them with fire. Kill them first and tear them in pieces. Just to be sure ☠

Include files are super handy, but nowadays mostly for temp-table / dataset definitions so you have one definition that is used when using tt / ds as parameter. Using include files for code is really something of the nineties

As for your problem, I think it is wise to separate out similar parts into a procedure of its own and call it with parameters. Then, inside that procedure, use the parameter to determine what to do

Code:
DEFINE INPUT  PARAMETER pcCountry AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER pcCapital AS CHARACTER NO-UNDO.

CASE pcCountry:
  WHEN "BE"  THEN pcCapital = "Brussels".
  WHEN "GE"  THEN pcCapital = "Berlin".
  WHEN "NL"  THEN pcCapital = "Amsterdam".
  WHEN "USA" THEN pcCapital = "New York".
  OTHERWISE pcCapital = "Unknown".
END CASE.

As for AI, I was surprised to find that current models are capable enough to assist with coding, even though ABL is quite an obscure language.
 
Last edited:
As for AI, I was surprised to find that current models are capable enough to assist with coding, even though ABL is quite an obscure language.
I would disagree. I would say they are more than capable. I've had some mega wins in the last couple of months and we're still on 11.7 so can't even make use of the coding assistant etc.
 
Back
Top