Engineering2026-05-19
Reading a COBOL codebase you did not write
The programs are the last thing to read. Start with the job control and the copybooks, because that is where forty years of business rules were actually written down.
- Author
- Halvard Bruun
- Published
- 19 MAY 2026
- Read
- 5 MIN
- Ref
- DBAB91
An engineer handed 210,000 lines of COBOL will usually open the largest program first. It is the wrong move. The largest program is largest because it accreted, and its structure will teach you nothing except that a lot of people have been here before you.
COBOL systems keep their meaning in two places, and neither is the procedure division. Start with the job control, then the copybooks. The programs come third, and by then most of them will be readable.
Job control is the architecture diagram
The JCL tells you what runs, in what order, reading which datasets and writing which others. That is the dataflow, recorded in an executable form that could not have drifted from reality, because the system would have stopped.
Read the nightly batch scheduler definitions and draw the graph: job, step, program, input datasets, output datasets, condition codes. A week of this gives you something the organisation almost certainly does not have — an accurate picture of which programs matter, which datasets are hand-offs between business domains, and which steps are conditional on a return code from a step that runs three hours earlier.
Condition-code logic deserves particular attention. COND=(4,LT) on a step is a business rule expressed in job control, and it will not appear in any program listing you read.
The copybooks are the domain model
A copybook is a shared record layout, included by every program that touches the data. It is the closest thing the system has to a schema, and it is where the domain vocabulary lives.
01 WS-POLICY-RECORD.
05 WS-POL-ID PIC X(10).
05 WS-POL-STATUS PIC X.
88 POL-ACTIVE VALUE 'A'.
88 POL-LAPSED VALUE 'L'.
88 POL-CANCELLED VALUE 'C' 'X' 'Z'.
88 POL-CHARGEABLE VALUE 'A' 'L'.
05 WS-POL-PREMIUM PIC S9(9)V99 COMP-3.
05 WS-POL-EXTRA PIC X(40).
05 WS-POL-MOTOR REDEFINES WS-POL-EXTRA.
10 WS-MOT-REG PIC X(8).
10 WS-MOT-NCD-YEARS PIC 9(2).
10 FILLER PIC X(30).
Twelve lines, four findings.
Level-88 items are business rules with names. POL-CANCELLED matches three status codes. C is the documented one; X and Z arrived with acquisitions in 1998 and 2004 and appear in no data dictionary. Any rewrite that treats status as a three-value enum will silently mis-handle every policy inherited from those books.
Overlapping 88s encode policy. POL-CHARGEABLE covers active and lapsed. Somebody decided lapsed policies still attract a charge. That decision exists nowhere else.
COMP-3 is packed decimal, not binary. S9(9)V99 COMP-3 occupies six bytes, holds a signed value to two implied decimal places, and is exact. Migrating it to a float is the single most common data-migration defect we see, and it surfaces months later as pennies of drift in a reconciliation.
REDEFINES is an untyped union. The same 40 bytes mean different things for different products, and the discriminator is not in the record. It is in whichever program decided which layout to use — so you must find that program before you can safely read the field.
Three traps worth knowing before you start
PERFORM ... THRU ...executes a range of paragraphs.PERFORM A200-VALIDATE THRU A200-EXITruns everything physically located between those two labels. Someone inserting a paragraph in the middle in 2009 extended the behaviour of every caller, invisibly.GO TO ... DEPENDING ONis a computed jump on an integer. The mapping from number to destination is positional, so adding a branch renumbers the rest.- Fall-through is normal. Paragraphs run into one another unless something prevents it. There is no block scope to protect you, and indentation means nothing.
Prove what actually runs
Static reachability analysis will over-report: it counts a program as live if anything references it, including a job that was disabled in 2013. Pair it with execution evidence — SMF records, or the scheduler's own run history — over a full business cycle, so quarter-end and year-end work is included.
On Nordvik Bank's core, 640 programs were in the source library. Over 24 months of execution history, 128 had never run. That is 18% of the estate retired without a line of analysis, and it was the single cheapest scope reduction available on the programme.
After two weeks
You should be able to name the ten programs that carry the business, describe the six datasets that pass between domains, and list the fields whose meaning is not derivable from the code. That last list is the one that matters, and it is what you take to the two people who still remember. Ask them about X and Z.
They will know. They will also be pleased that someone finally asked, because nobody has in a decade — and you will get an hour of context that no amount of reading was ever going to produce.