COBOL Module 15 – Modern tooling, performance and safe change
Modernising COBOL: wrappers, APIs and safe change
Compare wrapping, refactoring, rehosting and rewriting COBOL, give its rules a JSON interface, and change it with tests, rollback and reconciliation.
What you will learn
- Compare keeping and wrapping, refactoring, rehosting and rewriting a COBOL system for a given need
- Wrap COBOL business logic in a JSON interface without changing its results
- Plan a change with golden tests, a way back and side-by-side reconciliation
- Protect personal and financial data in test environments and in logs
Before you start
What you’ll learn · Before you start
What you will learn
- Compare keeping and wrapping, refactoring, rehosting and rewriting a COBOL system for a given need
- Wrap COBOL business logic in a JSON interface without changing its results
- Plan a change with golden tests, a way back and side-by-side reconciliation
- Protect personal and financial data in test environments and in logs
Before you start
On this page
INTCALC has worked out the month’s interest of every account since it was written, and now a mobile app needs the same answer, as JSON, over HTTP. Rewriting it means deriving every rule again, its rounding included; wrapping it means about 70 lines of COBOL around a program that does not change.
This lesson compares the ways to move a COBOL system, wraps INTCALC in a JSON interface that ran under GnuCOBOL 3.2, and sets out what makes any change safe: tests that record today’s results, a way back, a comparison of old and new on the same input, and test data and logs that expose no customer.
Four ways to move a COBOL system, and what each one risks
A system can be moved four ways, and each changes something different:
- Keep and wrap leaves the programs as they run and gives new callers an interface to them.
- Refactor changes the structure of the COBOL in small steps, each proved against golden output.
- Rehost moves the same COBOL to another platform, where another compiler, runtime and job control run it.
- Rewrite derives the system again in another language, every rule and every rounding included.
They differ most in risk to today’s results. Keeping and wrapping changes no rule. Refactoring and rehosting change how the rules are expressed or run, which golden outputs can check. A rewrite changes everything at once, and Martin Fowler writes that he and his colleagues have seen such plans fail most of the time. His alternative is to replace a system piece by piece around its edges, which a wrapper makes possible. Answer three questions about a system:
Answer the questions above: the table then marks what fits your case and says why the rest does not.
| Way | The proven rules | Leaves the platform | Risk to results | First value |
|---|---|---|---|---|
| Keep and wrap Changes: an interface around the programs | Good kept as they run today, called by new callers | Poor no: the programs stay where they run | Good low: the rules do not change | Good early: one interface at a time |
| Refactor Changes: the structure of the COBOL | Mixed kept if every step is checked against golden output | Poor no: it stays COBOL where it runs | Mixed small steps, each proved by tests | Mixed easier change later, little new for users |
| Rehost Changes: the platform the COBOL runs on | Mixed same source, another compiler and runtime | Good yes, with the COBOL kept | Mixed dialects, data formats and job control differ | Mixed when the whole system has moved |
| Rewrite Changes: the language and the code | Poor every rule derived again, rounding included | Good yes, and the language too | Poor high when done in one go | Poor late, unless it replaces one piece at a time |
How the answers decide
- “Do the system's rules still give the answers the business wants?” No, some rules are wrong or unwanted: adds a caveat to Keep and wrap and Rehost. Wrapping or moving rules that are wrong keeps them wrong: change those rules first, with tests that state the new answers.
- “Must the platform or the language go, for example a runtime that will not be supported?” Yes, it has to go: rules out Keep and wrap and Refactor. Wrapping and refactoring keep the programs where they run, so they cannot take the system off the platform.
- “Do you have tests or golden outputs that record what the system does today?” No, not yet: adds a caveat to Refactor, Rehost and Rewrite. Without a record of today's results, nobody can show that the changed system gives them: record golden outputs first.
The case for any of them is best made from the system’s own numbers, its run times, its failed changes and its cost to run, rather than from statistics about COBOL in general, which are often repeated without a source.
Checkpoint
Check: Four ways to move a COBOL system
A wrapper keeps the rules and adds a JSON interface
INTAPI is a wrapper: A program that puts a new interface in front of an existing one without changing it: it converts each request into the existing program's interface, calls it and turns the reply into the caller's format, such as JSON.. It reads a request that an API layer has already parsed, calls INTCALC with the same interface as the batch, INT-PARM, and writes one JSON reply with JSON GENERATE. IBM’s reference for the statement allows NAME OF … IS OMITTED to generate an anonymous JSON object, and the reply reports a word, paid, none or refused, instead of the status code the batch uses:
IDENTIFICATION DIVISION.
PROGRAM-ID. INTAPI.
* A JSON interface around INTCALC, which it calls unchanged.
* The API layer in front of it has already parsed each request
* into one line of REQUESTS: an account, a balance and a yearly
* rate. For each one INTAPI calls INTCALC and writes one JSON
* reply, with the result as a word instead of a status code.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT REQUEST-FILE ASSIGN TO "REQUESTS"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS REQUEST-STATUS.
DATA DIVISION.
FILE SECTION.
FD REQUEST-FILE.
01 REQUEST-LINE.
05 R-ACCOUNT PIC X(10).
05 FILLER PIC X.
05 R-BALANCE PIC X(12).
05 FILLER PIC X.
05 R-RATE PIC X(6).
WORKING-STORAGE SECTION.
01 REQUEST-STATUS PIC XX.
COPY INTPARM.
01 REPLY.
05 REPLY-ACCOUNT PIC X(10).
05 REPLY-INTEREST PIC S9(9)V99.
05 REPLY-RESULT PIC X(7).
01 JSON-OUT PIC X(200).
01 JSON-LEN PIC 9(4).
PROCEDURE DIVISION.
MAIN-PARA.
OPEN INPUT REQUEST-FILE
IF REQUEST-STATUS NOT = "00"
DISPLAY "INTAPI: REQUESTS status " REQUEST-STATUS
MOVE 12 TO RETURN-CODE
STOP RUN
END-IF
READ REQUEST-FILE
PERFORM UNTIL REQUEST-STATUS NOT = "00"
PERFORM ONE-REQUEST
READ REQUEST-FILE
END-PERFORM
CLOSE REQUEST-FILE
STOP RUN.
ONE-REQUEST.
COMPUTE INT-BALANCE = FUNCTION NUMVAL(R-BALANCE)
COMPUTE INT-RATE = FUNCTION NUMVAL(R-RATE)
CALL "INTCALC" USING INT-PARM
MOVE R-ACCOUNT TO REPLY-ACCOUNT
MOVE INT-INTEREST TO REPLY-INTEREST
EVALUATE INT-STATUS
WHEN 0 MOVE "paid" TO REPLY-RESULT
WHEN 4 MOVE "none" TO REPLY-RESULT
WHEN OTHER MOVE "refused" TO REPLY-RESULT
END-EVALUATE
JSON GENERATE JSON-OUT FROM REPLY COUNT IN JSON-LEN
NAME OF REPLY IS OMITTED
REPLY-ACCOUNT IS "account"
REPLY-INTEREST IS "interest"
REPLY-RESULT IS "result"
IF JSON-CODE = 0
DISPLAY JSON-OUT (1:JSON-LEN)
ELSE
DISPLAY "INTAPI: JSON-CODE " JSON-CODE
MOVE 12 TO RETURN-CODE
END-IF. from session import files, run
# INTAPI built with INTCALC, unchanged, and run on five requests that an API layer has already parsed: one JSON reply
# for each request.
files("src/INTAPI.cob", "src/INTCALC.cob", "copy/INTPARM.cpy", "data/requests.txt")
run("""
cat data/requests.txt
cobc -x -Wall -I copy -o INTAPI src/INTAPI.cob src/INTCALC.cob && DD_REQUESTS=data/requests.txt ./INTAPI
""") Output
$ cat data/requests.txt
AC00000042 25000.00 0.0650
AC00000077 1200.00 0.0350
AC00000123 -450.75 0.0650
AC00000150 987654.32 0.0725
AC00000199 10000.00 0.2500
$ cobc -x -Wall -I copy -o INTAPI src/INTAPI.cob src/INTCALC.cob && DD_REQUESTS=data/requests.txt ./INTAPI
{"account":"AC00000042","interest":135.42,"result":"paid"}
{"account":"AC00000077","interest":3.50,"result":"paid"}
{"account":"AC00000123","interest":0.00,"result":"none"}
{"account":"AC00000150","interest":5967.08,"result":"paid"}
{"account":"AC00000199","interest":0.00,"result":"refused"}
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 api_session.py
The interest of AC00000042 and AC00000150, 135.42 and 5,967.08, is what the month-end report of the tooling lesson printed for them, because the same rules ran. Parsing stays in the API layer here: in GnuCOBOL 3.2, JSON PARSE compiles with a pending warning and does nothing, as the JSON lesson showed. Enterprise COBOL offers more ways in, among them a directive that makes an existing COBOL program callable from Java. Step through a request:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- A new caller. An app asks for the month's interest of AC00000042. It knows nothing of COBOL; it sends JSON to an API layer.
- The API layer. The layer parses the JSON and passes the fields to INTAPI as one request line. In GnuCOBOL 3.2, JSON PARSE compiles but does nothing, so parsing happens here.
- The rules, unchanged. INTAPI fills INT-PARM and calls INTCALC, the same subprogram and the same interface as the batch. Nothing in INTCALC was edited for the new caller.
- The reply. JSON GENERATE turns the reply into one JSON object, interest 135.42 and result paid, with the names the interface promised and no outer group name.
- The batch, as before. STMTRUN calls the same INTCALC for the month-end report, which printed 135.42 for the same account in the tooling lesson. One set of rules now serves both.
Key idea
A wrapper adds a way in and changes no rule, so new callers get the batch’s own answers: INTAPI replied 135.42 and 5,967.08, as the month-end report printed them.
Checkpoint
Check: A JSON wrapper around unchanged rules
A safe change has tests, a way back and a comparison
Whichever way is chosen, a change to a system that pays interest is planned around four parts:
| Part | The question it answers |
|---|---|
| Golden outputs and unit cases | Does the changed system still give today’s results? |
| A way back | Can the old version run again within minutes, by a switch? |
| Side-by-side reconciliation | Do old and new agree on the same input, account by account? |
| Data handling | Do test data and logs hold no real customer’s details? |
side-by-side reconciliation: Running an old system and its replacement on the same input and comparing their results record by record, so that every difference between the two is found before the replacement is relied on. runs the old system and the new one on the same input and compares their results record by record. A way back keeps the old version installed and runnable until the new one has proved itself. A replacement can earn that proof in phases: it first runs in the shadow of the old system, on the same input, then answers for one slice of the accounts at a time. Golden outputs come first, because neither the comparison nor the way back means anything without a record of what right looks like. Data handling keeps every environment but production on synthetic or masked data, and keeps full account numbers out of logs.
Checkpoint
Check: The parts of a safe change
Practise: the ways, the wrapper and the plan
These questions check the ways, the wrapper and the plan, and every answer explains itself, a wrong one by the mistake behind it.
Practice that adapts to you
Practise this lesson
9 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Side-by-side reconciliation: old and new on the same input, account by account Pro: opens with a Pro, Premium or Ultimate pass
A rewrite that passes its own tests can still disagree with the system it replaces. This part runs the old interest batch and a rewrite on the same accounts, finds the accounts where they differ and why, and proves the fix with the same comparison.
In this part:
- Two systems, one input, compared account by account
- Why the rewrite lost a hundredth, and the fix that matched
- What a reconciliation compares, and what it reports
1 diagram · 4 runnable examples (AWK, Python, Shell) · about 5 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Replacing in slices, with a way back at every phase Pro: opens with a Pro, Premium or Ultimate pass
A replacement that switches everything at once has no way back that does not lose work. This part sets out six phases that move the interest run one slice at a time, each with what proves it and how it is undone.
In this part:
- Six phases, from recording to retiring
- What decides each move, and how it is undone
- Routing a slice so that each account always takes the same path
1 diagram · about 5 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Test data and logs that expose no customer Pro: opens with a Pro, Premium or Ultimate pass
Every environment but production is a copy someone did not secure. This part sets out where test data comes from, what a log line may contain, and has you write a log line that masks account numbers and cannot be forged.
In this part:
- Synthetic and masked data for every environment but production
- Log lines that cannot leak or be forged
- Write log lines that show no account number and cannot be forged
- Results of the sample tests
1 exercise with sample tests · about 5 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Interview questions
A warm-up answered in full, then three questions about changes to systems that pay interest:
-
Fresher to mid · Warm-up
What does it mean to wrap a COBOL program, and when is that better than rewriting it?
Wrapping keeps a COBOL program as it is and puts an interface in front of it, so that new callers, such as an app calling over HTTP, can use its rules. The wrapper converts the caller's request into the program's own interface, calls it, and turns the reply into the caller's format, for example JSON with JSON GENERATE. Because the rules behind it do not change, a wrapped calculation gives new callers exactly the answers the batch gives. It is better than a rewrite when the rules are right and still wanted and the platform can stay: nothing that works is put at risk, and the new callers get their interface early. A rewrite fits when the platform or the rules themselves have to go, and even then is safer done piece by piece.
-
Senior to staff
Leadership wants a 30-year-old COBOL interest system rewritten in Java and switched over in one weekend. What do you propose instead, and how do you show progress and safety at every step?
-
Mid to senior
A mobile app must show the same monthly interest as the bank's statement, which a COBOL batch computes. How do you give the app that number so that the two can never disagree, and how do you prove it?
-
Senior to staff
Side-by-side runs of an old COBOL batch and its replacement disagree on 0.3 % of accounts, each by one hundredth. How do you find the cause, decide which system is right, and decide when the replacement may answer customers?
Organisations named on this page
MySmartCoPilot has no connection with IBM, OWASP or the authors cited. Enterprise COBOL’s statements and directives are described from IBM’s documentation, and every run on this page used GnuCOBOL 3.2.
Flashcards · 7 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
What are the four ways to move a COBOL system?
Keep and wrap: leave the programs and give new callers an interface. Refactor: change the structure in small proven steps. Rehost: run the same COBOL on another platform. Rewrite: derive the system again in another language.
-
Which way of moving a COBOL system puts today's results most at risk?
A rewrite in one go, which must derive every rule and rounding again at once. Keeping and wrapping changes no rule, and refactoring and rehosting can be checked against golden outputs.
-
What does a wrapper program such as INTAPI do?
It gives new callers a way in, JSON behind an API layer, and calls the existing program through the batch's own interface, so it returns the batch's own answers: 135.42 and 5,967.08.
-
What four parts does a safe change to an interest system need?
Golden outputs and unit cases, a way back to the old version, side-by-side reconciliation of old and new on the same input, and test data and logs that hold no real customer's details.
-
What is side-by-side reconciliation?
Running the old system and the new one on the same input and comparing their results record by record, account by account.
-
Why do golden outputs come first in a modernisation plan?
Neither the comparison of old and new nor the way back means anything without a record of what right looks like.
-
How can a replacement earn its proof before it takes over?
First it runs in the shadow of the old system on the same input, then it answers for one slice of the accounts at a time, with the old version kept runnable as the way back.
Key takeaways
- Keep and wrap, refactor, rehost and rewrite differ most in risk to today’s results, and a rewrite in one go carries the most.
- A wrapper such as INTAPI gives new callers a JSON interface to rules that do not change, so it printed the batch’s own 135.42 and 5,967.08.
- A safe change has golden outputs, a way back, side-by-side reconciliation and test data and logs that expose no customer, with the golden outputs first.
Terms in this lesson
- side-by-side reconciliation
- Running an old system and its replacement on the same input and comparing their results record by record, so that every difference between the two is found before the replacement is relied on.
- wrapper
- A program that puts a new interface in front of an existing one without changing it: it converts each request into the existing program's interface, calls it and turns the reply into the caller's format, such as JSON.
References
- Enterprise COBOL for z/OS 6.5: JSON GENERATE statement (IBM)
- Enterprise COBOL for z/OS 6.5: COBOL/Java interoperability outside the OO COBOL framework (IBM)
- Enterprise COBOL for z/OS (IBM)
- GnuCOBOL 3.2 NEWS (GnuCOBOL project (GNU))
- Strangler Fig Application (Martin Fowler)
- OWASP Logging Cheat Sheet (OWASP Foundation)
- OWASP Secrets Management Cheat Sheet (OWASP Foundation)
- Open Mainframe Project COBOL Programming Course (Open Mainframe Project)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress