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

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

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

  3. The error communication area supports up to 5 detail entries. Is this sufficient? How would you handle cases where more details are needed?

  4. What versioning strategy would you recommend for the common routines? How do you handle backward compatibility when the interface needs to change?

  5. MedClaim used dynamic CALL exclusively. Under what circumstances might static CALL be appropriate for a common routine library?