Chapter 39 Exercises: Legacy System Maintenance and Modernization
These exercises are organized into five tiers of increasing difficulty. Work through them sequentially to build mastery, or jump to the tier that matches your current skill level.
Tier 1: Recall (Exercises 1-6)
These exercises cover the fundamental concepts and vocabulary of legacy code maintenance and modernization.
Exercise 1: Legacy Code Indicators
List five common characteristics of legacy COBOL code that indicate it needs modernization. For each characteristic, explain why it is problematic.
Solution:
- Excessive GO TO statements -- Creates spaghetti control flow that is difficult to trace, test, and modify. A single change can have unpredictable effects on distant parts of the program.
- Monolithic paragraph structure -- Programs with a few enormous paragraphs (500+ lines each) instead of small, focused paragraphs. Makes the program difficult to understand and impossible to unit-test individual functions.
- Hardcoded literals ("magic numbers") -- Values like
IF WS-CODE = 47scattered throughout without explanation. Makes maintenance error-prone because the meaning of 47 is unclear and changing the value requires finding every occurrence. - Dead code -- Paragraphs, variables, and conditions that are never executed or referenced. Clutters the program, confuses maintainers, and may trigger false positives in code analysis.
- Copybook duplication -- The same data structure defined in multiple programs without using COPY. Changes must be applied to every copy, and inconsistencies inevitably arise.
Exercise 2: Modernization Strategy Definitions
Define each of the following modernization strategies and provide one sentence describing when each is most appropriate:
- Rehost
- Replatform
- Refactor
- Rearchitect
- Replace
- Retain (encapsulate)
Solution:
- Rehost (lift and shift): Move the application as-is to a new infrastructure (e.g., mainframe to cloud COBOL runtime) without changing code. Appropriate when the primary goal is reducing infrastructure costs with minimal risk.
- Replatform: Move the application to a new platform with minor adaptations (e.g., mainframe COBOL to Micro Focus COBOL on Linux). Appropriate when the target platform offers cost savings and the code needs only minor adjustments.
- Refactor: Restructure the existing COBOL code to improve maintainability without changing its external behavior. Appropriate when the business logic is sound but the code structure impedes maintenance.
- Rearchitect: Redesign the application's architecture (e.g., monolith to microservices) while preserving the business logic. Appropriate when the current architecture cannot support new business requirements like real-time processing or API access.
- Replace: Retire the COBOL application entirely and implement a commercial off-the-shelf (COTS) or custom-built replacement. Appropriate when the business process has fundamentally changed and the existing code cannot be adapted.
- Retain (encapsulate): Keep the legacy code running but wrap it with modern interfaces (APIs, message queues). Appropriate when the code is stable, well-tested, and the business logic is too complex or risky to rewrite.
Exercise 3: GO TO Classification
Classify each of the following GO TO usages as either (A) eliminable through simple restructuring, (B) a forward-branch that can become an IF/END-IF, or (C) a backward-branch that should become a PERFORM loop:
* Usage 1:
IF WS-ERROR-FLAG = 1
GO TO 9999-EXIT
END-IF
* Usage 2:
1000-LOOP.
READ INPUT-FILE INTO WS-RECORD
IF WS-EOF-FLAG = 1
GO TO 1000-EXIT
END-IF
PERFORM 2000-PROCESS-RECORD
GO TO 1000-LOOP.
1000-EXIT.
* Usage 3:
GO TO 3100-STEP-A
3200-STEP-B
3300-STEP-C
DEPENDING ON WS-STEP-NUM.
* Usage 4:
IF WS-AMOUNT < 0
GO TO 5000-REJECT
END-IF
IF WS-AMOUNT > 99999
GO TO 5000-REJECT
END-IF
PERFORM 5100-ACCEPT.
GO TO 5200-CONTINUE.
5000-REJECT.
MOVE "INVALID" TO WS-STATUS.
5200-CONTINUE.
Solution:
- (B) Forward branch -- This is an early-exit pattern. It can be restructured with a PERFORM-through or by wrapping the remaining logic in an IF condition.
- (C) Backward branch -- The
GO TO 1000-LOOPcreates a loop. This should becomePERFORM 1000-LOOP UNTIL WS-EOF-FLAG = 1with the read and process logic inside. - (A) Eliminable -- GO TO DEPENDING ON is directly replaceable with EVALUATE/WHEN. Each target paragraph becomes a WHEN clause.
- (B) Forward branch -- The two GO TOs to 5000-REJECT skip the accept logic. This can be restructured with nested IF/ELSE:
IF WS-AMOUNT >= 0 AND WS-AMOUNT <= 99999 THEN ACCEPT ELSE REJECT.
Exercise 4: Strangler Fig Pattern
Explain the Strangler Fig pattern for legacy modernization. Answer these questions: 1. Where does the name come from? 2. What are the three phases of the pattern? 3. Why is it preferred over "big bang" replacement?
Solution:
- The name comes from the strangler fig tree, which grows around an existing tree, gradually replacing it. Eventually the original tree dies and the fig stands on its own. Similarly, the new system gradually replaces the old system's functionality.
- The three phases are: (a) Transform -- build new functionality that replaces a specific piece of the old system. (b) Coexist -- run both old and new simultaneously, routing traffic to the appropriate system. (c) Eliminate -- once the new component is proven, decommission the corresponding old component.
- It is preferred over big-bang replacement because it reduces risk. Each increment is small, testable, and reversible. If the new component fails, traffic can be routed back to the old system. The organization sees incremental value rather than waiting years for a complete replacement. Business operations are never disrupted.
Exercise 5: Data Modernization Concepts
Define each of the following data modernization terms:
- VSAM to DB2 migration
- EBCDIC to ASCII conversion
- Packed decimal to binary conversion
- Copybook extraction to JSON schema
- Date field expansion (Y2K-style)
Solution:
- VSAM to DB2 migration -- Moving data from VSAM file structures (KSDS, ESDS, RRDS) to DB2 relational database tables. This enables SQL access, better data sharing, and integration with modern analytics tools.
- EBCDIC to ASCII conversion -- Converting character data from EBCDIC encoding (used on IBM mainframes) to ASCII/UTF-8 (used on distributed systems). Required when moving data or programs off the mainframe.
- Packed decimal to binary conversion -- Converting COMP-3 (packed decimal) numeric fields to COMP (binary) or to standard integer/decimal types used by modern databases and languages.
- Copybook extraction to JSON schema -- Analyzing COBOL copybook layouts (01-level with PIC clauses) and generating equivalent JSON schema definitions. This enables non-COBOL systems to understand and validate data exchanged with the COBOL program.
- Date field expansion -- Expanding 2-digit year fields (PIC 9(2) or PIC 9(6) for YYMMDD) to 4-digit year fields (PIC 9(4) or PIC 9(8) for YYYYMMDD). Originally driven by Y2K but still relevant for legacy systems that were patched with windowing techniques rather than proper expansion.
Exercise 6: Code Smell Identification
Examine the following code fragment and list every "code smell" (maintenance problem) you can find:
2000-PROC.
MOVE 0 TO A B C D
GO TO 2100-X.
2100-X.
READ INFILE INTO R AT END GO TO 2900-END.
IF R-CODE = 'A' ADD R-AMT TO A GO TO 2100-X.
IF R-CODE = 'B' ADD R-AMT TO B GO TO 2100-X.
IF R-CODE = 'C' ADD R-AMT TO C GO TO 2100-X.
ADD R-AMT TO D.
GO TO 2100-X.
2900-END.
DISPLAY A B C D.
Solution:
- Single-letter variable names (A, B, C, D, R) -- No indication of purpose.
- GO TO loop -- The backward GO TO to 2100-X creates an implicit loop that should be PERFORM UNTIL.
- Inline READ with GO TO -- AT END with GO TO is the pre-structured programming pattern. Should use PERFORM with EOF flag.
- No END-IF terminators -- The cascading IF statements without END-IF are fragile and hard to modify.
- Magic literal codes -- 'A', 'B', 'C' are unexplained. Should use 88-level condition names.
- No paragraph separation -- Multiple responsibilities crammed into one flow (read, categorize, accumulate, display).
- Inline processing -- The DISPLAY at 2900-END mixes I/O with computation. Accumulation and reporting should be separate.
- Unnecessary GO TO -- The
GO TO 2100-XafterMOVE 0 TO A B C Dis pointless since 2100-X is the next sequential paragraph.
Tier 2: Understand (Exercises 7-13)
These exercises require explaining concepts, comparing approaches, and analyzing legacy code.
Exercise 7: GO TO Elimination -- Forward Branch
Rewrite the following GO TO forward-branch pattern using structured IF/ELSE:
3000-VALIDATE.
IF WS-NAME = SPACES
MOVE "NAME REQUIRED" TO WS-ERROR
GO TO 3000-EXIT
END-IF
IF WS-AMOUNT < 0
MOVE "INVALID AMOUNT" TO WS-ERROR
GO TO 3000-EXIT
END-IF
IF WS-DATE NOT NUMERIC
MOVE "INVALID DATE" TO WS-ERROR
GO TO 3000-EXIT
END-IF
MOVE "VALID" TO WS-STATUS
PERFORM 3100-PROCESS-RECORD.
3000-EXIT.
EXIT.
Solution:
3000-VALIDATE.
MOVE SPACES TO WS-ERROR
EVALUATE TRUE
WHEN WS-NAME = SPACES
MOVE "NAME REQUIRED" TO WS-ERROR
WHEN WS-AMOUNT < 0
MOVE "INVALID AMOUNT" TO WS-ERROR
WHEN WS-DATE NOT NUMERIC
MOVE "INVALID DATE" TO WS-ERROR
WHEN OTHER
MOVE "VALID" TO WS-STATUS
PERFORM 3100-PROCESS-RECORD
END-EVALUATE
.
The EVALUATE replaces the cascading IF/GO TO pattern. Each validation check is a WHEN clause, and the happy path (all validations pass) is in WHEN OTHER.
Exercise 8: GO TO Elimination -- Backward Branch (Loop)
Rewrite this GO TO-based loop using PERFORM UNTIL:
5000-CALC-TOTAL.
MOVE 0 TO WS-TOTAL.
MOVE 0 TO WS-COUNT.
5100-LOOP.
READ TRANS-FILE INTO WS-TRANS-REC
AT END GO TO 5200-DONE.
ADD WS-TRANS-AMOUNT TO WS-TOTAL.
ADD 1 TO WS-COUNT.
IF WS-TRANS-AMOUNT > WS-LIMIT
PERFORM 6000-FLAG-EXCEPTION
END-IF.
GO TO 5100-LOOP.
5200-DONE.
IF WS-COUNT > 0
COMPUTE WS-AVERAGE = WS-TOTAL / WS-COUNT
END-IF.
Solution:
5000-CALC-TOTAL.
MOVE 0 TO WS-TOTAL
MOVE 0 TO WS-COUNT
MOVE "N" TO WS-EOF-FLAG
PERFORM 5100-READ-AND-PROCESS
UNTIL WS-EOF-FLAG = "Y"
IF WS-COUNT > 0
COMPUTE WS-AVERAGE = WS-TOTAL / WS-COUNT
END-IF
.
5100-READ-AND-PROCESS.
READ TRANS-FILE INTO WS-TRANS-REC
AT END
MOVE "Y" TO WS-EOF-FLAG
NOT AT END
ADD WS-TRANS-AMOUNT TO WS-TOTAL
ADD 1 TO WS-COUNT
IF WS-TRANS-AMOUNT > WS-LIMIT
PERFORM 6000-FLAG-EXCEPTION
END-IF
END-READ
.
Exercise 9: Paragraph Extraction
The following paragraph does too many things. Identify the distinct responsibilities and extract each into its own paragraph:
2000-PROCESS.
READ INPUT-FILE INTO WS-INPUT-REC
AT END MOVE "Y" TO WS-EOF.
IF WS-EOF = "Y"
GO TO 2000-EXIT
END-IF.
IF WS-INPUT-TYPE = "H"
MOVE WS-INPUT-DATE TO WS-HDR-DATE
MOVE WS-INPUT-BATCH TO WS-HDR-BATCH
ADD 1 TO WS-HDR-COUNT
END-IF.
IF WS-INPUT-TYPE = "D"
MOVE WS-INPUT-ACCT TO WS-DTL-ACCT
MOVE WS-INPUT-AMT TO WS-DTL-AMT
ADD WS-DTL-AMT TO WS-BATCH-TOTAL
ADD 1 TO WS-DTL-COUNT
IF WS-DTL-AMT > 10000
MOVE "Y" TO WS-REVIEW-FLAG
ADD 1 TO WS-REVIEW-COUNT
END-IF
WRITE OUTPUT-REC FROM WS-DTL-LINE
END-IF.
IF WS-INPUT-TYPE = "T"
IF WS-BATCH-TOTAL NOT = WS-INPUT-AMT
DISPLAY "BATCH TOTAL MISMATCH"
MOVE "Y" TO WS-ERROR-FLAG
END-IF
END-IF.
2000-EXIT.
EXIT.
Solution:
2000-PROCESS.
PERFORM 2100-READ-INPUT
IF WS-EOF NOT = "Y"
EVALUATE WS-INPUT-TYPE
WHEN "H"
PERFORM 2200-PROCESS-HEADER
WHEN "D"
PERFORM 2300-PROCESS-DETAIL
WHEN "T"
PERFORM 2400-PROCESS-TRAILER
END-EVALUATE
END-IF
.
2100-READ-INPUT.
READ INPUT-FILE INTO WS-INPUT-REC
AT END MOVE "Y" TO WS-EOF
END-READ
.
2200-PROCESS-HEADER.
MOVE WS-INPUT-DATE TO WS-HDR-DATE
MOVE WS-INPUT-BATCH TO WS-HDR-BATCH
ADD 1 TO WS-HDR-COUNT
.
2300-PROCESS-DETAIL.
MOVE WS-INPUT-ACCT TO WS-DTL-ACCT
MOVE WS-INPUT-AMT TO WS-DTL-AMT
ADD WS-DTL-AMT TO WS-BATCH-TOTAL
ADD 1 TO WS-DTL-COUNT
IF WS-DTL-AMT > 10000
PERFORM 2310-FLAG-FOR-REVIEW
END-IF
WRITE OUTPUT-REC FROM WS-DTL-LINE
.
2310-FLAG-FOR-REVIEW.
MOVE "Y" TO WS-REVIEW-FLAG
ADD 1 TO WS-REVIEW-COUNT
.
2400-PROCESS-TRAILER.
IF WS-BATCH-TOTAL NOT = WS-INPUT-AMT
DISPLAY "BATCH TOTAL MISMATCH"
MOVE "Y" TO WS-ERROR-FLAG
END-IF
.
Exercise 10: Condition Name Refactoring
Replace the following magic numbers and string comparisons with 88-level condition names:
01 WS-ACCT-STATUS PIC X(1).
01 WS-TXN-TYPE PIC 9(2).
01 WS-PRIORITY PIC 9(1).
IF WS-ACCT-STATUS = "A" OR "R"
IF WS-TXN-TYPE = 01 OR 02 OR 03
IF WS-PRIORITY = 1
PERFORM 5000-HIGH-PRIORITY
END-IF
END-IF
END-IF
Solution:
01 WS-ACCT-STATUS PIC X(1).
88 ACCT-ACTIVE VALUE "A".
88 ACCT-RESTRICTED VALUE "R".
88 ACCT-USABLE VALUE "A" "R".
01 WS-TXN-TYPE PIC 9(2).
88 TXN-DEPOSIT VALUE 01.
88 TXN-WITHDRAWAL VALUE 02.
88 TXN-TRANSFER VALUE 03.
88 TXN-STANDARD VALUE 01 THRU 03.
01 WS-PRIORITY PIC 9(1).
88 PRIORITY-HIGH VALUE 1.
88 PRIORITY-MEDIUM VALUE 2.
88 PRIORITY-LOW VALUE 3.
IF ACCT-USABLE AND TXN-STANDARD
AND PRIORITY-HIGH
PERFORM 5000-HIGH-PRIORITY
END-IF
Exercise 11: Assessing Modernization Risk
A 15,000-line COBOL batch program has the following characteristics: - 147 GO TO statements - 23 paragraphs (average 650 lines each) - 12 COPY members referenced - 3 VSAM files and 1 DB2 table accessed - Last modified 8 months ago (minor bug fix) - 2 developers familiar with the code (one retiring in 6 months) - Processes $4.2 billion in transactions monthly
Rate the modernization urgency as LOW, MEDIUM, or HIGH for each factor and explain your reasoning. What modernization strategy would you recommend?
Solution:
- GO TO density (147 in 15K lines): HIGH -- Approximately 1 GO TO per 100 lines indicates severely tangled control flow.
- Paragraph size (avg 650 lines): HIGH -- Extremely large paragraphs are nearly impossible to understand or modify safely.
- External dependencies (12 copies, 4 files/tables): MEDIUM -- Moderate coupling to external structures; changes in copybooks or file layouts affect this program.
- Recent modification activity: LOW -- Recent successful modification indicates the code is still maintainable by current staff.
- Knowledge concentration (2 developers, 1 retiring): HIGH -- Critical knowledge loss imminent. This is the most urgent factor.
- Business criticality ($4.2B monthly): HIGH -- The consequences of a failure are severe, which paradoxically makes both inaction and aggressive change risky.
Recommended strategy: Refactor incrementally with knowledge capture. Before the experienced developer retires, invest 3-4 months in: (1) documenting the business rules embedded in the code, (2) extracting the large paragraphs into smaller, named paragraphs, (3) eliminating the most dangerous GO TO patterns, and (4) adding inline comments. Do NOT attempt a rewrite or replacement given the business criticality and time pressure.
Exercise 12: Legacy Code Reading
Read the following legacy code and describe in plain English what it does. Identify the business rule it implements:
4000-CALC.
MOVE 0 TO T.
IF C > 50000
COMPUTE T = (C - 50000) * .03
MOVE 50000 TO C
END-IF.
IF C > 20000
COMPUTE T = T + (C - 20000) * .02
MOVE 20000 TO C
END-IF.
IF C > 5000
COMPUTE T = T + (C - 5000) * .01
END-IF.
Solution:
This implements a tiered/progressive fee or tax calculation on a value C: - On the portion of C above $50,000: charge 3% - On the portion of C between $20,001 and $50,000: charge 2% - On the portion of C between $5,001 and $20,000: charge 1% - On the portion of C at or below $5,000: no charge
The total fee T is accumulated across all tiers. The code destructively modifies C at each tier boundary (capping it for the next tier's calculation). For example, if C = $75,000: T = (75000-50000) * 0.03 + (50000-20000) * 0.02 + (20000-5000) * 0.01 = 750 + 600 + 150 = $1,500.
This is a progressive rate structure commonly used for taxes, transaction fees, or commission calculations.
Exercise 13: Wrapper Pattern Explanation
Explain the wrapper (facade) pattern for legacy COBOL modernization. Describe: 1. What the wrapper does. 2. How the legacy code is invoked. 3. What the external interface looks like. 4. When this approach is preferable to rewriting.
Solution:
-
What the wrapper does: The wrapper is a new COBOL program (or a z/OS Connect service) that provides a clean, modern interface to external consumers while internally delegating all business logic to the unchanged legacy program. It translates between the modern interface (JSON/REST) and the legacy interface (COMMAREA/file I/O).
-
How the legacy code is invoked: The wrapper calls the legacy program using CALL or EXEC CICS LINK, passing data through the LINKAGE SECTION or COMMAREA exactly as the legacy program expects. The legacy program runs unchanged.
-
What the external interface looks like: External consumers see a clean API with well-named fields, proper error codes, and modern data formats (JSON). They are completely unaware that a legacy program exists behind the wrapper.
-
When this is preferable to rewriting: When the legacy code contains complex, well-tested business logic that has been validated over decades of production use. Rewriting risks introducing bugs in logic that was correct. The wrapper preserves the proven logic while enabling modern access patterns.
Tier 3: Apply (Exercises 14-21)
These exercises require performing actual code refactoring and modernization tasks.
Exercise 14: Complete GO TO Elimination
Refactor the following legacy program to eliminate all GO TO statements. Preserve the exact business logic:
PROCEDURE DIVISION.
0000-START.
OPEN INPUT CUST-FILE OUTPUT REPORT-FILE.
MOVE 0 TO LINE-CT PAGE-CT TOTAL-AMT.
0100-READ.
READ CUST-FILE AT END GO TO 0900-DONE.
ADD 1 TO LINE-CT.
IF LINE-CT > 50
PERFORM 0800-NEW-PAGE
MOVE 0 TO LINE-CT
END-IF.
IF CUST-BAL < 0
GO TO 0100-READ.
IF CUST-BAL > 100000
MOVE "*" TO FLAG-FIELD
ELSE
MOVE " " TO FLAG-FIELD.
ADD CUST-BAL TO TOTAL-AMT.
WRITE RPT-REC FROM DETAIL-LINE.
GO TO 0100-READ.
0800-NEW-PAGE.
ADD 1 TO PAGE-CT.
WRITE RPT-REC FROM HDR-LINE AFTER PAGE.
0900-DONE.
WRITE RPT-REC FROM TOTAL-LINE.
CLOSE CUST-FILE REPORT-FILE.
STOP RUN.
Solution:
PROCEDURE DIVISION.
0000-MAIN.
PERFORM 0100-INITIALIZE
PERFORM 0200-PROCESS-FILE
UNTIL WS-EOF-FLAG = "Y"
PERFORM 0900-FINALIZE
STOP RUN
.
0100-INITIALIZE.
OPEN INPUT CUST-FILE OUTPUT REPORT-FILE
MOVE 0 TO LINE-CT PAGE-CT TOTAL-AMT
MOVE "N" TO WS-EOF-FLAG
.
0200-PROCESS-FILE.
READ CUST-FILE
AT END
MOVE "Y" TO WS-EOF-FLAG
NOT AT END
PERFORM 0300-PROCESS-RECORD
END-READ
.
0300-PROCESS-RECORD.
ADD 1 TO LINE-CT
IF LINE-CT > 50
PERFORM 0800-NEW-PAGE
MOVE 0 TO LINE-CT
END-IF
IF CUST-BAL >= 0
IF CUST-BAL > 100000
MOVE "*" TO FLAG-FIELD
ELSE
MOVE " " TO FLAG-FIELD
END-IF
ADD CUST-BAL TO TOTAL-AMT
WRITE RPT-REC FROM DETAIL-LINE
END-IF
.
0800-NEW-PAGE.
ADD 1 TO PAGE-CT
WRITE RPT-REC FROM HDR-LINE AFTER PAGE
.
0900-FINALIZE.
WRITE RPT-REC FROM TOTAL-LINE
CLOSE CUST-FILE REPORT-FILE
.
Exercise 15: Magic Number Elimination
Refactor the following code to replace all magic numbers with named constants using 88-level conditions and WORKING-STORAGE constants:
IF WS-DEPT = 140 OR 220 OR 350
COMPUTE WS-BONUS = WS-SALARY * 0.15
ELSE IF WS-DEPT = 410 OR 520
COMPUTE WS-BONUS = WS-SALARY * 0.10
ELSE
COMPUTE WS-BONUS = WS-SALARY * 0.05
END-IF
IF WS-YEARS > 10
ADD 2500 TO WS-BONUS
ELSE IF WS-YEARS > 5
ADD 1000 TO WS-BONUS
END-IF
IF WS-BONUS > 25000
MOVE 25000 TO WS-BONUS
END-IF
Hint: Define 88-levels for department groups, named constants for rates and thresholds.
Exercise 16: Copybook Creation from Inline Definitions
The following data definitions appear in three different programs. Extract them into a single copybook and show how each program would reference it:
* Program PGMA:
01 CUSTOMER-RECORD.
05 CUST-ID PIC 9(8).
05 CUST-NAME PIC X(30).
05 CUST-ADDR PIC X(40).
05 CUST-BAL PIC S9(9)V99.
05 CUST-STATUS PIC X(1).
* Program PGMB (slightly different):
01 CUST-REC.
05 CR-ID PIC 9(8).
05 CR-NAME PIC X(30).
05 CR-ADDRESS PIC X(40).
05 CR-BALANCE PIC S9(9)V99.
05 CR-STAT PIC X(1).
* Program PGMC (wrong size!):
01 CUSTOMER.
05 C-ID PIC 9(8).
05 C-NAME PIC X(25).
05 C-ADDR PIC X(40).
05 C-BAL PIC S9(7)V99.
05 C-STATUS PIC X(1).
Hint: Choose canonical names, ensure all programs use the same sizes, and note the data inconsistency in PGMC that must be investigated.
Exercise 17: Dead Code Removal
Identify and remove all dead code from the following program fragment. Explain why each piece is dead:
WORKING-STORAGE SECTION.
01 WS-OLD-RATE PIC 9V99 VALUE 0.05.
01 WS-NEW-RATE PIC 9V99 VALUE 0.07.
01 WS-TEMP-CALC PIC 9(9)V99.
01 WS-UNUSED-FLAG PIC X VALUE "N".
01 WS-COUNTER PIC 9(5) VALUE 0.
PROCEDURE DIVISION.
MOVE 0 TO WS-COUNTER
PERFORM 1000-PROCESS
PERFORM 2000-REPORT
STOP RUN.
1000-PROCESS.
COMPUTE WS-TEMP-CALC =
WS-BALANCE * WS-NEW-RATE
IF 1 = 0
PERFORM 3000-OLD-CALCULATION
END-IF
.
2000-REPORT.
DISPLAY "Rate: " WS-NEW-RATE
DISPLAY "Result: " WS-TEMP-CALC
.
3000-OLD-CALCULATION.
COMPUTE WS-TEMP-CALC =
WS-BALANCE * WS-OLD-RATE
ADD 1 TO WS-COUNTER
.
Hint: Check for unreachable code, unused variables, and conditions that can never be true.
Exercise 18: API Facade for Legacy Program
Write a COBOL wrapper program that provides a clean CALL interface around a legacy program with a poorly designed LINKAGE SECTION. The legacy program expects:
* Legacy program LGCYPGM expects:
01 LS-INPUT.
05 LS-FUNC PIC 9. *> 1=Add 2=Del 3=Inq
05 LS-KEY PIC X(8).
05 LS-D1 PIC X(30). *> Name for func 1
05 LS-D2 PIC 9(7)V99. *> Amount for func 1
05 LS-RC PIC 9. *> 0=OK 1=Err 2=NotFnd
Design a wrapper with clearly named parameters and proper error handling.
Hint: Create separate entry points or an EVALUATE-based dispatch with well-named fields.
Exercise 19: PERFORM THRU Elimination
Refactor the following PERFORM THRU pattern into individual paragraph PERFORMs:
PERFORM 2000-VALIDATE THRU 2000-VALIDATE-EXIT.
PERFORM 3000-CALCULATE THRU 3999-CALCULATE-EXIT.
2000-VALIDATE.
IF WS-FIELD-A = SPACES
MOVE "ERR" TO WS-STATUS
GO TO 2000-VALIDATE-EXIT
END-IF
IF WS-FIELD-B NOT NUMERIC
MOVE "ERR" TO WS-STATUS
GO TO 2000-VALIDATE-EXIT
END-IF
MOVE "OK" TO WS-STATUS.
2000-VALIDATE-EXIT.
EXIT.
3000-CALCULATE.
COMPUTE WS-RESULT = WS-A + WS-B.
IF WS-RESULT < 0
GO TO 3999-CALCULATE-EXIT.
COMPUTE WS-TAX = WS-RESULT * WS-RATE.
3999-CALCULATE-EXIT.
EXIT.
Hint: Replace PERFORM THRU with PERFORM of a single paragraph. Eliminate the GO TO to EXIT paragraphs by using IF/ELSE logic or EVALUATE.
Exercise 20: Data Format Migration
Write a COBOL utility program that reads records in the old format and writes them in the new format:
Old format:
01 OLD-RECORD.
05 OLD-DATE PIC 9(6). *> YYMMDD
05 OLD-NAME PIC X(20).
05 OLD-AMOUNT PIC S9(5)V99 COMP-3.
05 OLD-STATUS PIC 9. *> 1=Active 2=Inactive
New format:
01 NEW-RECORD.
05 NEW-DATE PIC 9(8). *> YYYYMMDD
05 NEW-NAME PIC X(30).
05 NEW-AMOUNT PIC S9(9)V99.
05 NEW-STATUS PIC X(8). *> "ACTIVE"/"INACTIVE"
Hint: Handle the Y2K date conversion (YY 00-49 = 20xx, YY 50-99 = 19xx), pad the name field, convert packed decimal, and translate status codes.
Exercise 21: Incremental Refactoring Plan
Given a 5,000-line COBOL program with 80 GO TO statements and 15 paragraphs, create a step-by-step refactoring plan. Each step should be a single, testable change. Order the steps from least risky to most risky.
Hint: Start with changes that have no behavioral impact (adding condition names, adding END-IF terminators), then progress to GO TO elimination starting with the simplest patterns (forward branches to exit paragraphs).
Tier 4: Analyze (Exercises 22-27)
These exercises require evaluating strategies, making trade-off decisions, and analyzing complex scenarios.
Exercise 22: Modernization Strategy Selection
A 40-year-old insurance claims processing system has these characteristics: - 2.1 million lines of COBOL across 340 programs - Processes $8 billion in claims annually - 3 developers remaining (average age 58) - 47% of programs have no documentation - Regulatory requirements change 3-4 times per year - Average time to implement a regulatory change: 14 weeks
Evaluate each modernization strategy (rehost, replatform, refactor, rearchitect, replace, retain) and recommend an approach. Justify your choice with specific arguments.
Hint: Consider the constraints: business risk, available expertise, regulatory agility, timeline, and budget.
Exercise 23: Strangler Fig Implementation Plan
Design a Strangler Fig implementation plan for converting a COBOL-based order processing system to microservices. The system has four major subsystems: 1. Order entry (online, CICS-based) 2. Inventory check (batch + online) 3. Pricing/discount calculation (online) 4. Shipping/fulfillment (batch)
For each subsystem, determine: the order of migration, the coexistence strategy during transition, the routing mechanism between old and new, and the risk mitigation approach.
Hint: Start with the subsystem that has the most change requests and the cleanest interface boundaries.
Exercise 24: Refactoring Risk Assessment
A developer proposes refactoring a 3,000-line paragraph into 20 smaller paragraphs. The program processes payroll for 45,000 employees and runs weekly. Assess the risks of this refactoring and propose a testing strategy to mitigate them.
Hint: Consider data flow through the paragraph, shared variables, the impact of PERFORM vs. inline execution on the program's state, and regression testing requirements.
Exercise 25: Legacy vs. Modern Architecture Comparison
Compare a traditional COBOL batch architecture with a modern event-driven architecture for the same business process: end-of-day account reconciliation.
Analyze: processing model, error handling, recovery approach, scalability, and operational monitoring.
Hint: The batch approach reads all transactions sequentially and produces a reconciliation report. The event-driven approach processes each transaction as it occurs and maintains running reconciliation state.
Exercise 26: Knowledge Preservation Strategy
An organization has 5 COBOL developers maintaining 500 programs. Two developers are retiring in 12 months. Design a knowledge preservation strategy that captures the critical business logic and system knowledge before they leave.
Hint: Consider code archaeology (reading code to extract rules), developer interviews, automated documentation tools, and hands-on mentoring.
Exercise 27: Cost-Benefit Analysis of Modernization
Calculate the 5-year total cost of ownership for three scenarios for a COBOL claims system: 1. Maintain as-is on mainframe ($X/year maintenance + $Y/year infrastructure). 2. Refactor COBOL and wrap with APIs ($Z upfront + reduced maintenance). 3. Replace with COTS package ($W upfront + licensing + customization).
Given: Current annual maintenance = $2.5M, infrastructure = $1.8M, regulatory changes = 4/year at $150K each. Use reasonable assumptions for the other scenarios.
Hint: Include hidden costs: staff turnover, recruitment difficulty for COBOL skills, training costs, and risk of implementation failure.
Tier 5: Create (Exercises 28-32)
These exercises require performing substantial modernization work.
Exercise 28: Complete Program Refactoring
Take the following 200-line legacy program and refactor it completely: eliminate all GO TOs, extract paragraphs, add 88-levels, replace magic numbers, and add proper error handling. The refactored program must produce identical output.
IDENTIFICATION DIVISION.
PROGRAM-ID. LEGYPRG1.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INFILE ASSIGN TO "INPUT.DAT"
ORGANIZATION IS SEQUENTIAL.
SELECT OUTFILE ASSIGN TO "OUTPUT.DAT"
ORGANIZATION IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD INFILE.
01 INREC PIC X(80).
FD OUTFILE.
01 OUTREC PIC X(132).
WORKING-STORAGE SECTION.
01 WR.
05 T PIC X(1).
05 C PIC 9(3).
05 N PIC X(20).
05 A PIC 9(7)V99.
05 S PIC X(1).
01 E PIC X VALUE "N".
01 TC PIC 9(5) VALUE 0.
01 TA PIC 9(9)V99 VALUE 0.
01 EC PIC 9(5) VALUE 0.
01 LC PIC 9(3) VALUE 0.
01 PC PIC 9(3) VALUE 0.
01 OL PIC X(132) VALUE SPACES.
PROCEDURE DIVISION.
S. OPEN INPUT INFILE OUTPUT OUTFILE.
R. READ INFILE INTO WR AT END MOVE "Y" TO E.
IF E = "Y" GO TO D.
IF T = "H" GO TO H.
IF T = "D" GO TO P.
IF T = "T" GO TO V.
GO TO R.
H. ADD 1 TO PC.
MOVE SPACES TO OL.
STRING "PAGE " PC DELIMITED SIZE INTO OL.
WRITE OUTREC FROM OL AFTER PAGE.
MOVE 0 TO LC.
GO TO R.
P. IF S NOT = "A" AND NOT = "P" GO TO R.
ADD 1 TO TC. ADD A TO TA. ADD 1 TO LC.
IF LC > 55 GO TO H.
MOVE SPACES TO OL.
STRING C " " N " " A " " S
DELIMITED SIZE INTO OL.
WRITE OUTREC FROM OL.
GO TO R.
V. IF TA NOT = A
ADD 1 TO EC
MOVE SPACES TO OL
STRING "*** TOTAL MISMATCH: " TA " vs " A
DELIMITED SIZE INTO OL
WRITE OUTREC FROM OL.
GO TO R.
D. MOVE SPACES TO OL.
STRING "RECORDS: " TC " TOTAL: " TA " ERRORS: " EC
DELIMITED SIZE INTO OL.
WRITE OUTREC FROM OL.
CLOSE INFILE OUTFILE. STOP RUN.
Hint: First understand what it does, then rename variables, then restructure the control flow.
Exercise 29: API Wrapper with Error Translation
Design and implement a comprehensive API wrapper that exposes three legacy COBOL programs (customer inquiry, account update, transaction posting) through a single modern interface. The wrapper should: - Accept a well-structured request through the LINKAGE SECTION. - Dispatch to the appropriate legacy program. - Translate legacy error codes to modern error structures. - Log all interactions for audit. - Handle legacy program failures gracefully.
Hint: Use an EVALUATE-based dispatcher. Define a comprehensive error code mapping table.
Exercise 30: Data Migration Utility
Write a complete data migration utility that converts a VSAM KSDS file from legacy format to modern format. The utility should: - Read the legacy VSAM file. - Apply data transformations (date expansion, field widening, code translation). - Validate each record against business rules. - Write valid records to the new file. - Write rejected records to an error file with reason codes. - Produce a migration summary report.
Hint: Define transformation rules in a table for maintainability.
Exercise 31: Automated Documentation Generator
Write a COBOL program that reads a COBOL source file as input and produces a documentation report listing: - All paragraph names with their line numbers. - All COPY statements and the copybooks referenced. - All CALL statements and the programs called. - All file names and their access modes. - All GO TO statements and their targets. - A summary of code metrics (total lines, comment lines, blank lines, paragraphs, GO TOs).
Hint: Read the source file line by line, parse each line for keywords, and accumulate statistics.
Exercise 32: Modernization Proof of Concept
Implement a proof-of-concept for modernizing a batch COBOL report program into a near-real-time service: 1. The original batch program reads a sequential file and produces a formatted report. 2. The modernized version wraps the core business logic in a callable module. 3. A new driver program invokes the module for individual records passed through the LINKAGE SECTION. 4. The module returns formatted output suitable for JSON conversion.
Write all three components: the original batch program, the extracted business logic module, and the new service driver.
Hint: The key challenge is separating the business logic (which should be preserved) from the I/O and control flow (which changes between batch and service modes).
General Guidelines
- When refactoring, always verify that the external behavior remains identical.
- Test refactored code with the same inputs as the original and compare outputs.
- Document the purpose of each change so future maintainers understand the rationale.
- Prefer small, incremental changes over large restructurings.
- Always maintain a working version of the program that can be deployed at any point during the refactoring process.