Case Study 2: MedClaim's Common Routine Library
Background
MedClaim Health Services processes approximately 500,000 insurance claims per month through a COBOL-based system running on z/OS. Over the years, the system had grown organically — individual developers writing programs to handle specific claim types, each implementing their own versions of common functions like date validation, amount rounding, and error logging.
When James Okafor was promoted to team lead in 2018, he discovered the extent of the problem during a code audit. He found 23 different implementations of date validation scattered across the system. Fourteen of them had subtle bugs — handling leap years incorrectly, rejecting valid dates in certain edge cases, or producing inconsistent results for the same input.
"The February 29th bug was the wake-up call," James explains. "In 2020, our leap year, seven different programs rejected valid claims dated February 29th. Seven different bugs, in seven different copies of code that all did the same thing. We spent $40,000 in developer time fixing them. That's when I proposed the common routine library."
The Problem in Detail
Sarah Kim, MedClaim's business analyst, documented the duplication:
| Function | Copies Found | Bugs Found | Programs Affected |
|---|---|---|---|
| Date validation | 23 | 14 | 89 programs |
| Amount rounding | 18 | 7 | 67 programs |
| Error logging | 31 | 9 | 156 programs |
| Name formatting | 12 | 4 | 45 programs |
| Address formatting | 9 | 3 | 38 programs |
| Diagnosis code lookup | 6 | 2 | 34 programs |
| Procedure code lookup | 5 | 1 | 28 programs |
Beyond the bugs, the duplication created a maintenance nightmare. When CMS (the Centers for Medicare & Medicaid Services) changed its date format requirements in 2019, the team had to update 23 different date routines. The change took six weeks and introduced two new bugs.
The Solution: Standardized Subprogram Library
James designed a common routine library with three key principles:
Principle 1: Standardized Interface Pattern
Every subprogram in the library follows the same calling convention:
CALL 'routine-name' USING input-output-area
return-code
error-area
- Parameter 1: Function-specific input/output area (defined in a copybook)
- Parameter 2: Standardized return code (PIC S9(4) COMP)
- Parameter 3: Standardized error communication area (ERRCOMCP copybook)
Principle 2: All Interfaces Defined in Copybooks
Every routine's interface is defined in a copybook stored in the shared COPYLIB. Both the calling program and the subprogram COPY the same member.
Principle 3: Dynamic CALL Only
All routines are dynamically called so that bug fixes and enhancements can be deployed without relinking any calling program.
The Error Communication Area
James designed a reusable error structure used by all routines:
*================================================================
* ERRCOMCP — Standard Error Communication Area
* Used by: All common routines
*================================================================
01 ERR-COMM-AREA.
05 ERR-ROUTINE-NAME PIC X(8).
05 ERR-SEVERITY PIC 9(2).
88 ERR-INFO VALUE 0.
88 ERR-WARN VALUE 4.
88 ERR-ERROR VALUE 8.
88 ERR-SEVERE VALUE 12.
88 ERR-FATAL VALUE 16.
05 ERR-CODE PIC X(8).
05 ERR-MESSAGE PIC X(80).
05 ERR-TIMESTAMP PIC X(26).
05 ERR-DETAIL-COUNT PIC 9(2).
05 ERR-DETAILS.
10 ERR-DETAIL OCCURS 5 TIMES.
15 ERR-DTL-FIELD PIC X(30).
15 ERR-DTL-VALUE PIC X(30).
15 ERR-DTL-MSG PIC X(50).
This structure allows routines to communicate not just "what went wrong" but "which field, what value, and why it's wrong" — critical for debugging and for passing meaningful messages back to users in online transactions.
Implementation: The Date Validation Routine
Here is a simplified version of the consolidated DTEVALID routine:
IDENTIFICATION DIVISION.
PROGRAM-ID. DTEVALID.
*================================================================
* MedClaim Common Routine: Date Validation
* Validates dates in YYYYMMDD format.
* Also provides day-of-week, Julian date, age calculation.
*================================================================
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-WORK-FIELDS.
05 WS-YEAR PIC 9(4).
05 WS-MONTH PIC 9(2).
05 WS-DAY PIC 9(2).
05 WS-LEAP-FLAG PIC 9 VALUE 0.
05 WS-DAYS-TABLE.
10 FILLER PIC 9(2) VALUE 31.
10 FILLER PIC 9(2) VALUE 28.
10 FILLER PIC 9(2) VALUE 31.
10 FILLER PIC 9(2) VALUE 30.
10 FILLER PIC 9(2) VALUE 31.
10 FILLER PIC 9(2) VALUE 30.
10 FILLER PIC 9(2) VALUE 31.
10 FILLER PIC 9(2) VALUE 31.
10 FILLER PIC 9(2) VALUE 30.
10 FILLER PIC 9(2) VALUE 31.
10 FILLER PIC 9(2) VALUE 30.
10 FILLER PIC 9(2) VALUE 31.
05 WS-DAYS-REDEF REDEFINES WS-DAYS-TABLE.
10 WS-MAX-DAY PIC 9(2) OCCURS 12.
LINKAGE SECTION.
COPY DTEVALCP.
01 LS-RETURN-CODE PIC S9(4) COMP.
COPY ERRCOMCP.
PROCEDURE DIVISION USING DTE-VALIDATION-AREA
LS-RETURN-CODE
ERR-COMM-AREA.
MAIN-LOGIC.
MOVE 0 TO LS-RETURN-CODE
INITIALIZE ERR-COMM-AREA
MOVE 'DTEVALID' TO ERR-ROUTINE-NAME
PERFORM VALIDATE-FORMAT
IF LS-RETURN-CODE = 0
PERFORM VALIDATE-RANGES
END-IF
IF LS-RETURN-CODE = 0
PERFORM CALCULATE-EXTRAS
END-IF
GOBACK.
Deployment and Migration
The migration to the common library took four months:
Month 1: Built and tested all seven common routines. Created comprehensive test suites with edge cases (leap years, boundary dates, maximum amounts, special characters in names).
Month 2: Migrated 20 highest-impact programs (those processing the most claims). Each migration involved: 1. Replacing inline code with CALL statements 2. Adding COPY statements for the interface copybooks 3. Recompiling (no relink needed — all dynamic CALL) 4. Running parallel tests: old version and new version processing the same claims
Month 3: Migrated the next 60 programs.
Month 4: Migrated the remaining programs and decommissioned the old inline code.
Results
| Metric | Before | After (1 year) |
|---|---|---|
| Date-related production bugs per year | 12 | 0 |
| Lines of duplicated code | ~40,000 | 0 |
| Time to implement a cross-cutting change | 6 weeks | 1 day |
| Programs needing recompile for a routine fix | 156 | 1 (the routine) |
| Test coverage of common functions | ~30% | 98% |
The Unexpected Benefit
Six months after the library was complete, MedClaim needed to support a new CMS date format for electronic claim submissions. With the old system, this would have required modifying and retesting dozens of programs. With the common library, James modified DTEVALID once, ran the test suite, and deployed the updated module. Every program in the system automatically used the new format support on its next execution.
"That one change paid for the entire four-month migration effort," Sarah Kim noted. "What would have been a six-week project became a one-day task."
Discussion Questions
-
James chose to pass three separate parameters (data area, return code, error area) rather than one combined structure. What are the trade-offs of this design? When might a single structure be better?
-
During the migration, parallel testing was used — running old and new versions on the same data. How would you automate this comparison? What differences would be acceptable vs. alarming?
-
The error communication area supports up to 5 detail entries. Is this sufficient? How would you handle cases where more details are needed?
-
What versioning strategy would you recommend for the common routines? How do you handle backward compatibility when the interface needs to change?
-
MedClaim used dynamic CALL exclusively. Under what circumstances might static CALL be appropriate for a common routine library?