21
Sat, Dec
3 New Articles

Top 10 Bad Programming Practices in RPG IV

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

As we start this new year, we need to evaluate some of our RPG IV programming practices. We need to examine their viability as we move forward toward creating compelling new applications for the decades ahead.

While most programs are fundamentally sound, I see a large number of programmers writing routines that work for the moment, but not much more. Their code works as designed until some quirk pops up, and then boom!

Why do people write code that they know won't work under even the most basic of situations? What happens if a blank or zero is sent to a routine that is set up to process the letters a, b, and c? Does it react correctly or blow up? How much additional code is going to be required to allow that same routine to also accept the letters d, e, and f and the numbers 0, 1, and 2?

Time and time again, I've worked with existing code to merely add a simple option here or there. Too often, the code is so poorly written that it effectively takes a rewrite of the logic or a complete isolation of the new code to make these changes. This code often consists of hard-coded routines and values that encapsulate the original requirements only. Essentially, there is no way that anything else is getting in there without a fight. The user need only enter a wrong value and boom! It seems like programmers are protecting the code against future changes and programmers instead of preventing user errors and encouraging future programming enhancements.

This brings me to my 2005 list of the top 10 things most often done wrong in RPG IV. The list has changed since I last ran it roughly two years ago. This time, RPG II and RPG III programming habits seem to dominate the list. Some are just old habits that are apparently difficult to give up, while others are based on the newness of a feature or function and our lack of experience using it. I'll tell you what you shouldn't be doing as well as what you should be doing.

1. The B Data Type

This is a huge pet peeve of mine. Not only do I see from and to columns being specified, but I see the B data type being used pervasively. I suppose there are two reasons for this: 1) IBM continues to ship poorly designed data structures in QSYSINC for RPG IV, including the B data type along with from- and to-column notation, and 2) old habits die hard.

The RPG IV Integer data type supplants the passé binary fields. Binary fields are among the most poorly performing data types, whereas integer fields are some of the best-performing. Whenever you get the urge to use the B data type, replace that with an I, and things will work better.

One reason people continue to use the B data type is that IBM made a design mistake (in my opinion) when it implemented the replacement for B fields; programmers are required to specify the number of digits the field holds rather than use the traditional "size" specifications.

For example, a 2-byte integer is declared as 5I0. Conventionally, integers are referred to in other languages as short, int, long, or long long.

In the IBM documentation, specifically in the API manuals, the integer data type is referred to as BIN or INT (depending on who wrote the manual).

The BIN or INT notation is typically followed by the size of the integer value in bytes, like so:

Bin(2), Bin(4), Bin(8), Int2, Int4  Int8

Yet in RPG IV, this data type is declared as follows:

5I 0, 10I 0, 20I 0

As you can see, there is no obvious association between the RPG IV designation and the documentation. I've created the following table to better illustrate the association.

RPG IV
Designation
C and Java
API Manuals
Alternate API
Manuals
3I 0
char
Bin(1)
char
5I 0
short
Bin(2)
Int2
10I 0
int or long
Bin(4)
Int4
20I 0
long long
Bin(8)
Int8

One final thing: Binary fields are mapped to packed decimal under the covers. This causes a conversion whenever the field is modified. Integer fields are not mapped but are used as is. The IBM compiler development team tells me that integers are the fastest numeric variables when used for array indexes, loop counters, and subscripting.

2. *INKx Indicators for Function Keys

There's just no excuse for this. Granted, an old System/36 RPG II program may still have *INKG in it to exit the program when F7 is pressed, but please don't use these indicators anymore. If you're trying to eliminate the use of indicators 01 to 99 and thus not specifying a response indicator, then use a technique that's been around as long as or longer than the *INKx indicators. The technique is to use position 369 of the workstation's information data structure. In that position, a hexadecimal code uniquely identifies each Fn key as well as the Home, Help, Print, Rollup, Rolldown, etc. keys. For example:

FEDITCUST  CF   E             WORKSTN INFDS(WSDS)
 /COPY FKEYS
D WSDS            DS
D  FKey                          1A   Overlay(WSDS:369)

The copy member, FKEYS, is a series of named constants originally built in 1987 for my book The Modern RPG Language. You can find it in the third edition of The Modern RPG IV Language, or you can download it from the free RPGLab Web site.

It is bad enough that people still use numeric response indicators when you could have code that reads like this:

C                   dou       FKey = F3

So can we please stay away from the *INKx indicators?

3. From/To Columns on the Definition Specifications

This goes hand in hand with the old Binary field data type. Why do people try to be so contemporary in their coding style but then resort to from- and to-column notation in their Definition specifications?

Back in the 1960s and 1970s, when we had data on 80-column cards, a programmer often drew lines between the individual "fields" on the card. Since the columns were numbered, it was easy to transfer the field's from and to columns to your RPG program.

A contemporary example would be the use of the API exception/error data structure. The irony is that while APIs have been around for some 18+ years, programmers still consider them a contemporary programming practice. And yet, when they use APIs, I inevitably see the following data structure in their programs.

D apiError        DS
D  dsLen                  1      4B 0
D  RtnLen                 5      8B 0
D  msgid                  7     15A
D  szReserved            16     16A

This is the standard API exception/error data structure. What I see wrong with this data structure is the use of from and to columns for subfield positions. Today, only length notation should be used. From- and to-column notation should never be used.

If this data structure were written correctly, it would appear as follows:

D apiError        DS                  Inz
D  dsLen                        10I 0 Inz(%size(apiError))
D  RtnLen                       10I 0
D  msgid                         7A
D  szReserved                    1A

Not only is the data structure written with length notation, but the INZ keyword is used to initialize the DSLEN subfield. This allows the field to be initialized to the correct value.

4. Declaring Fields on the Calculation Specifications

When IBM was designing RPG IV, I jokingly suggested eliminating the capability to declare fields on the Calculation specification. I think if there were a fast and direct way to convert RPG III code to RPG IV and move those ad hoc fields on the Calculation specifications to Definitions, IBM would have considered it.

Granted, there is a ton of existing RPG II and RPG III code out there that contains ad hoc fields on the Calculation specification. But in new and modified code today, there is no reason to continue to use this technique.

Often, if I'm in the middle of a routine and need a new field, I insert a D spec right there in the middle of my code--in the middle of the Calc specs--and then move it up with the rest of the D specs when I have time.

5. Using INZ When Declaring Data Structures

Most of the code that has issues with decimal data errors (in both RPG III and RPG IV) could have been easily fixed with one small change. That change is using the Initialization capabilities for data structures. In RPG III, this means inserting an I in column 18 of the Data Structure specification; in RPG IV, it means using the INZ keyword on the Data Structure declaration.

It amazes me how few people use this powerful tool that was added to the language over 15 years ago. The INZ keyword causes the subfields of the data structure to be initialized based on their data type rather than initialized only to blanks. Therefore, numeric fields are initialized to zero, character fields to blanks, and other data types to the default low value.

Try it; this one small change could save you hours of recovery and/or debugging efforts.

6. Using Date Operation Codes

Why are people still coding MULT 10000.01? OK, so virtually no one used true date data type fields in their DDS/database files. I get that. RPG III doesn't support them, so the heck with it. I get it. But if we all have 8-digit zoned numeric fields that contain a date value (or something similar) in our database files, why not simply move them to true date data type fields in RPG IV, do the date math, and then move them back when we're finished? Here's an example:

D InvDate         S               D  
D ShipDate        S                
D INVDTE          S              8S 0 Inz(20050201)
D SHPDTE          S              8S 0

C     *ISO          MOVE      INVDTE        InvDate
C     InvDate       AddDur    5:*DAYS       ShipDate
C     *ISO          MOVE      ShipDate      SHPDTE

The fields INVDTE and SHPDTE are typical 8-digit numeric fields. In this example, I've declared them as 8-digit zoned numeric fields, but they could have just as easily come from a database file, from a READ operation.

The MOVE opcode converts the 8-digit date field INVDTE to a true date data type field named INVDATE. Then, the ADDDUR opcode adds a duration to the date value. The result is stored in a second date field named SHIPDATE.

To convert the resulting date value back to an 8-digit numeric field, the MOVE opcode is used once again.

It is so easy to convert between numeric and date fields that it seems careless to avoid the use of date operation codes and date data types.

7. Procedures and Subprocedures

When it comes to programming in the year 2005, the use of procedures in RPG IV should be mainstream. There is no compelling reason to avoid using subprocedures. Perhaps the biggest issue is writing your first procedure. Or perhaps it is understanding the difference between a procedure and a subprocedure. The difference is simple: There is none. The term subprocedure is the official RPG IV terminology for what we in programming conventionally refer to as a procedure or function. What's the difference between a procedure and a function? A function returns a value to its caller, and a procedure does not. So if you call everything a procedure, you are technically correct.

If you need to write that first procedure to help get you started, you may want to review my article on the subject. In addition, you could go to RPG World in Las Vegas in May and attend the pre-conference workshop.

8. Hard-Coding

Hard-coding, like using magic numbers, happens a bit too frequently in RPG. Instead of using a variable or an array of elements, many programmers will hard-code a routine instead of building in flexibility. This means routines are often coded more rigidly than they need to be and then left that way.

Hard-coding a routine is usually the first pass a programmer makes when writing the routine. But then, a programmer should revisit the routine to implement it in a more flexible manner.

To make a routine more flexible, avoid the use of literals, including numbers in mathematical operations. Use fields or named constants to store values so they can be modified. If possible, build in conditional logic that allows a future programmer to easily insert or modify the code. Here's an example:

C                   SELECT
C                   When      fKey = F3
C                   if        CleanUp() = b_OK
C                   Return
C                   endif
C                   When      fKey = F5
C                   callp     Refresh()
C                   When      fKey = F11
C                   callp     ToggleDsp()
C                   endSL

If another programmer needs to add logic to handle function key 6, it is not only apparent where to do that, but also easy to do.

What makes the above routine flexible? The Select/When clause combined with calling subprocedures moves the implementation into the subprocedures and compartmentalizes it, keeping it away from the main line logic of the routine. So it becomes relatively easy to modify and change this code.

And Then There Are the Magic Numbers...

This one continues to plague the code I work with, and then I have to go back and correct it. And I see it in nearly every program I maintain.

RPG III introduced the concept of named constants, and RPG IV made it much easier to declare them. Named constants help provide documentation and identification of values in a program. For example, what does the number 12 mean in the following code segment?

D I               S             10I 0
D sales           S              7P 2 Dim(12)

C                   for       I = 1 to 12
C                   eval      Total = Total + Sales(i)
C                   endfor

The number 12 could represent the number of months in the year, the number of sales periods, or something entirely different.

What happens when programmers need to maintain this code? How do they associate the number 12 in the FOR loop with the number of elements in the SALES array? What if there are other sections of code that also use the number 12, some that apply to this example and others that do not?

A better approach to programming is to convert that "magic number" into a named constant and then use that named constant throughout the code where applicable. For example, the following modified code would be much easier to analyze and modify, so it would cost less to maintain than hard-coded magic numbers.

D I               S             10I 0
D sales           S              7P 2 Dim(12)
D SALES_PERIODS   C                   Const(%elem(SALES))

C                   for       I = 1 to SALES_PERIODS
C                   eval      Total = Total + Sales(i)
C                   endfor

9. Calling Modules

It seems like more people are attempting to move to modules (*MODULE objects), which means using procedures, and this is all good. But some are simply using CRTRPGMOD to compile converted RPG III code into a module and then replacing an old CALL operation with a CALLB or CALLP to the old program name. Since the program is now a module, they are calling the module instead of a procedure name. This couldn't be further from what is desired.

Calling a module name is just wrong. Here's how it works: When you compile a source member that has no procedures in it as a module, the compiler generates a procedure for the mainline calcs with the same name as the source member. Consequently, that name is also the same as the module that was created. If you bind that module with another, and the second module has a call to the first one by name, it gives you the illusion that you're calling the module.

Granted all of this does work, but just feels wrong. It is as wrong as coding a PWRDWNSYS command in the middle of CL program. You can do it, but why the heck would you want to?

If you want to use CALLB or CALLP, use procedures and call those procedures. Don't do a half-hearted effort and lie to yourself that you're "using ILE." You're not.

10. Using Forums and Email List Services to Learn RPG IV

This is more of a political view than anything else. Many times, I'll see questions on the RPG email list services that are good solid questions. But then, the same author will ask a follow-up question and then another and another until it becomes apparent that the person posing the questions doesn't know anything about the topic.

This leads me--and others who frequent those lists and provide help--to believe that the author of the questions is actually trying to learn an entire topic through the list service rather than read a book, take a class, or attend a Web seminar on that topic.

This does two things: It clutters up the list services with questions that many people are uninterested in, and it often upsets the regulars on the list.

Granted, the lists are there for people to ask questions, and people should continue to do that. The problem, however, is very specific: When people keep probing the free advice on the list in order to try to teach themselves a new subject from start to end, they alienate the people on the list who are offering the free advice.

This activity leads to any of several different outcomes, but at the end of the day, it is just wrong to abuse this privilege.

So, if you have questions, please ask them, but if you don't know anything about a topic and want to learn, limit your questions to "where can I learn more about [subject x]?"

Bob Cozzi is a programmer/consultant, writer/author, and software developer. His popular RPG xTools add-on subprocedure library for RPG IV is fast becoming a standard with RPG developers. His book The Modern RPG Language has been the most widely used RPG programming book for more than a decade. He, along with others, speaks at and produces the highly popular RPG World conference for RPG programmers.

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: