Chapter 39 Quiz: Legacy System Maintenance and Modernization

Test your understanding of reading legacy COBOL code, refactoring techniques, GO TO elimination, modernization strategies, the strangler fig pattern, and data modernization. Each question has one correct answer unless otherwise stated. Try to answer each question before revealing the answer.


Multiple Choice

Question 1

What is the primary risk of a "big bang" replacement strategy for legacy COBOL systems?

A) The new system will be slower than the old one B) The replacement project may fail to deliver, leaving the organization without a working system during the transition C) COBOL developers will lose their jobs D) The hardware costs will increase

Show Answer **B) The replacement project may fail to deliver, leaving the organization without a working system during the transition** Big bang replacements are high-risk because they require the entire new system to be built and working before cutover. During the multi-year development period, the old system must continue operating, and any changes to it must be replicated in the new system. Industry statistics show that large-scale replacement projects have failure rates above 50%. The Strangler Fig pattern mitigates this by replacing incrementally.

Question 2

Which modernization strategy involves wrapping existing COBOL programs with modern interfaces (like REST APIs) without changing the COBOL code?

A) Replatform B) Refactor C) Encapsulate (Retain and Wrap) D) Rearchitect

Show Answer **C) Encapsulate (Retain and Wrap)** Encapsulation preserves the existing COBOL code and wraps it with modern interfaces such as REST APIs, message queues, or web services. The COBOL program continues running unchanged; a facade layer translates between modern request/response formats and the legacy program's COMMAREA or file-based interfaces. This is the lowest-risk modernization strategy.

Question 3

What is the first step when refactoring a GO TO-based backward branch (loop) into structured code?

A) Delete the GO TO statement B) Identify the loop boundaries -- where the loop starts and where the GO TO jumps back to C) Convert the code to object-oriented COBOL D) Add PERFORM VARYING around the entire paragraph

Show Answer **B) Identify the loop boundaries -- where the loop starts and where the GO TO jumps back to** Before restructuring, you must understand the control flow. Identify the target of the backward GO TO (the loop start), the condition that exits the loop (usually a GO TO to a paragraph after the loop, or an AT END clause), and all the code between them (the loop body). Only then can you create the correct PERFORM UNTIL structure.

Question 4

What is a "code smell" in the context of legacy COBOL maintenance?

A) A syntax error that prevents compilation B) A pattern in the code that suggests a deeper design problem, even though the code works correctly C) An error message produced by the runtime D) A performance bottleneck in a critical section

Show Answer **B) A pattern in the code that suggests a deeper design problem, even though the code works correctly** Code smells are indicators of maintainability problems. The code compiles and produces correct results, but its structure makes it difficult to understand, modify, or test. Examples include excessively long paragraphs, magic numbers, duplicated code, excessive GO TOs, and single-letter variable names. Code smells signal that refactoring would improve the code's quality.

Question 5

In the Strangler Fig pattern, what does the "routing" component do?

A) Determines which mainframe LPAR to use B) Directs each request to either the legacy system or the new system based on which functionality has been migrated C) Routes error messages to the appropriate support team D) Manages network traffic between data centers

Show Answer **B) Directs each request to either the legacy system or the new system based on which functionality has been migrated** The routing component (sometimes called the facade or dispatcher) sits in front of both systems. When a request comes in, it checks whether the corresponding functionality has been migrated to the new system. If yes, it routes to the new system. If not, it routes to the legacy system. As more functionality is migrated, more traffic flows to the new system until the legacy system is fully retired.

Question 6

Which refactoring technique replaces magic numbers like IF WS-CODE = 47 with readable condition names?

A) Adding 88-level condition names to the data definition B) Using EVALUATE instead of IF C) Creating a lookup table D) Using COPY REPLACING

Show Answer **A) Adding 88-level condition names to the data definition** 88-level condition names assign meaningful names to specific values. Instead of `IF WS-CODE = 47`, you define `88 CODE-PREMIUM-OVERRIDE VALUE 47` and write `IF CODE-PREMIUM-OVERRIDE`. This makes the code self-documenting and eliminates the need to look up what "47" means every time you encounter it.

Question 7

What is "dead code" in a legacy COBOL program?

A) Code that has been commented out B) Code that exists in the source but can never be executed during any program run C) Code that processes records marked for deletion D) Code that was written by a developer who has left the company

Show Answer **B) Code that exists in the source but can never be executed during any program run** Dead code includes paragraphs that are never PERFORMed or GO TO'd, variables that are defined but never referenced, conditions that can never be true (e.g., `IF 1 = 0`), and code after an unconditional STOP RUN or GO TO. Dead code clutters the program, confuses maintainers, and may trigger false positives in security scans and code reviews.

Question 8

When migrating VSAM KSDS data to DB2, which COBOL file operation maps most directly to an SQL SELECT?

A) OPEN B) READ with RIDFLD C) WRITE D) START

Show Answer **B) READ with RIDFLD** A keyed READ against a VSAM KSDS file using RIDFLD (Record Identification Field) is functionally equivalent to an SQL SELECT with a WHERE clause on the primary key. Both retrieve a specific record by its key value. OPEN maps to connecting/cursor declaration, WRITE maps to INSERT, and START maps to a cursor positioning or range query.

Question 9

What is the primary purpose of the PERFORM THRU statement in legacy COBOL?

A) To execute multiple paragraphs sequentially as a single unit B) To improve performance by reducing the number of PERFORM calls C) To enable polymorphism in procedural COBOL D) To create a transaction boundary

Show Answer **A) To execute multiple paragraphs sequentially as a single unit** PERFORM THRU executes all paragraphs from the first named paragraph through the last named paragraph, in sequence. It was commonly used with an EXIT paragraph at the end, allowing GO TO to jump to the exit point for early termination. Modern COBOL style avoids PERFORM THRU in favor of individual PERFORM calls and structured IF/ELSE for flow control.

Question 10

Which modernization approach carries the LEAST risk to ongoing business operations?

A) Complete rewrite in Java B) Incremental refactoring of existing COBOL code C) Big-bang replacement with a COTS package D) Converting COBOL to C# using an automated tool

Show Answer **B) Incremental refactoring of existing COBOL code** Incremental refactoring changes the code in small, testable steps. Each step preserves the external behavior while improving the internal structure. The program remains deployable after every change. If a problem is discovered, the last change can be easily reverted. All other options involve large, discontinuous changes that risk disrupting business operations.

Question 11

What is a "windowing" technique in the context of Y2K-era date handling?

A) Displaying dates in a scrollable window on the screen B) Interpreting 2-digit years using a pivot year (e.g., 00-49 = 2000-2049, 50-99 = 1950-1999) without changing the data format C) Converting all dates to Julian format D) Using the COBOL FUNCTION CURRENT-DATE instead of stored dates

Show Answer **B) Interpreting 2-digit years using a pivot year (e.g., 00-49 = 2000-2049, 50-99 = 1950-1999) without changing the data format** Windowing was a common Y2K mitigation technique that avoided changing data file layouts. The 2-digit year was left in the data, but comparison and calculation logic was modified to interpret values relative to a pivot year. This was faster and cheaper than full date expansion but created a deferred problem -- the pivot window eventually needs to be adjusted or replaced with 4-digit years.

Question 12

When extracting a large paragraph into smaller paragraphs during refactoring, what is the most important thing to verify?

A) That the new paragraph names follow naming conventions B) That all data dependencies (shared working-storage variables) are correctly handled and the refactored code produces identical results C) That the total line count decreases D) That the number of PERFORM statements is minimized

Show Answer **B) That all data dependencies (shared working-storage variables) are correctly handled and the refactored code produces identical results** When code is extracted into a new paragraph, any variables it reads or modifies must be accessible in the new context. In COBOL, WORKING-STORAGE variables are globally accessible within the program, so this is usually not a problem. However, the execution order and conditional logic must be preserved exactly. The refactored code must produce bit-for-bit identical output for all inputs.

Question 13

What is the "80/20 rule" as applied to legacy COBOL modernization?

A) 80% of COBOL programs should be rewritten and 20% should be retained B) 80% of maintenance effort is typically spent on 20% of the programs, so focus modernization on those high-maintenance programs first C) 80% of the budget should go to modernization and 20% to maintenance D) 80% of the code is boilerplate and only 20% contains business logic

Show Answer **B) 80% of maintenance effort is typically spent on 20% of the programs, so focus modernization on those high-maintenance programs first** The Pareto principle applies to legacy systems: a small number of programs generate most of the maintenance burden. Identifying these high-maintenance programs and prioritizing them for modernization yields the greatest return on investment. Attempting to modernize all programs equally wastes resources on stable, rarely-changed code that works well as-is.

True/False

Question 14

True or False: All GO TO statements in a COBOL program should be eliminated during refactoring.

Show Answer **False** While most GO TO statements should be eliminated through structured programming techniques, some contexts make GO TO acceptable or even necessary in COBOL. Specifically, GO TO within a PERFORM THRU range to jump to the EXIT paragraph is a recognized pattern (though it should be replaced with IF/ELSE when practical). Additionally, GO TO in an error-handling paragraph to a common error exit may be acceptable if the alternative would create deeply nested IF structures. The goal is readable, maintainable code -- not zero GO TOs at the expense of clarity.

Question 15

True or False: The Strangler Fig pattern requires both the old and new systems to run simultaneously during the migration period.

Show Answer **True** The Strangler Fig pattern inherently requires coexistence of old and new systems. A routing layer directs each request to either the legacy or the modern system based on which functionality has been migrated. Both systems must be operational, and data consistency between them must be maintained. This coexistence period continues until all functionality has been migrated and the legacy system can be decommissioned.

Question 16

True or False: Refactoring should change both the internal structure and the external behavior of a program simultaneously.

Show Answer **False** Refactoring, by definition, changes the internal structure of code **without changing its external behavior**. The outputs for all valid inputs must remain identical before and after refactoring. If you need to change behavior (fix a bug, add a feature), that should be a separate change from refactoring. Mixing structural changes with behavioral changes makes it impossible to verify that the refactoring did not introduce bugs.

Question 17

True or False: Legacy COBOL programs that are stable and rarely modified should generally be left as-is rather than modernized.

Show Answer **True** If a legacy program is stable, performs its function correctly, and rarely needs modification, the risk and cost of modernizing it typically outweigh the benefits. The principle of "if it isn't broken, don't fix it" applies strongly to business-critical legacy systems. Modernization effort should be focused on programs that are frequently modified, difficult to maintain, or need to support new requirements. Stable programs can be encapsulated (wrapped with APIs) if external access is needed.

Question 18

True or False: Automated COBOL-to-Java conversion tools produce code that is as maintainable as hand-written Java.

Show Answer **False** Automated conversion tools typically produce Java code that mirrors the COBOL program's structure: sequential logic, global variables (translated to class fields), and COBOL idioms expressed in Java syntax. The resulting Java code is often more difficult to maintain than the original COBOL because it does not follow Java conventions, design patterns, or object-oriented principles. It is sometimes described as "COBOL written in Java." Manual rearchitecting is needed to produce truly maintainable Java code, which requires deep understanding of the business logic.

Question 19

True or False: PERFORM THRU can always be safely replaced with a single PERFORM of the first paragraph.

Show Answer **False** PERFORM THRU executes all paragraphs from the first named paragraph through the last. If the range includes multiple paragraphs with sequential logic, replacing PERFORM THRU with PERFORM of just the first paragraph would skip the intermediate paragraphs. The replacement must either: (a) merge all the paragraphs in the range into one, or (b) have the first paragraph PERFORM each subsequent paragraph explicitly, or (c) restructure the logic so the intermediate paragraphs are not needed.

Question 20

True or False: Data modernization (changing file formats, expanding fields) is typically riskier than code modernization (refactoring logic).

Show Answer **True** Data modernization affects every program that reads or writes the data, not just the program being modernized. Changing a VSAM record layout, for example, may require coordinated changes across dozens of programs, JCL procedures, sort control cards, and downstream systems. The data must be migrated without loss, and all programs must switch to the new format simultaneously. Code refactoring, by contrast, can be done one program at a time with no impact on other programs or data.

Question 21

True or False: The best time to add unit tests to a legacy COBOL program is before refactoring it.

Show Answer **True** Adding tests before refactoring creates a safety net. The tests capture the program's current behavior (whether correct or not). As refactoring changes are made, the tests are run after each change to verify that the external behavior has not changed. Without pre-existing tests, there is no reliable way to confirm that refactoring did not introduce regressions. This is called "characterization testing" -- the tests characterize what the program actually does.

Code Analysis

Question 22

Analyze the following code and identify all the GO TO patterns present. For each, describe how to eliminate it:

       1000-PROCESS.
           READ INPUT-FILE AT END GO TO 1000-EXIT.
           IF REC-TYPE = "A"
               PERFORM 2000-TYPE-A
               GO TO 1000-PROCESS
           END-IF.
           IF REC-TYPE = "B"
               PERFORM 3000-TYPE-B
               GO TO 1000-PROCESS
           END-IF.
           DISPLAY "UNKNOWN TYPE: " REC-TYPE.
           GO TO 1000-PROCESS.
       1000-EXIT.
           EXIT.
Show Answer Three GO TO patterns are present: 1. **Forward branch (exit)**: `GO TO 1000-EXIT` on AT END. Eliminate by using a flag: `AT END MOVE "Y" TO WS-EOF-FLAG`. 2. **Backward branch (loop)**: Three `GO TO 1000-PROCESS` statements create a read loop. Eliminate by wrapping in `PERFORM 1000-PROCESS UNTIL WS-EOF-FLAG = "Y"`. 3. **Cascading IF with GO TO (dispatch)**: The IF/GO TO chain dispatches based on REC-TYPE. Eliminate with EVALUATE. Refactored:
       1000-PROCESS.
           READ INPUT-FILE
               AT END MOVE "Y" TO WS-EOF-FLAG
               NOT AT END
                   EVALUATE REC-TYPE
                       WHEN "A"
                           PERFORM 2000-TYPE-A
                       WHEN "B"
                           PERFORM 3000-TYPE-B
                       WHEN OTHER
                           DISPLAY "UNKNOWN TYPE: " REC-TYPE
                   END-EVALUATE
           END-READ
           .
Called as: `PERFORM 1000-PROCESS UNTIL WS-EOF-FLAG = "Y"`.

Question 23

What is wrong with this refactoring attempt?

Original:

       5000-CALC.
           MOVE 0 TO WS-TOTAL.
           PERFORM 5100-ADD-ITEM THRU 5100-ADD-ITEM-EXIT
               VARYING WS-IDX FROM 1 BY 1
               UNTIL WS-IDX > WS-COUNT.

       5100-ADD-ITEM.
           IF WS-ITEM-AMT(WS-IDX) < 0
               GO TO 5100-ADD-ITEM-EXIT.
           ADD WS-ITEM-AMT(WS-IDX) TO WS-TOTAL.
       5100-ADD-ITEM-EXIT.
           EXIT.

Attempted refactoring:

       5000-CALC.
           MOVE 0 TO WS-TOTAL.
           PERFORM VARYING WS-IDX FROM 1 BY 1
               UNTIL WS-IDX > WS-COUNT
               IF WS-ITEM-AMT(WS-IDX) >= 0
                   ADD WS-ITEM-AMT(WS-IDX) TO WS-TOTAL
               END-IF
           END-PERFORM.
Show Answer The refactoring attempt has a **syntax error**. In COBOL, `PERFORM VARYING ... END-PERFORM` (inline PERFORM) cannot contain an IF statement directly inside the PERFORM/END-PERFORM block in this way in standard COBOL. The inline body of a PERFORM is limited to imperative statements. The correct refactoring should use a separate paragraph:
       5000-CALC.
           MOVE 0 TO WS-TOTAL
           PERFORM 5100-ADD-ITEM
               VARYING WS-IDX FROM 1 BY 1
               UNTIL WS-IDX > WS-COUNT
           .

       5100-ADD-ITEM.
           IF WS-ITEM-AMT(WS-IDX) >= 0
               ADD WS-ITEM-AMT(WS-IDX) TO WS-TOTAL
           END-IF
           .
Note: Some modern COBOL compilers do allow IF inside inline PERFORM, but the out-of-line paragraph approach is universally portable and clearer. Actually, many modern COBOL compilers (Enterprise COBOL V4+, Micro Focus) do support inline PERFORM with conditional statements. The real issue with the attempted refactoring is that the logic is actually correct but the coder forgot the period/full stop after END-PERFORM. The refactored version is functionally equivalent to the original -- it correctly skips negative amounts.

Question 24

A legacy program uses the following date handling. Identify the Y2K-related issue and propose both a windowing fix and a full expansion fix:

       01  WS-BIRTH-DATE.
           05  WS-BD-YY       PIC 9(2).
           05  WS-BD-MM       PIC 9(2).
           05  WS-BD-DD       PIC 9(2).

       01  WS-CURRENT-DATE.
           05  WS-CD-YY       PIC 9(2).
           05  WS-CD-MM       PIC 9(2).
           05  WS-CD-DD       PIC 9(2).

           COMPUTE WS-AGE = WS-CD-YY - WS-BD-YY.
Show Answer **The issue**: A person born in 1985 (WS-BD-YY = 85) with a current year of 2025 (WS-CD-YY = 25) produces WS-AGE = 25 - 85 = -60. The 2-digit year cannot represent centuries, so cross-century calculations produce incorrect (and possibly negative) results. **Windowing fix** (minimal data change):
       01  WS-FULL-BIRTH-YEAR PIC 9(4).
       01  WS-FULL-CURR-YEAR  PIC 9(4).

           IF WS-BD-YY > 49
               COMPUTE WS-FULL-BIRTH-YEAR = 1900 + WS-BD-YY
           ELSE
               COMPUTE WS-FULL-BIRTH-YEAR = 2000 + WS-BD-YY
           END-IF

           MOVE FUNCTION CURRENT-DATE(1:4)
               TO WS-FULL-CURR-YEAR

           COMPUTE WS-AGE =
               WS-FULL-CURR-YEAR - WS-FULL-BIRTH-YEAR
**Full expansion fix** (data format change):
       01  WS-BIRTH-DATE.
           05  WS-BD-YYYY    PIC 9(4).
           05  WS-BD-MM      PIC 9(2).
           05  WS-BD-DD      PIC 9(2).

       01  WS-CURRENT-DATE   PIC 9(8).

           MOVE FUNCTION CURRENT-DATE(1:8)
               TO WS-CURRENT-DATE
           COMPUTE WS-AGE =
               WS-CURRENT-DATE(1:4) - WS-BD-YYYY
The full expansion requires migrating all data files from 6-byte to 8-byte date fields and changing all programs that reference the date structure.

Question 25

Review this legacy code and explain the business rule it implements. Then rewrite it using modern COBOL style:

       3000-FEE.
           MOVE 0 TO F.
           IF B < 1000 MOVE 15 TO F GO TO 3000-X.
           IF B < 5000 MOVE 10 TO F GO TO 3000-X.
           IF B < 25000 MOVE 5 TO F GO TO 3000-X.
           IF Y > 5 MOVE 0 TO F GO TO 3000-X.
           MOVE 3 TO F.
       3000-X. EXIT.
Show Answer **Business rule**: Monthly fee (F) is based on account balance (B) with a loyalty override for tenure (Y = years): - Balance under $1,000: fee is $15 - Balance $1,000-$4,999: fee is $10 - Balance $5,000-$24,999: fee is $5 - Balance $25,000 or above AND account tenure over 5 years: fee is $0 (waived) - Balance $25,000 or above AND tenure 5 years or less: fee is $3 **Modern rewrite:**
       3000-CALCULATE-MONTHLY-FEE.
           EVALUATE TRUE
               WHEN WS-BALANCE < 1000
                   MOVE 15 TO WS-MONTHLY-FEE
               WHEN WS-BALANCE < 5000
                   MOVE 10 TO WS-MONTHLY-FEE
               WHEN WS-BALANCE < 25000
                   MOVE 5 TO WS-MONTHLY-FEE
               WHEN WS-YEARS-AS-CUSTOMER > 5
                   MOVE 0 TO WS-MONTHLY-FEE
               WHEN OTHER
                   MOVE 3 TO WS-MONTHLY-FEE
           END-EVALUATE
           .

Question 26

Identify all the modernization opportunities in this program fragment:

       WORKING-STORAGE SECTION.
       01 A PIC X(80).
       01 B PIC X(80).
       01 C PIC 9(6).
       01 D PIC 9(5)V99.
       01 E PIC 9(5)V99.
       01 F PIC X VALUE "N".
       01 G PIC 9(5) VALUE 0.
       01 H PIC 9(3)V99 VALUE 7.25.

           OPEN INPUT INFILE.
       LP. READ INFILE INTO A AT END MOVE "Y" TO F.
           IF F = "Y" GO TO EN.
           MOVE A(1:6) TO C.
           MOVE A(10:7) TO D.
           IF D > 50000 COMPUTE E = D * H / 100
           ELSE MOVE 0 TO E.
           ADD 1 TO G.
           ADD D TO B.
           DISPLAY G C D E.
           GO TO LP.
       EN. CLOSE INFILE. DISPLAY G B. STOP RUN.
Show Answer Modernization opportunities: 1. **Variable naming**: All single-letter names (A through H) should be replaced with descriptive names (e.g., A=WS-INPUT-RECORD, B=WS-TOTAL-AMOUNT, C=WS-EMPLOYEE-ID, D=WS-SALARY, E=WS-TAX, F=WS-EOF-FLAG, G=WS-RECORD-COUNT, H=WS-TAX-RATE). 2. **GO TO loop elimination**: The `GO TO LP` backward branch should become `PERFORM LP UNTIL WS-EOF-FLAG = "Y"`. 3. **GO TO exit elimination**: The `GO TO EN` forward branch is eliminated when the loop becomes a PERFORM UNTIL. 4. **88-level condition names**: Add `88 END-OF-FILE VALUE "Y"` and `88 NOT-END-OF-FILE VALUE "N"`. 5. **Magic number elimination**: The value 50000 should be a named constant (`01 WS-HIGH-SALARY-THRESHOLD PIC 9(5) VALUE 50000`). The tax rate 7.25 should have a descriptive name. 6. **Substring extraction**: `A(1:6)` and `A(10:7)` should use a proper record layout with named fields instead of positional reference modifiers. 7. **Missing END-IF**: The IF/ELSE lacks END-IF terminators. 8. **File record layout**: The FD should define the record structure rather than using substring extraction. 9. **Error handling**: No AT END/NOT AT END structure, no file status checking. 10. **Variable B misused**: B is declared as PIC X(80) but used as an accumulator with ADD -- this will cause a data exception at runtime. It should be PIC 9(9)V99.

Question 27

A team is considering three approaches to modernize a 30-year-old COBOL claims processing system. Evaluate the pros and cons of each:

Approach A: Convert all COBOL to Java using an automated translation tool. Approach B: Keep COBOL on mainframe, expose via REST APIs using z/OS Connect. Approach C: Rewrite core modules in Java, keep peripheral modules in COBOL, with MQ integration between them.

Show Answer **Approach A -- Automated COBOL-to-Java conversion:** - Pros: Fast initial conversion; all code on a single platform; reduced mainframe costs. - Cons: Produces unmaintainable "COBOL in Java"; does not improve code quality; Java developers cannot maintain it without COBOL knowledge; testing burden is enormous (every line changed); performance characteristics change unpredictably; regulatory risk if translated code behaves differently. **Approach B -- Keep COBOL, expose via APIs:** - Pros: Lowest risk (existing code unchanged); fastest time to value; COBOL performance retained; proven business logic preserved; incremental approach. - Cons: Mainframe costs continue; still dependent on COBOL skills; does not address code quality issues; limited by legacy architecture for new features. **Approach C -- Hybrid rewrite with MQ integration:** - Pros: Most critical/complex modules get true modernization; less risky than full rewrite; allows best technology for each component; MQ provides reliable async communication. - Cons: Two technology stacks to maintain; data consistency between systems is complex; requires both COBOL and Java expertise; integration points add latency and failure modes; longer project timeline. **Recommendation**: Start with Approach B (quick wins, low risk), then selectively apply Approach C to modules that need true modernization (frequent changes, new features needed). Avoid Approach A entirely.

Scoring Guide

Score Level
24-27 Expert -- You can lead legacy modernization projects
19-23 Proficient -- Strong understanding of modernization strategies
14-18 Intermediate -- Good foundation, review refactoring techniques
9-13 Developing -- Focus on GO TO elimination and code analysis
Below 9 Beginning -- Revisit the chapter material before proceeding