Site logo
Tác giả
  • avatar Nguyễn Đức Xinh
    Name
    Nguyễn Đức Xinh
    Twitter
Ngày xuất bản
Ngày xuất bản

Cấu trúc điều kiện trong COBOL – IF, EVALUATE và best practice cho backend dev

Vì sao phải hiểu rõ điều kiện trong COBOL?

Trong mọi ngôn ngữ lập trình, rẽ nhánh điều kiện (conditional) là trung tâm của business logic. Với COBOL – đặc biệt trong hệ thống banking/enterprise – điều kiện lại càng quan trọng hơn vì:

  • Business rule thường dài, nhiều nhánh, dễ sai nếu code IF lồng nhau quá phức tạp
  • Cần đọc/maintain chương trình cũ hàng chục ngàn dòng, sử dụng cả IFEVALUATE
  • Error handling, logging, mapping status → message đều dùng condition

Ở bài 004, bạn đã nắm toán tử và biểu thức, bài này tập trung vào:

  • Cú pháp và cách dùng IF ... ELSE ... END-IF. trong COBOL
  • EVALUATE – tương đương switch-case trong ngôn ngữ hiện đại
  • Kết hợp điều kiện với AND, OR, NOT
  • Best practice để code điều kiện đọc được, tránh "IF hell"
  • Liên hệ trực tiếp với code enterprise trong [course/cobol/sections/code-example/RZZBSQLN1.PCO](course/cobol/sections/code-example/RZZBSQLN1.PCO)

IF, ELSE, END-IF trong COBOL

Cú pháp cơ bản

IF condition
    statement-1
END-IF.

Với ELSE:

IF condition
    statement-1
ELSE
    statement-2
END-IF.

So với Java/Python:

  • IF ~ if
  • ELSE ~ else
  • END-IF. ~ dấu {} đóng block

Ví dụ đơn giản: kiểm tra tuổi

       01 WS-AGE     PIC 99.

       PROCEDURE DIVISION.
           MOVE 20 TO WS-AGE.

           IF WS-AGE >= 18
               DISPLAY "Adult"
           ELSE
               DISPLAY "Minor"
           END-IF.

           STOP RUN.

Ví dụ trong enterprise: check file status

Trong RZZBSQLN1.PCO có đoạn:

INP1-OPEN-RTN.
    MOVE  "INP1-OPEN-RTN"       TO    DSP_PROC.
    OPEN INPUT INP1FILE.
    IF F_STS  NOT = "00"
        MOVE  "FILE :"          TO    DSP_MSG
        MOVE  INP1_FILE         TO    DSP_MSGNAIYO
        MOVE  "No.004"          TO    DSP_MSGCD
        ...
        PERFORM IO-ERROR        THRU  IO-ERROR-EXT
        GO TO STOP-PGM
    END-IF.
INP1-OPEN-EXT.
    EXIT.

Giải nghĩa theo mindset backend dev:

open INP1FILE
if (fSts != "00") {
    // fill error message
    ioError()
    goto stopPgm
}

Pattern này lặp lại trong nhiều routine:

  • Check file open/close/read
  • Nếu error → set message → PERFORM IO-ERRORGO TO STOP-PGM

Kết hợp điều kiện với AND, OR, NOT

COBOL dùng:

  • AND – cả hai điều kiện đều đúng
  • OR – một trong hai điều kiện đúng
  • NOT – phủ định

Ví dụ: kiểm tra nhiều điều kiện

       IF WS-AGE >= 18 AND WS-COUNTRY = "VN"
           DISPLAY "Adult in Vietnam"
       END-IF.

       IF NOT (F_STS = "00") OR ERR1_ERRCNT > 0
           DISPLAY "Has error"
       END-IF.

Trong RZZBSQLN1.PCO có pattern:

IF BCMO-1 = ZERO  OR
   BCMO-2 = SPACE
    GO TO CMD-GET-ERR
END-IF.

Mapping sang pseudo-code:

if (bcmo1 == 0 || bcmo2 == " ") {
    goto cmdGetErr
}

Best practice:

  • Khi AND/OR nhiều điều kiện, nên xuống dòng thẳng cột để dễ đọc
  • Nếu logic phức tạp, có thể tách thành biến flag trung gian (ví dụ WS-HAS-ERROR-FLAG)

Nested IF – Khi nào nên tránh?

IF lồng nhau quá sâu sẽ làm code khó đọc, đặc biệt trong COBOL, nơi block được kết thúc bằng END-IF. chứ không có {}.

Ví dụ xấu (minh họa):

IF A = 1
    IF B = 2
        IF C = 3
            ...
        END-IF
    END-IF
END-IF.

Cải thiện bằng cách:

  • Dùng AND: IF A = 1 AND B = 2 AND C = 3 (nếu phù hợp)
  • Hoặc dùng EVALUATE (switch-case) cho một số tình huống

Trong enterprise COBOL, thường thấy pattern early exit:

IF condition-error
    ... handle error ...
    GO TO STOP-PGM
END-IF.

* logic ok nằm phía dưới, không bị IF bao quanh

Đây là cách mà RZZBSQLN1 xử lý lỗi file và lỗi SQL.


EVALUATE – switch-case trong COBOL

EVALUATE là cấu trúc rẽ nhánh mạnh mẽ, tương đương switch-case trong Java/C:

EVALUATE expression
    WHEN value-1
        statements-1
    WHEN value-2
        statements-2
    WHEN OTHER
        statements-default
END-EVALUATE.

Ví dụ cơ bản: phân loại điểm

       01 WS-SCORE     PIC 9(3).

       PROCEDURE DIVISION.
           MOVE 85 TO WS-SCORE.

           EVALUATE TRUE
               WHEN WS-SCORE >= 90
                   DISPLAY "A"
               WHEN WS-SCORE >= 80
                   DISPLAY "B"
               WHEN WS-SCORE >= 70
                   DISPLAY "C"
               WHEN OTHER
                   DISPLAY "D"
           END-EVALUATE.

           STOP RUN.

Ở đây, trick hay là dùng EVALUATE TRUE để tạo ra cảm giác giống chuỗi if/else if/else.

Ví dụ thực tế trong RZZBSQLN1: đánh giá COMPLETION-CODE

Trong đoạn ENDDSP-RTN:

    EVALUATE COMPLETION-CODE
      WHEN 0
        MOVE  NC"�����͐���I�����܂����B"  TO  END_MSG41 
      WHEN 254
        MOVE  NC"�����͌x���I�����܂����B"  TO  END_MSG41 
      WHEN OTHER
        MOVE  NC"�����ُ͈�I�����܂����B"  TO  END_MSG41 
    END-EVALUATE.

Dịch nghĩa theo logic:

switch (completionCode) {
  case 0:
    message = "Kết thúc bình thường";
    break;
  case 254:
    message = "Kết thúc với cảnh báo";
    break;
  default:
    message = "Kết thúc bất thường";
}

Pattern này rất phổ biến trong batch:

  • Mapping completion code → message hiển thị cuối job
  • Mapping error code → text mô tả

EVALUATE nhiều expression (nâng cao)

COBOL còn cho phép EVALUATE nhiều expression một lúc:

EVALUATE A ALSO B
    WHEN 1 ALSO 1
        ...
    WHEN 1 ALSO 2
        ...
    WHEN OTHER
        ...
END-EVALUATE.

Tuy nhiên trong thực tế enterprise, rất nhiều code chỉ dùng EVALUATE một biểu thức hoặc EVALUATE TRUE.


So sánh IF vs EVALUATE – dùng khi nào?

Tình huống Nên dùng Lý do
Điều kiện đơn, 1–2 nhánh IF Ngắn gọn, dễ đọc
Chuỗi nhiều nhánh trên cùng 1 biến EVALUATE Giống switch-case, dễ maintain
Nhiều range (>=, <=) chồng nhau EVALUATE TRUE Thay cho nhiều IF/ELSE IF
Check error trước rồi exit IF (early exit) Rõ ràng, pattern phổ biến trong batch

Trong RZZBSQLN1:

  • Dùng IF cho các check đơn:
    • Check F_STS sau OPEN/READ/CLOSE
    • Check INP1_INPCNT > 0 trước khi EXEC SQL
  • Dùng EVALUATE để map COMPLETION-CODE → message

Ví dụ tổng hợp: luồng xử lý đơn giản với IF + EVALUATE

Giả sử ta viết một batch COBOL nhỏ:

  • Đọc tổng số record và số lỗi
  • Tính COMPLETION-CODE:
    • 0 nếu ERR-COUNT = 0
    • 254 nếu ERR-COUNT > 0 nhưng < 10
    • 255 nếu ERR-COUNT >= 10
  • In message cuối job dựa vào COMPLETION-CODE
       IDENTIFICATION DIVISION.
       PROGRAM-ID. JOB-END-DEMO.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 WS-REC-COUNT       PIC 9(6) VALUE ZERO.
       01 WS-ERR-COUNT       PIC 9(6) VALUE ZERO.
       01 COMPLETION-CODE    PIC 9(3) VALUE 0.
       01 WS-END-MESSAGE     PIC X(50).

       PROCEDURE DIVISION.

      * Giả lập kết quả xử lý
           MOVE  100 TO WS-REC-COUNT.
           MOVE  3   TO WS-ERR-COUNT.

      * Xác định COMPLETION-CODE
           IF WS-ERR-COUNT = 0
               MOVE 0   TO COMPLETION-CODE
           ELSE
               IF WS-ERR-COUNT < 10
                   MOVE 254 TO COMPLETION-CODE
               ELSE
                   MOVE 255 TO COMPLETION-CODE
               END-IF
           END-IF.

      * Map COMPLETION-CODE -> message
           EVALUATE COMPLETION-CODE
               WHEN 0
                   MOVE "JOB END NORMAL"      TO WS-END-MESSAGE
               WHEN 254
                   MOVE "JOB END WITH WARN"   TO WS-END-MESSAGE
               WHEN OTHER
                   MOVE "JOB END ABEND"       TO WS-END-MESSAGE
           END-EVALUATE.

           DISPLAY "REC= " WS-REC-COUNT.
           DISPLAY "ERR= " WS-ERR-COUNT.
           DISPLAY WS-END-MESSAGE.

           STOP RUN.

Đây chính là pattern mà RZZBSQLN1 áp dụng ở quy mô lớn hơn.


Bài tập thực hành

Bài 1 – Phân loại khách hàng theo số dư

Yêu cầu:

  • Khai báo: BALANCE PIC S9(7)V99, RANK PIC X(10)
  • Logic:
    • Nếu BALANCE < 0RANK = "DEBT"
    • Nếu BALANCE >= 0< 1000RANK = "NORMAL"
    • Nếu BALANCE >= 1000RANK = "VIP"
  • Viết bằng:
    • Version 1: chuỗi IF/ELSE IF
    • Version 2: dùng EVALUATE TRUE

Bài 2 – Map file status sang message

Giả sử có:

  • F-STS PIC X(02)

Quy ước:

  • "00" – OK
  • "10" – EOF (end of file)
  • "90" – Lỗi khác

Yêu cầu:

  • Viết EVALUATE F-STS để:
    • Hiển thị "OK" nếu "00"
    • Hiển thị "EOF" nếu "10"
    • Hiển thị "FILE ERROR" cho giá trị khác

Bài 3 – Early exit pattern cho batch

Viết đoạn code mô phỏng pattern trong RZZBSQLN1:

  • Sau khi OPEN INPUT FILE, nếu F-STS NOT = "00" thì:
    • Gán COMPLETION-CODE = 255
    • Hiển thị message lỗi
    • GO TO STOP-PGM
  • Ở label STOP-PGM., hiển thị "JOB END" cùng COMPLETION-CODESTOP RUN.

Bài 4 – Refactor IF lồng nhau sang EVALUATE TRUE

Cho code (giả sử):

IF SCORE >= 90
    MOVE "A" TO GRADE
ELSE
    IF SCORE >= 80
        MOVE "B" TO GRADE
    ELSE
        IF SCORE >= 70
            MOVE "C" TO GRADE
        ELSE
            MOVE "D" TO GRADE
        END-IF
    END-IF
END-IF.

Hãy viết lại bằng EVALUATE TRUE cho dễ đọc hơn.


Kết luận

Trong bài này, bạn đã:

  • Hiểu rõ cách dùng IF/ELSE/END-IF trong COBOL
  • Nắm được AND, OR, NOT để kết hợp điều kiện
  • Thấy sức mạnh của EVALUATE trong việc thay thế chuỗi if/else if dài
  • Nhìn được pattern điều kiện trong chương trình enterprise như RZZBSQLN1.PCO – từ check file status đến map completion code → message

Kết hợp với bài 004 (toán tử & biểu thức), bạn đã đủ khả năng đọc hầu hết logic rẽ nhánh và tính toán trong một chương trình COBOL thực tế.

Ở các bài tiếp theo, chúng ta sẽ đi sâu vào:

  • Vòng lặp & PERFORM (Loop & Control Flow) – cách tổ chức MAIN-RTN, INIT-RTN, FINISH-RTN giống batch program thật
  • FILE SECTION & FILE-CONTROL – chi tiết về đọc/ghi file text, pattern xử lý file trong enterprise mainframe.