Skip to content
PYD ENTERPRISES

COBOL anti-pattern

Copybook sprawl

Hundreds of near-duplicate copybooks, COPY REPLACING variants and same-named members in different libraries, so the record layout a program uses depends on how it was compiled.

FAMILY
COBOL
CUTOVER RISK
High
Hides business logic or coupling that a rewrite will drop unless it is extracted explicitly.
MODERN MAPPING
Versioned canonical schema
GENERATED ARTIFACT
copybook-clusters.json

Before and after

legacy source → modern mapping

Legacy: exhibits the pattern

CUSTUPD.cblCOBOL
1 * CUSTREC MEMBER EXISTS IN BOTH
2 * PROD.BRANCH.COPYLIB (49 BYTES)
3 * PROD.CORE.COPYLIB (52 BYTES)
4 WORKING-STORAGE SECTION.
5 COPY CUSTREC REPLACING ==:PFX:== BY ==WS-OLD==.
6 COPY CUSTREC REPLACING ==:PFX:== BY ==WS-NEW==.
7 COPY CUSTRECN.
8 COPY ERRAREA.
9 PROCEDURE DIVISION.
10 ...
11 IF WS-OLD-CUST-SEGMENT NOT = WS-NEW-CUST-SEGMENT
12 PERFORM 6000-SEGMENT-CHANGE
13 END-IF.
14 * PARAGRAPHS COPIED FROM A SHARED MEMBER
15 COPY CALCDISC.

Modern: Versioned canonical schema

contracts/customer.v3.tsTypeScript
1// Canonical layout for fingerprint cluster C-017:
2// CUSTREC (CORE), CUSTREC (BRANCH), CUSTRECN
3export interface CustomerV3 {
4 id: string; // CUST-ID X(10)
5 segment: Segment; // CUST-SEGMENT X(02)
6 openedOn: string; // CUST-OPEN-DT 9(08)
7 creditLimit: string; // S9(9)V99 COMP-3
8 branchCode?: string; // BRANCH variant only
9}
10
11export type Segment = "RT" | "SB" | "CB" | "PB";
12
13// Program views map onto the canonical type:
14// CUSTUPD WS-OLD-* and WS-NEW-* -> CustomerV3

Why it is dangerous in modernization

Copybooks are the de facto data dictionary of a mainframe estate, and after forty years they no longer agree with each other. The same record exists as CUSTREC, CUSTREC2 and CUSTRECN with small differences. COPY REPLACING produces several prefixed copies of one layout inside a single program. Two libraries in the SYSLIB concatenation can both contain a member called CUSTREC, and the compiler uses whichever library comes first, so the layout depends on the compile JCL or the Endevor processor rather than the source. Some copybooks contain procedure division code, not data. A modernization that builds its canonical data model by reading the copybook library alphabetically ends up with the wrong field lengths for some programs and a model with three customer entities that are really one.

How PYD ENTERPRISES detects it

PYD ENTERPRISES resolves copybooks the way the compiler did: it reads the library concatenation for each program from the compile JCL, the Endevor processor output or the build configuration, then expands every COPY with its REPLACING operands, including partial-word replacement of tags such as :PFX:. Each expanded layout is fingerprinted by field offsets, lengths and usages. Layouts with matching fingerprints are clustered even when names differ, and members that shadow another member of the same name are reported with the programs affected. Field-level usage analysis shows which fields each program actually reads or writes.

Maps to: Versioned canonical schema

Collapse each fingerprint cluster into one canonical schema with a version, published from a single schema registry or contracts package. Program-specific differences become explicit versions or optional fields, not separate entities. Fields that no program reads are candidates to drop, with the usage evidence attached for the data owner to review.

Generated specification fragment

copybook-clusters.jsonJSON
1{
2 "cluster": "C-017",
3 "canonical": "CustomerV3",
4 "members": [
5 { "member": "CUSTREC", "library": "PROD.CORE.COPYLIB",
6 "bytes": 52, "programs": 214 },
7 { "member": "CUSTREC", "library": "PROD.BRANCH.COPYLIB",
8 "bytes": 49, "programs": 31, "shadowed": true },
9 { "member": "CUSTRECN", "library": "PROD.CORE.COPYLIB",
10 "bytes": 52, "programs": 58 }
11 ],
12 "unusedFields": ["CUST-FILLER-01", "CUST-OLD-RM-CODE"],
13 "procedureCopybooks": ["CALCDISC"]
14}

Every generated element links back to the source file and line range shown in the legacy pane. Review and sign off before building against it.

Which CUSTREC did the compiler see?

In the example, two libraries each contain a CUSTREC member with different lengths. A program compiled with the core library first in SYSLIB gets the 52-byte layout; one compiled by a branch processor that lists the branch library first gets 49 bytes. Both programs say COPY CUSTREC. Reading the source alone cannot tell them apart, which is why PYD ENTERPRISES ingests compile JCL and Endevor processor output as first-class inputs, not as optional metadata.

Procedure copybooks

CALCDISC is a copybook that contains paragraphs. Every program that copies it gets its own copy of the discount logic, compiled against that program's data names. If the paragraphs reference a field that two programs define differently, the same source text produces different behavior. The engine expands procedure copybooks in place, extracts rules per including program, and then deduplicates rules that are identical after symbol resolution, so the discount rule appears once in the inventory with a list of every program that runs it.

What a usable data inventory looks like

  • One entry per fingerprint cluster, not per member name.
  • For each field: offset, length, usage, the programs that read it, and the programs that write it.
  • Shadowed members, with the compile configuration that selects each one.
  • REPLACING variants grouped under the layout they expand from.

This is the input a data architect needs to design the target schema. It also makes field retirement defensible: a field that nothing reads in any resolved compile is evidence, not opinion.

Find every Copybook sprawl in your codebase.

Run PYD ENTERPRISES in your private VPC and get each occurrence with file, line range, modern mapping and equivalence fixtures, ready for your architects to review.