CTS-KB
RPG 2 / 5

RPG モジュール設計

#RPG #IBM i #モジュール設計

対象: RPG IV(ILE RPG)/ フリーフォーマット
基本文法は RPG 文法基礎 を参照
COBOL版は COBOL モジュール設計 を参照


目次

  1. モジュール化の全体像
  2. サブルーチン(BEGSR / ENDSR)
  3. プロシージャ(dcl-proc)
  4. サービスプログラム(*SRVPGM)
  5. COPY / INCLUDE(コード共有)
  6. プロトタイプとインターフェース(dcl-pr / dcl-pi)
  7. バインディングディレクトリ
  8. コンパイルとリンク
  9. 設計パターン
  10. RPGとDDD的設計思想

1. モジュール化の全体像

RPGでコードを分割・再利用する方法は3段階ある。

小規模 ──────────────────────────────── 大規模

サブルーチン         プロシージャ          サービスプログラム
(BEGSR/ENDSR)       (dcl-proc)           (*SRVPGM)
1ファイル内          1モジュール内          複数モジュール結合
名前空間なし         ローカル変数あり       外部公開可能

COBOL対応:
SECTION/PARAGRAPH    NESTED PROGRAM        外部 CALL + LINKAGE

いつ何を使うか

規模手法
10行以下の共通処理サブルーチンエラーメッセージ表示、ログ出力
1モジュール内の機能分割プロシージャ税計算、日付変換、入力チェック
複数プログラムから共用サービスプログラム共通ライブラリ、マスタ検索API

2. サブルーチン(BEGSR / ENDSR)

最も古い・最も単純なモジュール化。COBOL の PERFORM 〜 SECTION に相当。

**free
ctl-opt dftactgrp(*no) actgrp(*caller);

dcl-s totalAmt packed(11:2);
dcl-s taxAmt   packed(11:2);
dcl-s taxRate  packed(5:4) inz(0.10);

// メイン処理
totalAmt = 10000;
exsr calcTax;
dsply ('Tax: ' + %char(taxAmt));
*inlr = *on;

// サブルーチン定義
begsr calcTax;
  taxAmt = totalAmt * taxRate;
endsr;

特徴と制限

  • グローバル変数のみ: サブルーチン内にローカル変数を持てない
  • 戻り値なし: 結果はグローバル変数経由で受け渡し
  • 再帰不可: 自分自身を呼べない
  • 名前空間なし: 同じプログラム内で名前が衝突する

→ 小規模な処理のまとめにのみ使用。複雑な処理にはプロシージャを使うべき。

COBOL との対比

COBOL:                              RPG:
PERFORM CALC-TAX                    exsr calcTax;

CALC-TAX SECTION.                   begsr calcTax;
  COMPUTE TAX = TOTAL * RATE          taxAmt = totalAmt * taxRate;
  .                                 endsr;

3. プロシージャ(dcl-proc)

ILE RPGのモダンなモジュール化手法。ローカル変数・戻り値・パラメータをサポート。COBOL の NESTED PROGRAM に相当。

**free
ctl-opt dftactgrp(*no) actgrp(*caller);

dcl-s result packed(11:2);

// メイン処理
result = calcTax(10000 : 0.10);
dsply ('Tax: ' + %char(result));
*inlr = *on;

// ──────────────────────────────────
// プロシージャ定義
// ──────────────────────────────────
dcl-proc calcTax;
  dcl-pi *n packed(11:2);    // 戻り値の型
    amount  packed(11:2) const;  // パラメータ1
    rate    packed(5:4)  const;  // パラメータ2
  end-pi;

  dcl-s tax packed(11:2);    // ローカル変数

  tax = amount * rate;
  return tax;
end-proc;

プロシージャのメリット

項目サブルーチンプロシージャ
ローカル変数×
戻り値×
パラメータ×
再帰呼出×
外部公開×○(EXPORT)
COBOLの対応SECTIONNESTED PROGRAM / 外部CALL

EXPORT(外部公開)

// 他のモジュールから呼べるプロシージャ
dcl-proc calcTax export;
  dcl-pi *n packed(11:2);
    amount  packed(11:2) const;
    rate    packed(5:4)  const;
  end-pi;

  return amount * rate;
end-proc;

4. サービスプログラム(*SRVPGM)

複数のプログラムから共通的に使うプロシージャをまとめたもの。COBOLの外部CALLに相当するが、より効率的(動的リンクではなくバインドリンク)。

構造:

ORDPGM.rpgle(受注プログラム)
  └─ callp calcTax(amount : rate)  ←─┐
                                       │ バインド
INVPGM.rpgle(在庫プログラム)         │
  └─ callp calcTax(amount : rate)  ←─┤

TAXSRV.rpgle(税計算サービス)─────────┘
  └─ dcl-proc calcTax export;

作成手順

// 1. サービスモジュールのコンパイル
CRTRPGMOD MODULE(MYLIB/TAXSRV) SRCFILE(MYLIB/QRPGSRC)

// 2. サービスプログラムの作成
CRTSRVPGM SRVPGM(MYLIB/TAXSRV) MODULE(MYLIB/TAXSRV) EXPORT(*ALL)

// 3. バインディングディレクトリに登録
ADDBNDDIRE BNDDIR(MYLIB/MYBND) OBJ((MYLIB/TAXSRV *SRVPGM))

// 4. 呼出元プログラムのコンパイル
CRTBNDRPG PGM(MYLIB/ORDPGM) SRCFILE(MYLIB/QRPGSRC) BNDDIR(MYLIB/MYBND)

5. COPY / INCLUDE(コード共有)

データ構造やプロトタイプの定義をファイル間で共有する。COBOLのCOPY句に相当。

/COPY(コピーブック)

// コピーブック: QRPGLESRC/TAXPR(税計算プロシージャのプロトタイプ)
dcl-pr calcTax packed(11:2);
  amount  packed(11:2) const;
  rate    packed(5:4)  const;
end-pr;
// 呼出元プログラム
**free
ctl-opt dftactgrp(*no) actgrp(*caller) bnddir('MYLIB/MYBND');

/copy MYLIB/QRPGLESRC,TAXPR    // プロトタイプを取り込む

dcl-s result packed(11:2);
result = calcTax(10000 : 0.10);
*inlr = *on;

COBOL との対比

COBOL:                              RPG:
COPY CUSTCPY.                       /copy MYLIB/QRPGLESRC,CUSTDS
01 CUST-REC.                        dcl-ds custRec qualified;
  05 CUST-ID PIC X(8).                custId char(8);
  05 CUST-NAME PIC X(30).             custName char(30);
                                    end-ds;

6. プロトタイプとインターフェース(dcl-pr / dcl-pi)

外部プロシージャを呼ぶ際の「契約」。COBOLのLINKAGE SECTIONに相当。

// プロトタイプ(呼出側に配置 — 「この関数はこういうパラメータを取る」という宣言)
dcl-pr calcTax packed(11:2);
  amount  packed(11:2) const;
  rate    packed(5:4)  const;
end-pr;

// インターフェース(実装側に配置 — 「この関数は実際にこのパラメータを受け取る」)
dcl-proc calcTax export;
  dcl-pi *n packed(11:2);
    amount  packed(11:2) const;
    rate    packed(5:4)  const;
  end-pi;
  return amount * rate;
end-proc;

COBOL との対比

COBOL:                              RPG:
LINKAGE SECTION.                    dcl-pi *n packed(11:2);
01 LK-AMOUNT PIC S9(9)V99.           amount packed(11:2) const;
01 LK-RATE   PIC S9V9999.            rate   packed(5:4)  const;
                                    end-pi;
PROCEDURE DIVISION
  USING LK-AMOUNT LK-RATE.         dcl-proc calcTax export;

7. バインディングディレクトリ

サービスプログラムの「カタログ」。どのサービスプログラムを使うかをまとめる。

// バインディングディレクトリの作成
CRTBNDDIR BNDDIR(MYLIB/MYBND)

// サービスプログラムを登録
ADDBNDDIRE BNDDIR(MYLIB/MYBND) OBJ((MYLIB/TAXSRV *SRVPGM))
ADDBNDDIRE BNDDIR(MYLIB/MYBND) OBJ((MYLIB/CUSTSRV *SRVPGM))

// プログラムのコンパイル時に指定
CRTBNDRPG PGM(MYLIB/ORDPGM) SRCFILE(MYLIB/QRPGSRC) BNDDIR(MYLIB/MYBND)

// または ctl-opt で指定
ctl-opt bnddir('MYLIB/MYBND');

8. コンパイルとリンク

ILE RPG のコンパイルモデル

ソース(.rpgle)
  ↓  CRTRPGMOD
モジュール(*MODULE)
  ↓  CRTPGM / CRTSRVPGM
プログラム(*PGM)またはサービスプログラム(*SRVPGM)

コマンド一覧

コマンド用途生成物
CRTBNDRPGソース→プログラムを一発で*PGM
CRTRPGMODソース→モジュール*MODULE
CRTPGMモジュール群→プログラム*PGM
CRTSRVPGMモジュール群→サービスプログラム*SRVPGM
CRTBNDDIRバインディングディレクトリ作成*BNDDIR

9. 設計パターン

パターン1: ユーティリティ・サービス

UTILSRV *SRVPGM
  ├─ formatDate()      — 日付のフォーマット変換
  ├─ validateEmail()   — メールアドレス検証
  ├─ padLeft()         — 左詰め
  └─ toUpper()         — 大文字変換

パターン2: ドメイン・サービス

ORDSRV *SRVPGM(受注ドメイン)
  ├─ createOrder()     — 受注登録
  ├─ calcOrderTotal()  — 受注金額計算
  ├─ validateOrder()   — 受注データ検証
  └─ getOrderStatus()  — 受注ステータス取得

INVSRV *SRVPGM(在庫ドメイン)
  ├─ allocateStock()   — 在庫引当
  ├─ releaseStock()    — 引当解除
  └─ getAvailable()    — 有効在庫取得

パターン3: レイヤード・アーキテクチャ

画面/API  → ビジネスロジック → データアクセス
(DSPF)     (ORDSRV)          (ORDDA *SRVPGM)
            createOrder()       readOrder()
            calcTotal()         writeOrder()
            validateOrder()     updateOrder()

10. RPGとDDD的設計思想

RPGのサービスプログラムはDDDのバウンデッドコンテキスト(BC)に対応させることができる。モダナイゼーション時にこの対応関係を理解しておくと、API分割の設計が自然に決まる。

RPG(AS/400)                    .NET(クラウド移行後)
──────────────────               ──────────────────────
ORDSRV *SRVPGM                   OrderService(受注BC)
  createOrder()                    CreateOrder API
  calcOrderTotal()                 CalcOrderTotal API

INVSRV *SRVPGM                   InventoryService(在庫BC)
  allocateStock()                  AllocateStock API
  getAvailable()                   GetAvailable API

CUSTSRV *SRVPGM                  CustomerService(顧客BC)
  getCustInfo()                    GetCustomerInfo API
  updateCustCredit()               UpdateCredit API

モダナイゼーションへの示唆

  • RPGのサービスプログラム境界が、そのままマイクロサービスの境界候補になる
  • AI解析ツールでサービスプログラムの依存関係を抽出すれば、BC分割の設計案が自動生成できる
  • DDS(ファイル定義)がエンティティモデル、サービスプログラムが集約に対応する

関連記事