Case Study 2: Designing a Loan Application Data Structure

Background

Meridian Community Credit Union (MCCU) serves approximately 180,000 members across three states. In 2024, the credit union launched a project to replace its paper-based loan application process with a fully digital system running on its IBM z/OS mainframe. The new system would accept loan applications from branch tellers, online banking portals, and a new mobile app -- all feeding into a single COBOL batch processing program that would evaluate applications nightly.

Roberto Diaz, a COBOL developer with 14 years of experience at MCCU, was tasked with designing the WORKING-STORAGE data structures for the loan application processing program. Roberto understood that the quality of the data design would directly determine the quality of every paragraph in the PROCEDURE DIVISION. A well-structured WORKING-STORAGE section would make the validation, scoring, and decision logic straightforward to implement. A poorly structured one would cause confusion, bugs, and costly rework.

This case study follows Roberto's design process as he builds a comprehensive WORKING-STORAGE layout for the loan application system, demonstrating group items, 88-level conditions, VALUE clause initialization, and the organizational principles covered in Chapter 4.

The Requirements

The loan application processing program must handle five loan products:

  1. Personal unsecured loans -- $1,000 to $25,000, terms of 12 to 60 months
  2. Auto loans (new vehicles) -- $5,000 to $75,000, terms of 24 to 72 months
  3. Auto loans (used vehicles) -- $3,000 to $50,000, terms of 24 to 60 months
  4. Home equity loans -- $10,000 to $250,000, terms of 60 to 240 months
  5. Share-secured loans -- $500 to $100,000, terms of 6 to 60 months

For each application, the program must:

  • Capture and validate applicant personal information (name, SSN, date of birth, address, phone, email)
  • Record employment information (employer, job title, years employed, employment status)
  • Collect financial details (gross monthly income, monthly debt payments, existing MCCU accounts)
  • Store the loan request parameters (product type, amount, term, purpose)
  • Calculate the debt-to-income ratio and determine the risk tier
  • Make an automated decision: approve, conditionally approve, deny, or refer to a loan officer
  • Track processing statistics for the nightly batch report

Roberto's Design: The Complete Data Structure

Organizing the WORKING-STORAGE Section

Roberto began by sketching the major groups on a whiteboard. He identified seven logical sections:

  1. Program constants (product limits, rate tables, scoring thresholds)
  2. Processing flags and switches
  3. Counters and accumulators for the batch report
  4. The loan application record (applicant, employment, financial, loan request)
  5. Calculation work fields
  6. Decision result fields
  7. Display and report formatting fields

He then translated this design into COBOL, using the naming conventions established by MCCU's development standards.

The Complete Program

The following program demonstrates Roberto's full WORKING-STORAGE design with a PROCEDURE DIVISION that processes three sample loan applications and produces a summary.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. LOANAPP.
      *================================================================*
      * Program:     LOANAPP
      * Description: Loan Application Processing - Data Structure Demo
      * Author:      Roberto Diaz
      * Date:        2024-03-15
      * Purpose:     Demonstrates WORKING-STORAGE design for a loan
      *              application processing system at Meridian
      *              Community Credit Union.
      *================================================================*

       DATA DIVISION.
       WORKING-STORAGE SECTION.

      *================================================================*
      * SECTION 1: PROGRAM CONSTANTS                                   *
      *================================================================*
       01  WS-C-PROGRAM-INFO.
           05  WS-C-PROGRAM-ID        PIC X(08) VALUE 'LOANAPP '.
           05  WS-C-PROGRAM-VER       PIC X(05) VALUE '01.00'.
           05  WS-C-INSTITUTION       PIC X(30)
               VALUE 'MERIDIAN COMMUNITY CU'.

      *--- Loan product limits ---
       01  WS-C-PERSONAL-LIMITS.
           05  WS-C-PERS-MIN-AMT      PIC 9(07)V99
               VALUE 1000.00.
           05  WS-C-PERS-MAX-AMT      PIC 9(07)V99
               VALUE 25000.00.
           05  WS-C-PERS-MIN-TERM     PIC 9(03) VALUE 012.
           05  WS-C-PERS-MAX-TERM     PIC 9(03) VALUE 060.

       01  WS-C-AUTO-NEW-LIMITS.
           05  WS-C-ANEW-MIN-AMT      PIC 9(07)V99
               VALUE 5000.00.
           05  WS-C-ANEW-MAX-AMT      PIC 9(07)V99
               VALUE 75000.00.
           05  WS-C-ANEW-MIN-TERM     PIC 9(03) VALUE 024.
           05  WS-C-ANEW-MAX-TERM     PIC 9(03) VALUE 072.

       01  WS-C-AUTO-USED-LIMITS.
           05  WS-C-AUSD-MIN-AMT      PIC 9(07)V99
               VALUE 3000.00.
           05  WS-C-AUSD-MAX-AMT      PIC 9(07)V99
               VALUE 50000.00.
           05  WS-C-AUSD-MIN-TERM     PIC 9(03) VALUE 024.
           05  WS-C-AUSD-MAX-TERM     PIC 9(03) VALUE 060.

       01  WS-C-HOME-EQUITY-LIMITS.
           05  WS-C-HEQL-MIN-AMT      PIC 9(07)V99
               VALUE 10000.00.
           05  WS-C-HEQL-MAX-AMT      PIC 9(07)V99
               VALUE 250000.00.
           05  WS-C-HEQL-MIN-TERM     PIC 9(03) VALUE 060.
           05  WS-C-HEQL-MAX-TERM     PIC 9(03) VALUE 240.

       01  WS-C-SHARE-SECURED-LIMITS.
           05  WS-C-SSEC-MIN-AMT      PIC 9(07)V99
               VALUE 500.00.
           05  WS-C-SSEC-MAX-AMT      PIC 9(07)V99
               VALUE 100000.00.
           05  WS-C-SSEC-MIN-TERM     PIC 9(03) VALUE 006.
           05  WS-C-SSEC-MAX-TERM     PIC 9(03) VALUE 060.

      *--- DTI ratio thresholds ---
       01  WS-C-DTI-THRESHOLDS.
           05  WS-C-DTI-EXCELLENT     PIC V9(4) VALUE 0.2800.
           05  WS-C-DTI-GOOD          PIC V9(4) VALUE 0.3600.
           05  WS-C-DTI-FAIR          PIC V9(4) VALUE 0.4300.
           05  WS-C-DTI-MAX           PIC V9(4) VALUE 0.5000.

      *--- Credit score thresholds ---
       01  WS-C-SCORE-THRESHOLDS.
           05  WS-C-SCORE-EXCEL-MIN   PIC 9(03) VALUE 740.
           05  WS-C-SCORE-GOOD-MIN    PIC 9(03) VALUE 670.
           05  WS-C-SCORE-FAIR-MIN    PIC 9(03) VALUE 580.
           05  WS-C-SCORE-MINIMUM     PIC 9(03) VALUE 500.

      *--- Report formatting constants ---
       01  WS-C-REPORT-SEP            PIC X(60) VALUE ALL '='.
       01  WS-C-DETAIL-SEP            PIC X(60) VALUE ALL '-'.

      *================================================================*
      * SECTION 2: PROCESSING FLAGS AND SWITCHES                       *
      *================================================================*
       01  WS-F-EOF-FLAG              PIC X(01) VALUE 'N'.
           88  WS-EOF                            VALUE 'Y'.
           88  WS-NOT-EOF                        VALUE 'N'.

       01  WS-F-APP-VALID-FLAG        PIC X(01) VALUE 'Y'.
           88  WS-APP-IS-VALID                   VALUE 'Y'.
           88  WS-APP-IS-INVALID                 VALUE 'N'.

       01  WS-F-PROCESSING-FLAG       PIC X(01) VALUE 'Y'.
           88  WS-CONTINUE-PROCESSING            VALUE 'Y'.
           88  WS-STOP-PROCESSING                VALUE 'N'.

      *================================================================*
      * SECTION 3: COUNTERS AND ACCUMULATORS                           *
      *================================================================*
       01  WS-CTR-APPLICATIONS.
           05  WS-CTR-TOTAL-READ      PIC 9(05) VALUE ZERO.
           05  WS-CTR-APPROVED        PIC 9(05) VALUE ZERO.
           05  WS-CTR-COND-APPROVED   PIC 9(05) VALUE ZERO.
           05  WS-CTR-DENIED          PIC 9(05) VALUE ZERO.
           05  WS-CTR-REFERRED        PIC 9(05) VALUE ZERO.
           05  WS-CTR-ERRORS          PIC 9(05) VALUE ZERO.

       01  WS-CTR-BY-PRODUCT.
           05  WS-CTR-PERSONAL        PIC 9(05) VALUE ZERO.
           05  WS-CTR-AUTO-NEW        PIC 9(05) VALUE ZERO.
           05  WS-CTR-AUTO-USED       PIC 9(05) VALUE ZERO.
           05  WS-CTR-HOME-EQUITY     PIC 9(05) VALUE ZERO.
           05  WS-CTR-SHARE-SECURED   PIC 9(05) VALUE ZERO.

       01  WS-ACC-AMOUNTS.
           05  WS-ACC-TOTAL-REQUESTED PIC 9(11)V99 VALUE ZERO.
           05  WS-ACC-TOTAL-APPROVED  PIC 9(11)V99 VALUE ZERO.
           05  WS-ACC-TOTAL-DENIED    PIC 9(11)V99 VALUE ZERO.

      *================================================================*
      * SECTION 4: LOAN APPLICATION RECORD                             *
      *================================================================*

      *--- 4A: Application Header ---
       01  WS-APP-HEADER.
           05  WS-APP-ID              PIC X(12).
           05  WS-APP-DATE            PIC 9(08).
           05  WS-APP-DATE-PARTS REDEFINES WS-APP-DATE.
               10  WS-APP-DATE-YYYY   PIC 9(04).
               10  WS-APP-DATE-MM     PIC 9(02).
               10  WS-APP-DATE-DD     PIC 9(02).
           05  WS-APP-BRANCH          PIC X(04).
           05  WS-APP-CHANNEL         PIC X(01).
               88  WS-CHANNEL-BRANCH              VALUE 'B'.
               88  WS-CHANNEL-ONLINE              VALUE 'O'.
               88  WS-CHANNEL-MOBILE              VALUE 'M'.
               88  WS-CHANNEL-PHONE               VALUE 'P'.
               88  WS-CHANNEL-VALID
                   VALUE 'B' 'O' 'M' 'P'.

      *--- 4B: Applicant Personal Information ---
       01  WS-APP-PERSONAL.
           05  WS-APP-FIRST-NAME      PIC X(20).
           05  WS-APP-MIDDLE-INIT     PIC X(01).
           05  WS-APP-LAST-NAME       PIC X(25).
           05  WS-APP-SSN             PIC X(09).
           05  WS-APP-DOB             PIC 9(08).
           05  WS-APP-DOB-PARTS REDEFINES WS-APP-DOB.
               10  WS-APP-DOB-YYYY    PIC 9(04).
               10  WS-APP-DOB-MM      PIC 9(02).
               10  WS-APP-DOB-DD      PIC 9(02).
           05  WS-APP-ADDRESS.
               10  WS-APP-STREET      PIC X(30).
               10  WS-APP-CITY        PIC X(20).
               10  WS-APP-STATE       PIC X(02).
               10  WS-APP-ZIP         PIC X(10).
           05  WS-APP-PHONE-PRIMARY   PIC X(10).
           05  WS-APP-PHONE-ALT       PIC X(10).
           05  WS-APP-EMAIL           PIC X(40).

      *--- 4C: Employment Information ---
       01  WS-APP-EMPLOYMENT.
           05  WS-APP-EMP-STATUS      PIC X(01).
               88  WS-EMP-FULL-TIME               VALUE 'F'.
               88  WS-EMP-PART-TIME                VALUE 'P'.
               88  WS-EMP-SELF-EMPLOYED            VALUE 'S'.
               88  WS-EMP-RETIRED                  VALUE 'R'.
               88  WS-EMP-UNEMPLOYED               VALUE 'U'.
               88  WS-EMP-ACTIVE
                   VALUE 'F' 'P' 'S' 'R'.
               88  WS-EMP-VALID-STATUS
                   VALUE 'F' 'P' 'S' 'R' 'U'.
           05  WS-APP-EMPLOYER-NAME   PIC X(30).
           05  WS-APP-JOB-TITLE       PIC X(25).
           05  WS-APP-YEARS-EMPLOYED  PIC 9(02).
           05  WS-APP-MONTHS-EMPLOYED PIC 9(02).

      *--- 4D: Financial Information ---
       01  WS-APP-FINANCIAL.
           05  WS-APP-GROSS-MONTHLY   PIC 9(07)V99.
           05  WS-APP-OTHER-INCOME    PIC 9(07)V99.
           05  WS-APP-TOTAL-INCOME    PIC 9(07)V99.
           05  WS-APP-MONTHLY-DEBT    PIC 9(07)V99.
           05  WS-APP-CREDIT-SCORE    PIC 9(03).
               88  WS-SCORE-EXCELLENT   VALUE 740 THRU 850.
               88  WS-SCORE-GOOD        VALUE 670 THRU 739.
               88  WS-SCORE-FAIR        VALUE 580 THRU 669.
               88  WS-SCORE-POOR        VALUE 500 THRU 579.
               88  WS-SCORE-VERY-POOR   VALUE 300 THRU 499.
               88  WS-SCORE-VALID       VALUE 300 THRU 850.
           05  WS-APP-MCCU-MEMBER     PIC X(01).
               88  WS-IS-MEMBER                   VALUE 'Y'.
               88  WS-NOT-MEMBER                  VALUE 'N'.
           05  WS-APP-MEMBER-SINCE    PIC 9(08).
           05  WS-APP-SHARE-BALANCE   PIC 9(09)V99.

      *--- 4E: Loan Request Details ---
       01  WS-APP-LOAN-REQUEST.
           05  WS-APP-LOAN-TYPE       PIC X(02).
               88  WS-LOAN-PERSONAL               VALUE 'PL'.
               88  WS-LOAN-AUTO-NEW                VALUE 'AN'.
               88  WS-LOAN-AUTO-USED               VALUE 'AU'.
               88  WS-LOAN-HOME-EQUITY             VALUE 'HE'.
               88  WS-LOAN-SHARE-SECURED           VALUE 'SS'.
               88  WS-LOAN-TYPE-VALID
                   VALUE 'PL' 'AN' 'AU' 'HE' 'SS'.
           05  WS-APP-LOAN-AMOUNT     PIC 9(07)V99.
           05  WS-APP-LOAN-TERM       PIC 9(03).
           05  WS-APP-LOAN-PURPOSE    PIC X(30).
           05  WS-APP-COLLATERAL-VAL  PIC 9(09)V99.
           05  WS-APP-COLLATERAL-DESC PIC X(40).

      *================================================================*
      * SECTION 5: CALCULATION WORK FIELDS                             *
      *================================================================*
       01  WS-WK-CALC-FIELDS.
           05  WS-WK-DTI-RATIO       PIC 9(01)V9(04)  VALUE ZERO.
           05  WS-WK-NEW-PAYMENT     PIC 9(07)V99     VALUE ZERO.
           05  WS-WK-TOTAL-DEBT      PIC 9(07)V99     VALUE ZERO.
           05  WS-WK-LTV-RATIO       PIC 9(01)V9(04)  VALUE ZERO.
           05  WS-WK-MONTHLY-RATE    PIC 9(01)V9(08)  VALUE ZERO.
           05  WS-WK-NUM-PAYMENTS    PIC 9(03)         VALUE ZERO.
           05  WS-WK-POWER-FACTOR    PIC 9(05)V9(10)  VALUE ZERO.
           05  WS-WK-TEMP-CALC       PIC 9(09)V9(06)  VALUE ZERO.
           05  WS-WK-RISK-POINTS     PIC 9(04)         VALUE ZERO.
           05  WS-WK-INTEREST-RATE   PIC 9(02)V9(04)  VALUE ZERO.
           05  WS-WK-APPLICANT-AGE   PIC 9(03)         VALUE ZERO.

      *--- Risk tier determination ---
       01  WS-WK-RISK-TIER           PIC X(01) VALUE SPACE.
           88  WS-RISK-TIER-A                    VALUE 'A'.
           88  WS-RISK-TIER-B                    VALUE 'B'.
           88  WS-RISK-TIER-C                    VALUE 'C'.
           88  WS-RISK-TIER-D                    VALUE 'D'.
           88  WS-RISK-TIER-F                    VALUE 'F'.
           88  WS-RISK-ACCEPTABLE
               VALUE 'A' 'B' 'C'.

      *--- Error message accumulation ---
       01  WS-WK-ERROR-TABLE.
           05  WS-WK-ERROR-COUNT     PIC 9(02) VALUE ZERO.
           05  WS-WK-ERROR-ENTRY OCCURS 15 TIMES.
               10  WS-WK-ERR-CODE   PIC X(04).
               10  WS-WK-ERR-DESC   PIC X(50).

      *================================================================*
      * SECTION 6: DECISION RESULT FIELDS                              *
      *================================================================*
       01  WS-DECISION-RESULT.
           05  WS-DEC-STATUS         PIC X(01) VALUE SPACE.
               88  WS-DEC-APPROVED               VALUE 'A'.
               88  WS-DEC-COND-APPROVED           VALUE 'C'.
               88  WS-DEC-DENIED                  VALUE 'D'.
               88  WS-DEC-REFERRED                VALUE 'R'.
               88  WS-DEC-PENDING                 VALUE 'P'.
           05  WS-DEC-REASON-CODE    PIC X(04) VALUE SPACES.
           05  WS-DEC-REASON-DESC    PIC X(50) VALUE SPACES.
           05  WS-DEC-APPROVED-AMT   PIC 9(07)V99 VALUE ZERO.
           05  WS-DEC-APPROVED-RATE  PIC 9(02)V9(04) VALUE ZERO.
           05  WS-DEC-APPROVED-TERM  PIC 9(03) VALUE ZERO.
           05  WS-DEC-MONTHLY-PMT    PIC 9(07)V99 VALUE ZERO.
           05  WS-DEC-CONDITIONS     PIC X(60) VALUE SPACES.
           05  WS-DEC-OFFICER-ID     PIC X(06) VALUE SPACES.

      *================================================================*
      * SECTION 7: DISPLAY AND REPORT FIELDS                           *
      *================================================================*
       01  WS-DSP-HEADER-LINE.
           05  FILLER                PIC X(05) VALUE SPACES.
           05  FILLER                PIC X(30)
               VALUE 'LOAN APPLICATION DECISION RPT'.
           05  FILLER                PIC X(10) VALUE SPACES.
           05  WS-DSP-RUN-DATE      PIC X(10) VALUE SPACES.

       01  WS-DSP-DETAIL-LINE.
           05  FILLER                PIC X(02) VALUE SPACES.
           05  WS-DSP-APP-ID        PIC X(12).
           05  FILLER                PIC X(02) VALUE SPACES.
           05  WS-DSP-APP-NAME      PIC X(30).
           05  FILLER                PIC X(02) VALUE SPACES.
           05  WS-DSP-LOAN-TYPE     PIC X(10).
           05  FILLER                PIC X(02) VALUE SPACES.
           05  WS-DSP-AMOUNT        PIC $$$,$$$,MATH1$,$$$,$$9.99.
       01  WS-DSP-FORMATTED-PCT     PIC Z9.99.
       01  WS-DSP-FORMATTED-COUNT   PIC Z,ZZ9.

      *--- Current date fields ---
       01  WS-CURRENT-DATE-DATA.
           05  WS-CURRENT-DATE.
               10  WS-CURRENT-YEAR  PIC 9(04).
               10  WS-CURRENT-MONTH PIC 9(02).
               10  WS-CURRENT-DAY   PIC 9(02).
           05  WS-CURRENT-TIME.
               10  WS-CURRENT-HOUR  PIC 9(02).
               10  WS-CURRENT-MIN   PIC 9(02).
               10  WS-CURRENT-SEC   PIC 9(02).
               10  WS-CURRENT-HUND  PIC 9(02).
           05  WS-GMT-OFFSET        PIC S9(04).

      *--- Test data counter ---
       01  WS-TEST-APP-NUMBER        PIC 9(01) VALUE ZERO.

       PROCEDURE DIVISION.
       0000-MAIN-CONTROL.
           PERFORM 1000-INITIALIZATION
           PERFORM 2000-PROCESS-APPLICATIONS
           PERFORM 3000-PRINT-SUMMARY
           STOP RUN
           .

      *================================================================*
      * 1000-INITIALIZATION: Set up working fields and date            *
      *================================================================*
       1000-INITIALIZATION.
           MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE-DATA
           STRING WS-CURRENT-MONTH DELIMITED BY SIZE
                  '/'               DELIMITED BY SIZE
                  WS-CURRENT-DAY   DELIMITED BY SIZE
                  '/'               DELIMITED BY SIZE
                  WS-CURRENT-YEAR  DELIMITED BY SIZE
                  INTO WS-DSP-RUN-DATE
           END-STRING
           DISPLAY WS-C-REPORT-SEP
           DISPLAY WS-DSP-HEADER-LINE
           DISPLAY WS-C-REPORT-SEP
           DISPLAY SPACES
           .

      *================================================================*
      * 2000-PROCESS-APPLICATIONS: Process each test application       *
      *================================================================*
       2000-PROCESS-APPLICATIONS.
           PERFORM 2100-LOAD-APPLICATION-1
           PERFORM 2500-EVALUATE-APPLICATION
           PERFORM 2800-DISPLAY-RESULT

           PERFORM 2100-LOAD-APPLICATION-2
           PERFORM 2500-EVALUATE-APPLICATION
           PERFORM 2800-DISPLAY-RESULT

           PERFORM 2100-LOAD-APPLICATION-3
           PERFORM 2500-EVALUATE-APPLICATION
           PERFORM 2800-DISPLAY-RESULT
           .

      *================================================================*
      * 2100-LOAD-APPLICATION-1: Strong applicant, personal loan       *
      *================================================================*
       2100-LOAD-APPLICATION-1.
           PERFORM 2050-CLEAR-APPLICATION
           ADD 1 TO WS-CTR-TOTAL-READ

           MOVE 'APP-20240301' TO WS-APP-ID
           MOVE 20240301       TO WS-APP-DATE
           MOVE 'BR01'         TO WS-APP-BRANCH
           SET WS-CHANNEL-BRANCH TO TRUE

           MOVE 'MARGARET'     TO WS-APP-FIRST-NAME
           MOVE 'A'            TO WS-APP-MIDDLE-INIT
           MOVE 'THOMPSON'     TO WS-APP-LAST-NAME
           MOVE '555123456'    TO WS-APP-SSN
           MOVE 19820415       TO WS-APP-DOB

           SET  WS-EMP-FULL-TIME TO TRUE
           MOVE 'FIRST NATIONAL BANK' TO WS-APP-EMPLOYER-NAME
           MOVE 'BRANCH MANAGER'      TO WS-APP-JOB-TITLE
           MOVE 08                    TO WS-APP-YEARS-EMPLOYED
           MOVE 03                    TO WS-APP-MONTHS-EMPLOYED

           MOVE 6500.00  TO WS-APP-GROSS-MONTHLY
           MOVE 0500.00  TO WS-APP-OTHER-INCOME
           MOVE 7000.00  TO WS-APP-TOTAL-INCOME
           MOVE 1200.00  TO WS-APP-MONTHLY-DEBT
           MOVE 762       TO WS-APP-CREDIT-SCORE
           SET  WS-IS-MEMBER TO TRUE
           MOVE 20160901   TO WS-APP-MEMBER-SINCE
           MOVE 12500.00  TO WS-APP-SHARE-BALANCE

           SET  WS-LOAN-PERSONAL TO TRUE
           MOVE 15000.00  TO WS-APP-LOAN-AMOUNT
           MOVE 048        TO WS-APP-LOAN-TERM
           MOVE 'HOME IMPROVEMENT' TO WS-APP-LOAN-PURPOSE
           MOVE ZERO       TO WS-APP-COLLATERAL-VAL
           MOVE SPACES     TO WS-APP-COLLATERAL-DESC

           ADD 1 TO WS-CTR-PERSONAL
           .

      *================================================================*
      * Load application 2: Risky applicant, auto loan                 *
      *================================================================*
       2100-LOAD-APPLICATION-2.
           PERFORM 2050-CLEAR-APPLICATION
           ADD 1 TO WS-CTR-TOTAL-READ

           MOVE 'APP-20240302' TO WS-APP-ID
           MOVE 20240301       TO WS-APP-DATE
           MOVE 'BR03'         TO WS-APP-BRANCH
           SET WS-CHANNEL-ONLINE TO TRUE

           MOVE 'DAVID'       TO WS-APP-FIRST-NAME
           MOVE 'R'           TO WS-APP-MIDDLE-INIT
           MOVE 'KELLEY'      TO WS-APP-LAST-NAME
           MOVE '555987654'   TO WS-APP-SSN
           MOVE 19950822      TO WS-APP-DOB

           SET  WS-EMP-PART-TIME TO TRUE
           MOVE 'RIVERSIDE GROCERY'   TO WS-APP-EMPLOYER-NAME
           MOVE 'STOCK CLERK'         TO WS-APP-JOB-TITLE
           MOVE 01                    TO WS-APP-YEARS-EMPLOYED
           MOVE 04                    TO WS-APP-MONTHS-EMPLOYED

           MOVE 2200.00  TO WS-APP-GROSS-MONTHLY
           MOVE 0000.00  TO WS-APP-OTHER-INCOME
           MOVE 2200.00  TO WS-APP-TOTAL-INCOME
           MOVE 1100.00  TO WS-APP-MONTHLY-DEBT
           MOVE 548       TO WS-APP-CREDIT-SCORE
           SET  WS-IS-MEMBER TO TRUE
           MOVE 20230601   TO WS-APP-MEMBER-SINCE
           MOVE 00800.00  TO WS-APP-SHARE-BALANCE

           SET  WS-LOAN-AUTO-NEW TO TRUE
           MOVE 32000.00  TO WS-APP-LOAN-AMOUNT
           MOVE 072        TO WS-APP-LOAN-TERM
           MOVE 'NEW VEHICLE PURCHASE' TO WS-APP-LOAN-PURPOSE
           MOVE 28000.00  TO WS-APP-COLLATERAL-VAL
           MOVE '2024 HONDA CIVIC'     TO WS-APP-COLLATERAL-DESC

           ADD 1 TO WS-CTR-AUTO-NEW
           .

      *================================================================*
      * Load application 3: Moderate applicant, home equity            *
      *================================================================*
       2100-LOAD-APPLICATION-3.
           PERFORM 2050-CLEAR-APPLICATION
           ADD 1 TO WS-CTR-TOTAL-READ

           MOVE 'APP-20240303' TO WS-APP-ID
           MOVE 20240301       TO WS-APP-DATE
           MOVE 'BR02'         TO WS-APP-BRANCH
           SET WS-CHANNEL-BRANCH TO TRUE

           MOVE 'SUSAN'       TO WS-APP-FIRST-NAME
           MOVE 'L'           TO WS-APP-MIDDLE-INIT
           MOVE 'MARTINEZ'    TO WS-APP-LAST-NAME
           MOVE '555456789'   TO WS-APP-SSN
           MOVE 19750930      TO WS-APP-DOB

           SET  WS-EMP-FULL-TIME TO TRUE
           MOVE 'COUNTY SCHOOL DIST'  TO WS-APP-EMPLOYER-NAME
           MOVE 'TEACHER'             TO WS-APP-JOB-TITLE
           MOVE 15                    TO WS-APP-YEARS-EMPLOYED
           MOVE 00                    TO WS-APP-MONTHS-EMPLOYED

           MOVE 5200.00  TO WS-APP-GROSS-MONTHLY
           MOVE 0300.00  TO WS-APP-OTHER-INCOME
           MOVE 5500.00  TO WS-APP-TOTAL-INCOME
           MOVE 1850.00  TO WS-APP-MONTHLY-DEBT
           MOVE 698       TO WS-APP-CREDIT-SCORE
           SET  WS-IS-MEMBER TO TRUE
           MOVE 20100315   TO WS-APP-MEMBER-SINCE
           MOVE 08200.00  TO WS-APP-SHARE-BALANCE

           SET  WS-LOAN-HOME-EQUITY TO TRUE
           MOVE 45000.00  TO WS-APP-LOAN-AMOUNT
           MOVE 120        TO WS-APP-LOAN-TERM
           MOVE 'KITCHEN RENOVATION'  TO WS-APP-LOAN-PURPOSE
           MOVE 185000.00 TO WS-APP-COLLATERAL-VAL
           MOVE 'PRIMARY RESIDENCE'   TO WS-APP-COLLATERAL-DESC

           ADD 1 TO WS-CTR-HOME-EQUITY
           .

      *================================================================*
      * 2050-CLEAR-APPLICATION: Reset per-application fields           *
      *================================================================*
       2050-CLEAR-APPLICATION.
           INITIALIZE WS-APP-HEADER
           INITIALIZE WS-APP-PERSONAL
           INITIALIZE WS-APP-EMPLOYMENT
           INITIALIZE WS-APP-FINANCIAL
           INITIALIZE WS-APP-LOAN-REQUEST
           INITIALIZE WS-WK-CALC-FIELDS
           INITIALIZE WS-WK-ERROR-TABLE
           INITIALIZE WS-DECISION-RESULT
           MOVE SPACE TO WS-WK-RISK-TIER
           SET WS-APP-IS-VALID TO TRUE
           SET WS-CONTINUE-PROCESSING TO TRUE
           SET WS-DEC-PENDING TO TRUE
           .

      *================================================================*
      * 2500-EVALUATE-APPLICATION: Run validation and scoring          *
      *================================================================*
       2500-EVALUATE-APPLICATION.
           PERFORM 2510-VALIDATE-LOAN-TYPE
           IF WS-CONTINUE-PROCESSING
               PERFORM 2520-VALIDATE-AMOUNT-TERM
           END-IF
           IF WS-CONTINUE-PROCESSING
               PERFORM 2530-VALIDATE-EMPLOYMENT
           END-IF
           IF WS-CONTINUE-PROCESSING
               PERFORM 2540-CALCULATE-DTI
           END-IF
           IF WS-CONTINUE-PROCESSING
               PERFORM 2550-DETERMINE-RISK-TIER
           END-IF
           IF WS-CONTINUE-PROCESSING
               PERFORM 2560-MAKE-DECISION
           END-IF

           ADD WS-APP-LOAN-AMOUNT TO WS-ACC-TOTAL-REQUESTED
           .

      *================================================================*
      * 2510-VALIDATE-LOAN-TYPE: Check product type is valid           *
      *================================================================*
       2510-VALIDATE-LOAN-TYPE.
           IF NOT WS-LOAN-TYPE-VALID
               ADD 1 TO WS-WK-ERROR-COUNT
               MOVE 'E001' TO WS-WK-ERR-CODE(WS-WK-ERROR-COUNT)
               MOVE 'Invalid loan product type'
                   TO WS-WK-ERR-DESC(WS-WK-ERROR-COUNT)
               SET WS-APP-IS-INVALID TO TRUE
               SET WS-STOP-PROCESSING TO TRUE
               SET WS-DEC-DENIED TO TRUE
               MOVE 'E001' TO WS-DEC-REASON-CODE
               MOVE 'Invalid loan type' TO WS-DEC-REASON-DESC
               ADD 1 TO WS-CTR-ERRORS
           END-IF
           .

      *================================================================*
      * 2520-VALIDATE-AMOUNT-TERM: Check within product limits         *
      *================================================================*
       2520-VALIDATE-AMOUNT-TERM.
           EVALUATE TRUE
               WHEN WS-LOAN-PERSONAL
                   IF WS-APP-LOAN-AMOUNT < WS-C-PERS-MIN-AMT
                       OR WS-APP-LOAN-AMOUNT > WS-C-PERS-MAX-AMT
                       PERFORM 2525-AMOUNT-OUT-OF-RANGE
                   END-IF
                   IF WS-APP-LOAN-TERM < WS-C-PERS-MIN-TERM
                       OR WS-APP-LOAN-TERM > WS-C-PERS-MAX-TERM
                       PERFORM 2526-TERM-OUT-OF-RANGE
                   END-IF
               WHEN WS-LOAN-AUTO-NEW
                   IF WS-APP-LOAN-AMOUNT < WS-C-ANEW-MIN-AMT
                       OR WS-APP-LOAN-AMOUNT > WS-C-ANEW-MAX-AMT
                       PERFORM 2525-AMOUNT-OUT-OF-RANGE
                   END-IF
                   IF WS-APP-LOAN-TERM < WS-C-ANEW-MIN-TERM
                       OR WS-APP-LOAN-TERM > WS-C-ANEW-MAX-TERM
                       PERFORM 2526-TERM-OUT-OF-RANGE
                   END-IF
               WHEN WS-LOAN-AUTO-USED
                   IF WS-APP-LOAN-AMOUNT < WS-C-AUSD-MIN-AMT
                       OR WS-APP-LOAN-AMOUNT > WS-C-AUSD-MAX-AMT
                       PERFORM 2525-AMOUNT-OUT-OF-RANGE
                   END-IF
                   IF WS-APP-LOAN-TERM < WS-C-AUSD-MIN-TERM
                       OR WS-APP-LOAN-TERM > WS-C-AUSD-MAX-TERM
                       PERFORM 2526-TERM-OUT-OF-RANGE
                   END-IF
               WHEN WS-LOAN-HOME-EQUITY
                   IF WS-APP-LOAN-AMOUNT < WS-C-HEQL-MIN-AMT
                       OR WS-APP-LOAN-AMOUNT > WS-C-HEQL-MAX-AMT
                       PERFORM 2525-AMOUNT-OUT-OF-RANGE
                   END-IF
                   IF WS-APP-LOAN-TERM < WS-C-HEQL-MIN-TERM
                       OR WS-APP-LOAN-TERM > WS-C-HEQL-MAX-TERM
                       PERFORM 2526-TERM-OUT-OF-RANGE
                   END-IF
               WHEN WS-LOAN-SHARE-SECURED
                   IF WS-APP-LOAN-AMOUNT < WS-C-SSEC-MIN-AMT
                       OR WS-APP-LOAN-AMOUNT > WS-C-SSEC-MAX-AMT
                       PERFORM 2525-AMOUNT-OUT-OF-RANGE
                   END-IF
                   IF WS-APP-LOAN-TERM < WS-C-SSEC-MIN-TERM
                       OR WS-APP-LOAN-TERM > WS-C-SSEC-MAX-TERM
                       PERFORM 2526-TERM-OUT-OF-RANGE
                   END-IF
           END-EVALUATE
           .

       2525-AMOUNT-OUT-OF-RANGE.
           ADD 1 TO WS-WK-ERROR-COUNT
           MOVE 'E002' TO WS-WK-ERR-CODE(WS-WK-ERROR-COUNT)
           MOVE 'Loan amount outside product limits'
               TO WS-WK-ERR-DESC(WS-WK-ERROR-COUNT)
           .

       2526-TERM-OUT-OF-RANGE.
           ADD 1 TO WS-WK-ERROR-COUNT
           MOVE 'E003' TO WS-WK-ERR-CODE(WS-WK-ERROR-COUNT)
           MOVE 'Loan term outside product limits'
               TO WS-WK-ERR-DESC(WS-WK-ERROR-COUNT)
           .

      *================================================================*
      * 2530-VALIDATE-EMPLOYMENT: Check employment meets criteria      *
      *================================================================*
       2530-VALIDATE-EMPLOYMENT.
           IF NOT WS-EMP-VALID-STATUS
               ADD 1 TO WS-WK-ERROR-COUNT
               MOVE 'E004' TO WS-WK-ERR-CODE(WS-WK-ERROR-COUNT)
               MOVE 'Invalid employment status code'
                   TO WS-WK-ERR-DESC(WS-WK-ERROR-COUNT)
           END-IF
           IF WS-EMP-UNEMPLOYED
               IF NOT WS-LOAN-SHARE-SECURED
                   ADD 1 TO WS-WK-ERROR-COUNT
                   MOVE 'E005'
                       TO WS-WK-ERR-CODE(WS-WK-ERROR-COUNT)
                   MOVE 'Unemployed: only share-secured eligible'
                       TO WS-WK-ERR-DESC(WS-WK-ERROR-COUNT)
               END-IF
           END-IF
           IF WS-WK-ERROR-COUNT > 0
               SET WS-APP-IS-INVALID TO TRUE
               SET WS-STOP-PROCESSING TO TRUE
               SET WS-DEC-DENIED TO TRUE
               MOVE 'E004' TO WS-DEC-REASON-CODE
               MOVE 'Employment criteria not met'
                   TO WS-DEC-REASON-DESC
               ADD 1 TO WS-CTR-ERRORS
           END-IF
           .

      *================================================================*
      * 2540-CALCULATE-DTI: Compute debt-to-income ratio               *
      *================================================================*
       2540-CALCULATE-DTI.
           IF WS-APP-TOTAL-INCOME > ZERO
               COMPUTE WS-WK-DTI-RATIO ROUNDED =
                   WS-APP-MONTHLY-DEBT / WS-APP-TOTAL-INCOME
           ELSE
               MOVE 9.9999 TO WS-WK-DTI-RATIO
           END-IF
           .

      *================================================================*
      * 2550-DETERMINE-RISK-TIER: Score the applicant                  *
      *================================================================*
       2550-DETERMINE-RISK-TIER.
           MOVE ZERO TO WS-WK-RISK-POINTS

      *    Credit score component (0-40 points)
           EVALUATE TRUE
               WHEN WS-SCORE-EXCELLENT
                   ADD 40 TO WS-WK-RISK-POINTS
               WHEN WS-SCORE-GOOD
                   ADD 30 TO WS-WK-RISK-POINTS
               WHEN WS-SCORE-FAIR
                   ADD 20 TO WS-WK-RISK-POINTS
               WHEN WS-SCORE-POOR
                   ADD 10 TO WS-WK-RISK-POINTS
               WHEN OTHER
                   ADD 00 TO WS-WK-RISK-POINTS
           END-EVALUATE

      *    DTI ratio component (0-30 points)
           EVALUATE TRUE
               WHEN WS-WK-DTI-RATIO <= WS-C-DTI-EXCELLENT
                   ADD 30 TO WS-WK-RISK-POINTS
               WHEN WS-WK-DTI-RATIO <= WS-C-DTI-GOOD
                   ADD 22 TO WS-WK-RISK-POINTS
               WHEN WS-WK-DTI-RATIO <= WS-C-DTI-FAIR
                   ADD 12 TO WS-WK-RISK-POINTS
               WHEN WS-WK-DTI-RATIO <= WS-C-DTI-MAX
                   ADD 05 TO WS-WK-RISK-POINTS
               WHEN OTHER
                   ADD 00 TO WS-WK-RISK-POINTS
           END-EVALUATE

      *    Employment stability component (0-20 points)
           IF WS-EMP-FULL-TIME
               ADD 10 TO WS-WK-RISK-POINTS
           END-IF
           IF WS-APP-YEARS-EMPLOYED >= 5
               ADD 10 TO WS-WK-RISK-POINTS
           ELSE
               IF WS-APP-YEARS-EMPLOYED >= 2
                   ADD 05 TO WS-WK-RISK-POINTS
               END-IF
           END-IF

      *    Membership component (0-10 points)
           IF WS-IS-MEMBER
               ADD 05 TO WS-WK-RISK-POINTS
               IF WS-APP-SHARE-BALANCE >= 5000.00
                   ADD 05 TO WS-WK-RISK-POINTS
               END-IF
           END-IF

      *    Assign tier based on total points
           EVALUATE TRUE
               WHEN WS-WK-RISK-POINTS >= 80
                   SET WS-RISK-TIER-A TO TRUE
               WHEN WS-WK-RISK-POINTS >= 60
                   SET WS-RISK-TIER-B TO TRUE
               WHEN WS-WK-RISK-POINTS >= 40
                   SET WS-RISK-TIER-C TO TRUE
               WHEN WS-WK-RISK-POINTS >= 25
                   SET WS-RISK-TIER-D TO TRUE
               WHEN OTHER
                   SET WS-RISK-TIER-F TO TRUE
           END-EVALUATE
           .

      *================================================================*
      * 2560-MAKE-DECISION: Determine the final lending decision       *
      *================================================================*
       2560-MAKE-DECISION.
           EVALUATE TRUE
               WHEN WS-RISK-TIER-A
                   SET WS-DEC-APPROVED TO TRUE
                   MOVE WS-APP-LOAN-AMOUNT
                       TO WS-DEC-APPROVED-AMT
                   MOVE WS-APP-LOAN-TERM
                       TO WS-DEC-APPROVED-TERM
                   MOVE 'A001' TO WS-DEC-REASON-CODE
                   MOVE 'Approved: excellent risk profile'
                       TO WS-DEC-REASON-DESC
                   ADD 1 TO WS-CTR-APPROVED
                   ADD WS-APP-LOAN-AMOUNT
                       TO WS-ACC-TOTAL-APPROVED

               WHEN WS-RISK-TIER-B
                   SET WS-DEC-APPROVED TO TRUE
                   MOVE WS-APP-LOAN-AMOUNT
                       TO WS-DEC-APPROVED-AMT
                   MOVE WS-APP-LOAN-TERM
                       TO WS-DEC-APPROVED-TERM
                   MOVE 'A002' TO WS-DEC-REASON-CODE
                   MOVE 'Approved: good risk profile'
                       TO WS-DEC-REASON-DESC
                   ADD 1 TO WS-CTR-APPROVED
                   ADD WS-APP-LOAN-AMOUNT
                       TO WS-ACC-TOTAL-APPROVED

               WHEN WS-RISK-TIER-C
                   SET WS-DEC-COND-APPROVED TO TRUE
                   MOVE WS-APP-LOAN-AMOUNT
                       TO WS-DEC-APPROVED-AMT
                   MOVE WS-APP-LOAN-TERM
                       TO WS-DEC-APPROVED-TERM
                   MOVE 'C001' TO WS-DEC-REASON-CODE
                   MOVE 'Conditional: requires co-signer'
                       TO WS-DEC-REASON-DESC
                   MOVE 'CO-SIGNER OR ADDITIONAL COLLATERAL'
                       TO WS-DEC-CONDITIONS
                   ADD 1 TO WS-CTR-COND-APPROVED

               WHEN WS-RISK-TIER-D
                   SET WS-DEC-REFERRED TO TRUE
                   MOVE 'R001' TO WS-DEC-REASON-CODE
                   MOVE 'Referred: marginal risk, officer review'
                       TO WS-DEC-REASON-DESC
                   MOVE 'LO0042' TO WS-DEC-OFFICER-ID
                   ADD 1 TO WS-CTR-REFERRED

               WHEN WS-RISK-TIER-F
                   SET WS-DEC-DENIED TO TRUE
                   MOVE 'D001' TO WS-DEC-REASON-CODE
                   MOVE 'Denied: risk profile below minimum'
                       TO WS-DEC-REASON-DESC
                   ADD 1 TO WS-CTR-DENIED
                   ADD WS-APP-LOAN-AMOUNT
                       TO WS-ACC-TOTAL-DENIED
           END-EVALUATE
           .

      *================================================================*
      * 2800-DISPLAY-RESULT: Show the decision for this application    *
      *================================================================*
       2800-DISPLAY-RESULT.
           DISPLAY WS-C-DETAIL-SEP
           DISPLAY '  Application: ' WS-APP-ID
           DISPLAY '  Applicant:   ' WS-APP-FIRST-NAME
               ' ' WS-APP-LAST-NAME
           DISPLAY '  Product:     ' WS-APP-LOAN-TYPE

           MOVE WS-APP-LOAN-AMOUNT TO WS-DSP-FORMATTED-AMT
           DISPLAY '  Amount:      ' WS-DSP-FORMATTED-AMT

           DISPLAY '  Term:        ' WS-APP-LOAN-TERM ' months'
           DISPLAY '  Credit Score: ' WS-APP-CREDIT-SCORE

           MOVE WS-WK-DTI-RATIO TO WS-DSP-FORMATTED-PCT
           DISPLAY '  DTI Ratio:    ' WS-DSP-FORMATTED-PCT '%'

           DISPLAY '  Risk Points:  ' WS-WK-RISK-POINTS
               '  Tier: ' WS-WK-RISK-TIER

           EVALUATE TRUE
               WHEN WS-DEC-APPROVED
                   DISPLAY '  Decision:  *** APPROVED ***'
               WHEN WS-DEC-COND-APPROVED
                   DISPLAY '  Decision:  CONDITIONALLY APPROVED'
                   DISPLAY '  Conditions: '
                       WS-DEC-CONDITIONS
               WHEN WS-DEC-DENIED
                   DISPLAY '  Decision:  *** DENIED ***'
               WHEN WS-DEC-REFERRED
                   DISPLAY '  Decision:  REFERRED TO OFFICER '
                       WS-DEC-OFFICER-ID
           END-EVALUATE

           DISPLAY '  Reason:      ' WS-DEC-REASON-DESC
           IF WS-WK-ERROR-COUNT > 0
               DISPLAY '  Errors Found: ' WS-WK-ERROR-COUNT
           END-IF
           DISPLAY SPACES
           .

      *================================================================*
      * 3000-PRINT-SUMMARY: Nightly batch processing summary           *
      *================================================================*
       3000-PRINT-SUMMARY.
           DISPLAY WS-C-REPORT-SEP
           DISPLAY '  NIGHTLY PROCESSING SUMMARY'
           DISPLAY WS-C-REPORT-SEP
           DISPLAY SPACES

           MOVE WS-CTR-TOTAL-READ TO WS-DSP-FORMATTED-COUNT
           DISPLAY '  Total Applications:     '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-APPROVED TO WS-DSP-FORMATTED-COUNT
           DISPLAY '  Approved:               '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-COND-APPROVED TO WS-DSP-FORMATTED-COUNT
           DISPLAY '  Conditionally Approved: '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-DENIED TO WS-DSP-FORMATTED-COUNT
           DISPLAY '  Denied:                 '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-REFERRED TO WS-DSP-FORMATTED-COUNT
           DISPLAY '  Referred to Officer:    '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-ERRORS TO WS-DSP-FORMATTED-COUNT
           DISPLAY '  Validation Errors:      '
               WS-DSP-FORMATTED-COUNT

           DISPLAY SPACES
           DISPLAY '  BY PRODUCT TYPE:'

           MOVE WS-CTR-PERSONAL TO WS-DSP-FORMATTED-COUNT
           DISPLAY '    Personal:       '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-AUTO-NEW TO WS-DSP-FORMATTED-COUNT
           DISPLAY '    Auto (New):     '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-AUTO-USED TO WS-DSP-FORMATTED-COUNT
           DISPLAY '    Auto (Used):    '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-HOME-EQUITY TO WS-DSP-FORMATTED-COUNT
           DISPLAY '    Home Equity:    '
               WS-DSP-FORMATTED-COUNT

           MOVE WS-CTR-SHARE-SECURED TO WS-DSP-FORMATTED-COUNT
           DISPLAY '    Share Secured:  '
               WS-DSP-FORMATTED-COUNT

           DISPLAY SPACES

           MOVE WS-ACC-TOTAL-REQUESTED TO WS-DSP-FORMATTED-AMT
           DISPLAY '  Total Requested:  ' WS-DSP-FORMATTED-AMT

           MOVE WS-ACC-TOTAL-APPROVED  TO WS-DSP-FORMATTED-AMT
           DISPLAY '  Total Approved:   ' WS-DSP-FORMATTED-AMT

           MOVE WS-ACC-TOTAL-DENIED    TO WS-DSP-FORMATTED-AMT
           DISPLAY '  Total Denied:     ' WS-DSP-FORMATTED-AMT

           DISPLAY SPACES
           DISPLAY WS-C-REPORT-SEP
           .

Solution Walkthrough

Step 1: Constants as the Foundation

Roberto placed all product limits, thresholds, and scoring boundaries at the top of WORKING-STORAGE. Each loan product has its own 01-level group (WS-C-PERSONAL-LIMITS, WS-C-AUTO-NEW-LIMITS, etc.), making it trivial to locate and modify product parameters. When MCCU later added a sixth loan product -- a small-dollar emergency loan -- Roberto simply added a new WS-C-EMERGENCY-LIMITS group and a new 88-level value under WS-APP-LOAN-TYPE. No existing constant definitions needed modification.

The DTI thresholds and credit score thresholds are similarly isolated. When MCCU's board of directors adjusted the "fair" DTI threshold from 0.43 to 0.40, Roberto changed a single VALUE clause. Every paragraph that tested DTI ranges through the 88-level conditions continued to work without modification.

Step 2: The Application Record as a Group Hierarchy

The loan application data is organized into five logical sub-groups under separate 01-level items: header, personal, employment, financial, and loan request. This design provides several advantages:

  • Selective initialization. The 2050-CLEAR-APPLICATION paragraph initializes each group individually. If a future enhancement requires preserving the header while resetting the financial details (for example, when the same applicant submits multiple loan requests), Roberto can initialize only WS-APP-FINANCIAL and WS-APP-LOAN-REQUEST.

  • Readable references. Field names like WS-APP-CREDIT-SCORE and WS-APP-YEARS-EMPLOYED are immediately meaningful. A maintenance programmer encountering IF WS-SCORE-EXCELLENT in the PROCEDURE DIVISION can trace it back to WS-APP-CREDIT-SCORE and see the threshold (740 THRU 850) without consulting any external documentation.

  • Group-level operations. MCCU later added a feature to write the entire application record to an audit file. Because the groups are cleanly defined, the WRITE statement could reference each 01-level group directly.

Step 3: 88-Level Conditions as Business Language

Roberto's most impactful design decision was the systematic use of 88-level conditions. Every field that participates in any decision has condition names:

  • Loan type has individual values (WS-LOAN-PERSONAL, WS-LOAN-AUTO-NEW) and a composite validation condition (WS-LOAN-TYPE-VALID).
  • Employment status has individual values, a composite "actively employed" condition (WS-EMP-ACTIVE), and a validation condition (WS-EMP-VALID-STATUS).
  • Credit score has range-based conditions using THRU that exactly match MCCU's credit policy tiers.
  • Decision status has conditions for each possible outcome, enabling EVALUATE TRUE in the display logic.
  • Risk tier has both individual tiers and a composite "acceptable risk" condition (WS-RISK-ACCEPTABLE).

The composite conditions deserve special attention. WS-EMP-ACTIVE combines full-time, part-time, self-employed, and retired into a single condition. This means the business rule "applicant must be actively employed" can be tested with IF WS-EMP-ACTIVE instead of enumerating four codes. When MCCU later added a "contract worker" employment status ('C'), the developer added the value to WS-EMP-ACTIVE and WS-EMP-VALID-STATUS, and every reference to those conditions in the PROCEDURE DIVISION automatically included the new status.

Step 4: The Error Table for Multi-Error Reporting

The error message table (WS-WK-ERROR-TABLE) uses OCCURS to allow accumulating up to 15 errors per application. This is critical for user experience: rather than rejecting an application on the first error and forcing the applicant to resubmit repeatedly, the system collects all validation failures and reports them together. The branch teller or online form can display all issues at once.

Step 5: The Reset Strategy

The 2050-CLEAR-APPLICATION paragraph demonstrates a crucial design decision: which fields to reset between applications and which to preserve. The application data, calculation fields, error table, and decision result are all initialized. The counters, accumulators, and program constants are never initialized -- they must persist across all applications in the batch run.

Roberto uses INITIALIZE rather than MOVE SPACES or MOVE ZEROS because the application record contains both alphanumeric and numeric fields. INITIALIZE correctly sets alphanumeric fields to SPACES and numeric fields to ZEROS, while MOVE SPACES would corrupt the numeric fields.

Lessons Learned

1. REDEFINES for Date Flexibility

Roberto defined the application date as a numeric field (PIC 9(08)) with a REDEFINES that breaks it into year, month, and day components. This allows the program to store the date as a single value (for sorting and comparison) while also accessing individual components (for age calculation, month-end processing, and display formatting). This dual-access pattern appears throughout production COBOL systems wherever dates are used.

2. The "Valid" Composite Condition

Adding a composite 88-level condition that combines all valid values for a field (like WS-LOAN-TYPE-VALID and WS-EMP-VALID-STATUS) is a simple practice that dramatically simplifies validation logic. Instead of testing each valid value individually, one condition check handles them all. When new valid values are added, only the composite condition and the individual condition definitions need updating.

3. Separating Calculation Fields from Application Data

Roberto placed all calculation work fields in their own group (WS-WK-CALC-FIELDS), separate from the application data. This separation means the calculation fields can be initialized without disturbing the application record, and the application record can be written to an audit file without including intermediate calculation artifacts.

4. Display Fields Sized for Formatting

The display fields (WS-DSP-FORMATTED-AMT, WS-DSP-FORMATTED-PCT, WS-DSP-FORMATTED-COUNT) are defined with numeric-edited PIC clauses that include currency signs, commas, and decimal points. Roberto sized these fields to accommodate the maximum values from the corresponding work fields. A common mistake is under-sizing display fields, which causes asterisk overflow in reports -- a defect that is embarrassing but not always caught in testing.

5. Risk Scoring Through WORKING-STORAGE Design

The risk tier determination uses a point-based scoring system where points are accumulated in WS-WK-RISK-POINTS and then mapped to a risk tier through EVALUATE. This design makes the scoring model transparent and auditable. When MCCU's compliance team asked to review the scoring criteria, Roberto could walk them through the WORKING-STORAGE definitions and the scoring paragraph in a single meeting. The thresholds were all visible as VALUE clauses, and the point assignments were clear in the EVALUATE structure.

Discussion Questions

  1. Roberto defined five separate 01-level groups for the product limits. An alternative design would be a single table with OCCURS 5 TIMES, indexed by product type. What are the advantages and disadvantages of each approach? When would the table approach be preferable?

  2. The error table uses OCCURS 15 TIMES. How would you determine the right number of entries? What happens if the application has more than 15 errors? How would you handle this in the PROCEDURE DIVISION?

  3. The composite 88-level condition WS-EMP-ACTIVE includes retired status. A business analyst argues that retired applicants should be handled differently from actively employed ones. How would you restructure the 88-level conditions to accommodate this change while minimizing impact on existing code?

  4. Roberto uses INITIALIZE for clearing application fields between records. What would happen if he used MOVE SPACES TO WS-APP-FINANCIAL instead? How would the resulting data corruption manifest during processing?

  5. The risk scoring model assigns up to 100 points across four categories. If MCCU wanted to add a fifth category (asset verification, worth up to 15 points), what WORKING-STORAGE changes would be needed? What PROCEDURE DIVISION changes would be needed? How does the separation of constants from logic help with this kind of enhancement?

  6. Examine the REDEFINES on WS-APP-DATE. If you needed to display the date as "March 15, 2024" rather than "20240315", what additional WORKING-STORAGE items would you define? Would you use REDEFINES, a separate display field, or both?