Why Your RPG Code Should Read Like a Recipe (Not a Novel)
Coffee of the day: Green Mountain Horizon Blend. Smooth, balanced, and quietly reliable, it’s the kind of roast you can drink all morning without getting tired of it. It doesn’t overpower—it just supports, giving you steady energy to do the work that matters. In many ways, it reminds me of RPG at its best: not flashy, not complicated for its own sake, but dependable and full of hidden depth when you need it.
I’ve been writing RPG for over 30 years, and I’ve seen every flavor of
bad code you can imagine. I’ve written most of it myself.
- Nested IFs seven levels deep.
- Variables named WK1 through WK9.
- Procedures that do everything
except make coffee.
For years, I thought that was just how RPG worked. You had to be clever.
You had to pack as much logic as possible into as few lines as possible. That
was the craft.
Then I became a manager.
Now I spend more time reading code than writing it. And I’ve learned
something that changed how I think about programming: good code isn’t clever.
Good code is kind.
It’s kind to the person who has to debug it at 2 AM. It’s kind to the
junior developer trying to learn your module. It’s kind to you, six months from
now, when you’ve forgotten why you wrote it that way.
Good code reads like a recipe. Not a novel.
What I Mean by a Recipe
A recipe is predictable. You know where the ingredients are. You know
what each step does. You can scan it quickly and understand the flow. There’s
no mystery, no subplot, no twist ending. You follow it, and you get the result
you expect.
A novel is different. A novel has context you need to hold in your head.
It has characters with backstories. It builds tension. It rewards close
reading. That’s fine for fiction. It’s a disaster for production code.
Most RPG code I see—and most I’ve written—leans too far toward the novel:
- Long procedures with multiple
responsibilities.
- Variables reused across different
contexts.
- Logic that requires tracing
through three files and two service programs to figure out what’s
happening.
You can’t scan it. You have to study it. And most of the time, you don’t
have time to study.
Four Principles of Recipe-Like Code
I’ve boiled it down to four simple principles. They’re not always easy,
but they’re worth it:
- Short procedures with clear names
- A procedure should do one thing
well.
- CalculateDiscount() should calculate a discount.
Not validate customers, log transactions, and update files.
- If you can’t name a procedure
without “and,” it’s doing too much.
- Meaningful variable names
- Forget the six-character limits
of old RPG.
- Use customerNumber, not CUSTNO.
- Use invoiceAmount, not INVAMT.
- Extra characters aren’t
wasted—they’re an investment in clarity.
- Single responsibility for
variables
- Don’t reuse tempValue for three different purposes.
- Don’t let returnCode mean five different things
depending on context.
- Every variable should have one
clear job.
- Comments that explain why, not
what
- Code already tells me what
you’re doing.
- I want to know why.
- “Checked for blank customer ID
to avoid SQL error” is gold.
- “Multiply by 1.05 instead of
constant because of regulatory fee” is gold.
A Real Example
Here’s a procedure I inherited years ago. It calculated pricing for an
order:
DCL-PROC ProcessOrder;
DCL-PI *N;
orderNumber CHAR(10);
END-PI;
DCL-S totalAmount PACKED(9:2);
DCL-S discountAmount PACKED(9:2);
DCL-S taxAmount PACKED(9:2);
DCL-S customerType CHAR(1);
DCL-S WK1 PACKED(9:2);
DCL-S WK2 PACKED(9:2);
// Get customer info
EXEC SQL SELECT CUST_TYPE INTO :customerType
FROM CUSTOMERS WHERE CUST_NO = :orderNumber;
// Calculate total
EXEC SQL SELECT SUM(LINE_TOTAL) INTO :totalAmount
FROM ORDER_LINES WHERE ORDER_NO = :orderNumber;
// Apply discount
IF customerType = 'A';
WK1 = totalAmount * 0.10;
ELSEIF customerType = 'B';
WK1 = totalAmount * 0.05;
ELSE;
WK1 = 0;
ENDIF;
discountAmount = WK1;
totalAmount = totalAmount - discountAmount;
// Calculate tax
WK2 = totalAmount * 0.07;
taxAmount = WK2;
totalAmount = totalAmount + taxAmount;
// Update order
EXEC SQL UPDATE ORDERS
SET ORDER_TOTAL = :totalAmount,
DISCOUNT_AMT = :discountAmount,
TAX_AMT = :taxAmount
WHERE ORDER_NO = :orderNumber;
END-PROC;
It works. But it’s a slog to follow. WK1 and WK2 could mean
anything. The procedure mixes data access, calculation, and persistence all in
one place.
Here’s how I’d rewrite it:
DCL-PROC ProcessOrder;
DCL-PI *N;
orderNumber CHAR(10);
END-PI;
DCL-S customerType CHAR(1);
DCL-S orderTotal PACKED(9:2);
DCL-S discountAmount PACKED(9:2);
DCL-S taxAmount PACKED(9:2);
DCL-S finalTotal PACKED(9:2);
customerType = GetCustomerType(orderNumber);
orderTotal = CalculateOrderTotal(orderNumber);
discountAmount = CalculateDiscount(orderTotal: customerType);
taxAmount = CalculateTax(orderTotal - discountAmount);
finalTotal = orderTotal - discountAmount + taxAmount;
SaveOrderTotals(orderNumber: finalTotal: discountAmount: taxAmount);
END-PROC;
Same logic. But now it’s a recipe: ingredients + steps = result.
You can scan it and know what’s happening. Each subprocedure has a clear
purpose. If you want to change discounts, you head straight to CalculateDiscount().
Why This Matters as a Leader
When I review code now, I’m not just looking for bugs. I’m looking at how
the code treats the next person who reads it.
Clear code is an act of respect. It says: I care about the person who
comes after me.
That mindset scales across a team. Clever tricks might save you 10
minutes today. Clear structure saves your team 10 hours next month.
I also find that once developers learn to write “recipe-like” code, they
get better at explaining designs, writing docs, and communicating in general.
Clarity is a habit, and it carries over.
The One Question I Ask
I end every code review with this:
Could someone read this at 2 AM during an outage and know what to fix?
If the answer is no, it’s not done. Even if it compiles. Even if it
“works.”
Your code will outlive your memory of writing it. Someone else will debug
it under pressure. Don’t leave them a novel. Leave them a recipe.
Final Sips
As I sip my Green Mountain Horizon Blend, I think about how the blend is
smooth, balanced, and dependable—never too strong, never too thin. It’s the
quiet backbone of a productive morning.
That’s exactly what your RPG code should be: dependable, predictable, and
kind to the people who use it long after you’ve moved on.
Write like a chef, not a novelist. Leave a recipe worth following.
Comments
Post a Comment