Write Code That Others (and Future You) Will Thank You For
Few technical subjects stir stronger passions than programming standards. Some shops want almost none, others want a rule for everything. The truth is that good standards are shop-specific. They should fit your organization, your team, and the type of applications you maintain.
In this lesson I give you a practical, battle-tested set of RPG IV style guidelines. These are the ones I recommend you adopt (or adapt) so your code stays readable, maintainable, and professional. I promise to keep the list short enough that everyone can remember it and only focus on the important things.
Comments – Less Is More
Good comments explain why something exists, not what the code is doing. If your code is clear, you need fewer comments.
Best Practices for Comments
- Always include a brief prologue at the top of every program and every subprocedure.
- The prologue should contain:
- Program or procedure title
- Short description of purpose
- Change history (date, programmer, reason for change)
- Summary of indicator usage (if any)
- Procedure interface description (return value and parameters)
- Example of how to call the procedure
- Use consistent marker lines (dashes or asterisks) to separate major sections: declarations, main procedure, subroutines, and subprocedures.
- Use single blank lines to group related lines of code. Do not use multiple consecutive blank lines.
- Never put right-hand “end-of-line” comments in columns 81-100 in legacy column-based RPG. If a line needs a comment, give it its own comment line above or below.
Example of a clean prologue
/// ------------------------------------------------------------------------------
///
/// Program: PROGNAME - Brief Program Title
///
/// Description: Comprehensive explanation of the program's purpose and
/// functionality. Use multiple lines as needed with proper
/// indentation for readability.
///
/// Purpose: Educational/Production utility demonstrating:
/// - SQL embedded in RPG for data access
/// - Key concept or pattern #1
/// - Key concept or pattern #2
/// - Additional concepts as needed
///
/// Features:
/// - SQL cursor operations for efficient data retrieval
/// - Specific capability #1
/// - Specific capability #2
/// - Design pattern or best practice demonstrated
/// - Performance considerations
///
/// Control Options:
/// - main(mainline): Eliminates RPG cycle overhead
/// - optimize(*full): Maximum optimization
/// - option(*nodebugio:*srcstmt:*nounref): Debug and compile options
/// - pgminfo(*pcml:*module): Embeds parameter metadata
/// - actgrp(*new/*caller): Activation group strategy
/// - indent('| '): Code indentation character
/// - alwnull(*usrctl): Allow null-capable fields
///
/// SQL Options:
/// - commit(*none): No commitment control
/// - closqlcsr(*endmod): Close cursors at module end
///
/// Usage: CALL PROGNAME or detailed usage instructions
///
/// Parameters (if applicable):
/// - parm1: type - Description of parameter
/// - parm2: type - Description of parameter
///
/// Dependencies:
/// - Database tables or views accessed
/// - Required files, service programs, or APIs
/// - External resources needed
///
/// Copybooks Required:
/// - header.rpgleinc: Standard control options
/// - Other includes as needed
///
/// Reference:
/// https://www.nicklitten.com/relevant-blog-post-url
///
/// Modification History:
/// V.000 YYYY-MM-DD | Nick Litten | Initial creation
///
/// ------------------------------------------------------------------------------
Declarations - Keep Everything in D-Specs
RPG IV finally gave us a proper place to declare everything.
- Declare all variables, constants, and data structures in D-specs (or free-form dcl- statements).
- Do not declare variables in C-specs except for key lists and parameter lists (and even those belong at the top).
- Whenever a literal has meaning, make it a named constant.
- Indent data item names inside data structures to improve readability.
- Prefer length notation over positional notation in data structures.
- Use the OVERLAY keyword instead of positional notation when fields overlap.
- For compile-time arrays, always use the **CTDATA form.
For example:
Prefix char(3);
MsgID char(4);
Major char(2) overlay(MsgID:1);
Minor char(2) overlay(MsgID:3);
end-ds;
Naming Conventions
The single most important part of style is the names you choose.
- Make every name fully descriptive and unambiguous.
- Use mixed case to make names readable (e.g., CustomerNumber, CalcTax).
- Use verb/object naming for subroutines and procedures (e.g., LoadCustomer, ValidateOrder).
- Avoid special characters (@ # $ _) whenever possible.
- Keep names 10 to 14 characters long in most cases. Longer is acceptable in fully free-form source.
Indicators - Use Them Sparingly
Indicators are a legacy feature. Modern RPG can live with very few of them.
- Eliminate indicators wherever possible.
- Prefer built-in functions: %EOF, %FOUND, %ERROR, %EQUAL, etc.
- If you must use indicators, give them meaningful names using an INDDS data structure or the array-overlay technique.
- Never use conditioning indicators (columns 7-11) on calculation lines. Use IF, SELECT, or FOR instead.
- Document any indicator you do use, especially U1-U8 or those sent to display/printer files.
Structured Programming Techniques
Always write structured code.
- Never use GOTO, CABxx, or COMP.
- Use IF / ELSE / ENDIF, SELECT / WHEN / OTHER / ENDSL, and DO / DOU / DOW / FOR.
- Always qualify the ending opcode: ENDIF, ENDDO, ENDSL.
- Use ITER and LEAVE for loop control instead of tricks.
- Avoid obscure “bit-twiddling” opcodes unless there is no better alternative.
Modular Programming Techniques
ILE RPG and the Integrated Language Environment encourage modularity.
- Always prototype every called procedure or program (dcl-pr).
- Store prototypes and related constants in /COPY members.
- Use IMPORT and EXPORT only for truly global items that are set once and never changed.
- Build service programs. Keep related procedures together.
Character String Manipulation
RPG IV has excellent string handling. Use it.
- Declare string constants as named constants instead of arrays.
- Use built-in functions (%SCAN, %SUBST, %TRIM, %REPLACE, %CONCAT, etc.) instead of old tricks with arrays or data structures.
- Prefer free-form EVAL for assignments involving strings.
Avoid Obsolescence
RPG is over 30 years old!
Many original features are still there but should not be used.
- Do not sequence line numbers in columns 1-5.
- Use externally described files (EXTFILE, EXTDESC) instead of program-described files.
- If a free-format version of an opcode exists, use it (IF instead of IFxx, CALLP instead of CALL, etc.).
- Prefer built-in functions over opcodes when both do the same job.
- Avoid CALL, CALLB, PARM, PLIST, DEBUG, FREE, and other obsolete opcodes.
Final Advice
When good style and raw performance conflict, choose good style.
Always:
Hard-to-read programs are hard to debug, hard to maintain, and hard to get right.
