Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

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.

  • Advanced
  • 20 minutes
  • Examples run with GnuCOBOL 3.2, Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 7 of 20 minutes free
Free: Four ways to move a COBOL system, and what each one risks · A wrapper keeps the rules and adds a JSON interface · A safe change has tests, a way back and a comparison · Practise: the ways, the wrapper and the plan. With a pass: 3 in-depth parts and 3 interview answers, about 13 minutes.

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

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:

Interactive · answer and compare Which way fits this COBOL system? Answer three questions about the system. The table marks the ways that fit and says why the others do not.
Do the system's rules still give the answers the business wants?
Must the platform or the language go, for example a runtime that will not be supported?
Do you have tests or golden outputs that record what the system does today?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Four ways to move a COBOL system against the four things that decide between them
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

  1. One question The interest rules are right and still wanted, the platform can stay, and a mobile app needs them over HTTP. Which way fits best?

    Choose one answer.

    Show the answer: One question

    Answer: Keep and wrap, giving the app an interface to the rules as they run

    The trade-off table rules out nothing for these answers, and wrapping carries the least risk to today's results.

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:

src/INTAPI.cob: a JSON interface around INTCALC COB · src/INTAPI.cob
       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.
INTAPI built with INTCALC and run on five requests Python · api_session.py
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:

Interactive · step by step A JSON interface around a program that does not change Step through one request from a new caller to INTCALC and back, then the batch that calls the same program.
A JSON interface around a program that does not change, step 5 of 5. Showing Mobile app or service, API layer, INTAPI ({"interest":135.42,…}), INTCALC, STMTRUN. In focus: STMTRUN, INTCALC.requestone request lineCALL USING INT-PARMthe same CALLMobile app or servicesends JSON over HTTPAPI layerJSON in, fields outINTAPI{"interest":135.42,…}INTCALCunchanged, testedSTMTRUNthe batch, as before

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.

JSON Validator Paste one of INTAPI's replies to check that it is valid JSON before an API layer relies on it.

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

  1. One question Why did INTAPI reply with interest 135.42 for AC00000042, the same as the month-end report?

    Choose one answer.

    Show the answer: One question

    Answer: Because it calls the same INTCALC, with the same interface, so the same rules ran

    One set of rules serving the batch and the API is the point of wrapping: the two cannot drift apart.

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

  1. One question A team has a rewrite, a switch to go back, and synthetic test data, but no record of the old system's results. What should they add first?

    Choose one answer.

    Show the answer: One question

    Answer: Golden outputs of the old system on fixed input, because every comparison needs them

    Golden outputs come first; reconciliation and the way back build on them.

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.

  1. Question 1 of 9 What does "keep and wrap" change in a COBOL system?

    Choose one answer.

    Show the answer: Question 1 of 9

    Answer: Only the way in, an interface for new callers; the programs run as they did

    Each of the four ways changes one thing; wrapping changes the least.

  2. Question 2 of 9 Why does a rewrite in one go carry the most risk to today's results?

    Choose one answer.

    Show the answer: Question 2 of 9

    Answer: Every rule, rounding included, is derived again at once, and every caller moves to the new code in one step

    The alternative replaces piece by piece, around a wrapper, with old and new compared.

  3. Question 3 of 9 A runtime will lose support, so the platform has to go, but the rules are right and there are golden outputs. Which ways remain?

    Choose one answer.

    Show the answer: Question 3 of 9

    Answer: Rehost or rewrite, and rehosting keeps the proven COBOL

    With golden outputs, either remaining way can be proved; rehosting changes less.

  4. Question 4 of 9 What does NAME OF REPLY IS OMITTED do in INTAPI's JSON GENERATE?

    Choose one answer.

    Show the answer: Question 4 of 9

    Answer: It leaves out the outer name REPLY, so each reply is an anonymous JSON object

    Without it, every reply would be wrapped in {"REPLY": …}, a COBOL name the app has no use for.

  5. Question 5 of 9 A team plans to give the app its own copy of the interest rules, written in the app's language, "to save a call". What does the wrapper design avoid that this plan risks?

    Choose one answer.

    Show the answer: Question 5 of 9

    Answer: Two sets of rules that can drift apart, so the app and the statement show different interest

    One set of rules, many callers.

  6. Question 6 of 9 Why does the lesson's API layer parse the request JSON instead of INTAPI itself?

    Choose one answer.

    Show the answer: Question 6 of 9

    Answer: In GnuCOBOL 3.2, JSON PARSE compiles with a pending warning and does nothing, so the parsing must happen outside

    On Enterprise COBOL, which has JSON PARSE, the split could be drawn elsewhere; the rules would still stay in INTCALC.

  7. Question 7 of 9 Which part of a safe change comes first?

    Choose one answer.

    Show the answer: Question 7 of 9

    Answer: Golden outputs and unit cases that record today's results

    Record, then change, then compare.

  8. Question 8 of 9 What does side-by-side reconciliation compare?

    Choose one answer.

    Show the answer: Question 8 of 9

    Answer: The results of the old and the new system on the same input, record by record

    Reconciliation turns "the new system should behave like the old one" into a count of differences.

  9. Question 9 of 9 The new interest service went live and the old batch was removed the same night. On day two a difference is found. What does this plan lack?

    Choose one answer.

    Show the answer: Question 9 of 9

    Answer: A way back: the old version kept installed and runnable, chosen by a switch, until the new one had proved itself

    The old system is retired last, when nothing depends on it, not on the night the new one starts.

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.

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.

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.

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:

  1. 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.

  2. 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?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. 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?

    Model answer, Pro. First step and follow-ups

  4. 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?

    Model answer, Pro. First step and follow-ups

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  7. 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

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.