PL/IからJavaへ:基幹システムの「数値」を巡る、甘くない真実
メインフレームの現場で何十年と生き抜いてきた諸君なら、一度は目にしたことがあるだろう。あの不気味に輝く`PIC S9(9)V99`の定義を。
今日は、PL/Iで書かれた堅牢な基幹プログラムをJavaへマイグレーションする際、最も多くのエンジニアが沼にハマる「データ型の変換」について、現場の知見を叩き込んでおこうと思う。理論上の変換表だけを見ていては、本番環境で確実に痛い目を見るからな。
—
1. なぜ「数値」が魔物なのか
PL/Iの`FIXED DECIMAL`は、10進数演算をハードウェアレベル(あるいはライブラリレベル)で厳密に制御する。特に、演算中の一時的な精度保持や、ピクチャ指定による暗黙的な切り捨て・四捨五入の挙動は、まさに「長年動いている仕様」そのものだ。
一方で、Javaの`BigDecimal`は、スケーリングと丸めモード(RoundingMode)を開発者が明示的に指定しなければならない。「デフォルトでどうなるか」という前提が、PL/IとJavaでは根本的に異なるという点をまず肝に銘じておけ。
2. 現場で遭遇する「精度の罠」
まずは、よくあるPL/Iの計算ルーチンを見てみよう。
1
/ —————————————————————— /
/ 計算処理の一例:固定小数点演算の典型的なパターン /
/ —————————————————————— /
CALC_PROC: PROCEDURE(IN_VAL) OPTIONS(MAIN);
DCL IN_VAL FIXED DEC(9, 2);
DCL TAX_R FIXED DEC(3, 3) INIT(0.08); / 8% /
DCL RESULT FIXED DEC(11, 2);
/ ここでの計算は、PL/Iのコンパイラオプションによるが、 /
/ 中間結果は自動的に拡張された精度で保持される。 /
RESULT = IN_VAL (1 + TAX_R);
/ ピクチャ属性を使った編集出力 /
DCL OUT_STR PIC ‘ZZZ,ZZZ,ZZ9.99’;
OUT_STR = RESULT;
PUT SKIP LIST(‘RESULT: ‘ || OUT_STR);
END CALC_PROC;
このコードをそのままJavaの`double`に直して満足しているようでは、深夜の呼び出し対応が確定したようなものだ。Javaで書くなら、最低でも`BigDecimal`を使い、`MathContext`や`RoundingMode.HALF_UP`(あるいはシステムの要求仕様に応じたモード)を明示的に指定しなければならない。
マイグレーションの鉄則
- スケールの明示: `BigDecimal`の`setScale`を省略するな。
- 丸めモードの統一: PL/Iが内部でどのように丸めているか(切り捨てか、四捨五入か)、古いマニュアルではなく、現行ソースの計算結果をダンプして確認しろ。
- オーバーフロー: PL/Iは`FIXEDOVERFLOW`のONユニットで例外を捕捉できるが、Javaでは`ArithmeticException`を適切にハンドリングする必要がある。
—
3. ONユニットと例外処理の温度差
PL/Iの強力な武器である`ON`ユニットは、プログラムの局所的なエラー制御に長けている。
1
/ 数値変換エラー時の制御例 /
ON CONVERSION BEGIN;
/ 不正なデータが来た場合のログ出力とスキップ /
PUT SKIP LIST(‘データ変換エラーが発生しました。処理を継続します。’);
GOTO NEXT_RECORD;
END;
/ ファイルからの読み込み /
GET FILE(VSAM_FILE) INTO(RECORD_AREA);
これをJavaの`try-catch`に置き換える際、単にログを出して終了するだけでは、元のPL/Iが持っていた「一部の不正データがあっても、残りを処理しきる」というバッチの強靭さが損なわれる。バッチ処理の文脈において、例外は「止めるためのもの」ではなく「リカバリするためのもの」であることを意識した設計が必要だ。
—
4. エンジニアへの提言:仕様を信じるな、データを信じろ
マイグレーションプロジェクトにおいて、一番危険なのは「現行コードの仕様書」だ。仕様書は往々にして陳腐化している。
1. 実データのダンプ: 過去のテストデータや本番のログから、入出力される数値の最大値・最小値、小数点以下の桁数を確認すること。
2. 計算過程のトレース: PL/Iの`FIXED BINARY`と`FIXED DECIMAL`が混在する計算式があれば、そこは地雷原だ。変換前に必ず型を統一する設計にせよ。
3. テストコードの充実: Javaに移植した後、元のPL/Iと同じ入力値を流し込み、計算結果が1ビットの狂いもなく一致するかを確認する「回帰テスト」を自動化すること。
メインフレームからJavaへの移行は、単なる言語の翻訳作業ではない。数十年かけて積み上げられた「暗黙の知恵」を現代の言語に再定義する、一種の「考古学」に近い作業なんだ。
諸君、コードを眺める際は、単に構文を追うのではなく、「なぜこの桁数なのか」「なぜこのタイミングでONユニットを置いたのか」という設計者の意図を想像してほしい。それができるエンジニアこそが、次世代のシステムを任せられる存在になる。
現場からは以上だ。また何かあれば、いつでも聞きに来い。
