はじめに
IBM i RiSING Cグループのテーマとして「生成AIを使ってみる」に取り組みました。
本記事はその記録です。
題材は IBM i を学ぶうえで避けて通れない RPGLE(RPG IV 固定長フォーマット)。
桁位置に意味がある独特の言語を生成AIはどこまで扱えるのか、そしてAIが書いたコードを読んで直せるようになること自体が RPGLE のより深い理解につながるのではないか、と考え検証しました。
同じ仕様書を Claude と Gemini に渡し、コンパイルが通ってテストケースを全件パスするまでの往復回数を記録。
毎回コンパイルにかけ、エラーの原因を自分たちで特定して次の指示を出すという進め方です。
検証の結果は次の通りです。
| 評価項目 | Claude | Gemini |
|---|---|---|
| コーディング | 〇 | × |
| 保守性/可読性 | × | 〇 |
| 使いやすさ | 〇 | △ |
速く正解にたどり着いたモデルと、読みやすいコードを書いたモデルが別だった、というのが正直いちばん意外な結果でした。
この「割れ方」がいちばんの収穫と感じたので、そこを中心にまとめます。
N=1 の単発検証で、保守性と使いやすさは主観評価です。
「このモデルが優れている」ではなく「こういう条件でこうなった」という一事例として読んでください。
前提:RPGLE の「固定長」について
RPGLE とは、IBM i の主力言語 RPG のうち、ILE によるモジュール化に対応した RPG IV 世代のこと。とのことです。
その固定長フォーマットは、桁位置に意味があるという、他ではあまり見かけない性質を持っています。
行の先頭付近に「この行が何の仕様書か」を示すアルファベットを、決められた桁位置に置く必要があります。
| 記号 | 名称 | 役割 |
|---|---|---|
| H | 制御仕様書 | コンパイルオプションなどの設定 |
| F | ファイル仕様書 | 使用するファイルの宣言 |
| D | 定義仕様書 | 変数・定数・データ構造の定義 |
| C | 演算仕様書 | 実際の処理ロジック |
H OPTION(*SRCSTMT: *NODEBUGIO)
D DATEIN S 8A
C EVAL ERRFLG = '0'
記号だけでなく変数名・型・桁数・演算子の開始位置もすべて決まっています。
仕様書の記号は1桁目から書きます。
コメントも自由には書けません。
* を行頭側に置くか仕様書記号のあとに付けて(D*)行まるごとコメントにするのが基本で、コードの右側に書ける欄は後方の限られた桁にしかないようです。
実際、今回の検証でもこの2点がつまずきの中心になりました。
検証のお題と進め方
「日付(YYYYMMDD/8桁)を受け取り、曜日コードとエラーフラグを返すプログラム」を仕様書から生成させます。
地味に見えますがうるう年判定が効いており、テストケースは正常系5件・異常系5件を事前に用意しました。
| No. | 観点 | 入力 | 曜日 | エラー |
|---|---|---|---|---|
| 1 | うるう年の2/29(4で割れる年) | 20240229 | 4 | 0 |
| 2 | うるう年の2/29(400で割れる世紀年) | 20000229 | 2 | 0 |
| 3 | 平年2月末日 | 20260228 | 6 | 0 |
| 4 | 大の月の末日 | 20260131 | 6 | 0 |
| 5 | 小の月の末日 | 20260430 | 4 | 0 |
| 6 | 4月31日 | 20260431 | - | 1 |
| 7 | 2月30日 | 20260230 | - | 1 |
| 8 | 平年の2/29 | 20260229 | - | 1 |
| 9 | 1900年2/29(100で割れるが400で割れない) | 19000229 | - | 1 |
| 10 | 2100年2/29 | 21000229 | - | 1 |
No.9 の 1900年がポイントで、「4で割り切れる」だけの雑な判定だとここで落ちるはず、と考えて入れました。
| Claude | Gemini | |
|---|---|---|
| モデル | Fable5 | 3.6(思考モード) |
| プラン | 有料版 | Google Workspace |
| 実行環境 | アプリ | ブラウザ |
進め方は次の通りです。
- 仕様書はファイルとして添付する(プロンプトに直書きしない)
- テストケースを先に固める — コードを見てから作ると実装に引きずられるため
- 初回プロンプトは両モデルで完全に同一にする
- 1往復ごとに実機でコンパイルし、その結果を唯一の判定基準にする
- やり取りを1回分ずつ記録する(依頼内容 / 結果 / 備考 とその回のコード全文)
- コンパイルが通ったら、テストケースを全件流す
特に 4 は「AIが『修正しました』と言っているが実際は通らない」ケースを機械的に弾けるので、入れておいてよかったルールでした。
結果サマリ
| Claude | Gemini | |
|---|---|---|
| コンパイル完了までの 往復 |
3回 | 7回 |
| テストケース | 10/10 パス | 10/10 パス |
| 最終コード行数 | 206行 | 88行 |
| うちコメント行 | 126行(61%) | 55行(63%) |
| うち実コード行 | 80行 | 33行 |
| 曜日算出のアプローチ | ツェラーの公式を自前実装 | 組込みの日付型・日付BIFを利用 |
最終的なアウトプットはどちらも合格でした。
差が出たのは、そこに到達するまでの過程と、出来上がったコードの姿だったと感じています。
1回目:両者とも同じ場所でつまずいた
面白いことに、初回のエラーは両者まったく同じでした。
仕様書のアルファベット位置がずれている。
両モデルとも行頭に5桁分のスペースを入れた形で出力してきましたが、この5桁は不要です。
- H OPTION(*SRCSTMT: *NODEBUGIO)
+ H OPTION(*SRCSTMT: *NODEBUGIO)
2回目のプロンプトで「各仕様書のアルファベット開始桁を修正して」と指示すると、両者とも素直に追従しました。
ここはAIの実力差ではなく、こちらのプロンプト設計の不備もあったと思っています。「どの環境に、どの形式で投入するか」まで伝えていませんでした。
Claude:3往復で決着
Claude はこの後、1つだけ修正が入って完了しました。
2回目の残課題は、各月の末日テーブルをコンパイル時配列(CTDATA) で持っていたことによるエラーです。
D WDAYS S 2S 0 DIM(12) CTDATA PERRCD(12)
3回目で修正を依頼すると、CTDATA を使わない方式へ設計ごと切り替えてきました。
* コンパイル時配列(CTDATA)は環境により認識されない場合がある
* ため、データ構造の初期値(INZ)+OVERLAYによる配列定義とする。
D WDAYTB DS
D WDAYSC 24A INZ('312831303130313130313031')
D WDAYS 2S 0 DIM(12) OVERLAY(WDAYSC)
同じ書き方を微調整するのではなく、エラーの出ない別の実現方法に置き換え、しかも「なぜ変えたか」をコメントに残していました。
Gemini:7往復の内訳
一方 Gemini は、2回目以降も細かいエラーが続きました。
| 回 | 依頼内容 | 結果 |
|---|---|---|
| 1 | 仕様書を基にコード生成 |
アルファベット桁位置がずれ |
| 2 | 桁位置の修正 |
レコード後ろのコメント記述で エラー |
| 3 | コメント行とコード行を分けるよう 修正依頼 |
一部コードでエラー コメント長でもエラー |
| 4 | コード修正とコメント短縮を依頼 |
1文のみエラー (※会話履歴を忘れ始める) |
| 5 | エラー行を指摘して修正依頼 |
4回目の修正箇所で コンパイルエラー |
| 6 | エラー内容を指摘 |
1文のみコンパイルエラー |
| 7 | エラー内容を指摘 |
コンパイル完了 (※テキストファイル出力はされず) |
つまずき①:コメントの置き方
2回目のコードは定義の右側にコメントを書いていました。
定義の直後に * を置いてもキーワード欄の一部として解釈され、エラーになるようです。
- D W_DATE S D DATFMT(*ISO) * 日付型変換用
+ D* 日付型変換用
+ D W_DATE S D DATFMT(*ISO)
つまずき②:*ISO と *ISO0
入力は 20260229 のような区切りなし8桁なので *ISO0 が正解だったのですが、5回目まで区切り文字ありの *ISO を使っていました。
- C *ISO TEST(DE) P_DATE
+ C *ISO0 TEST(DE) P_DATE
さらに7回目、MOVE による文字→日付型の変換が残っていた箇所を %DATE に置き換えて、ようやくコンパイルが通りました。
- C MOVE P_DATE W_DATE
+ C EVAL W_DATE = %DATE(P_DATE : *ISO0)
つまずき③:会話履歴の喪失
これが往復回数に一番効いたと感じています。
4回目の時点で、それ以前のやり取りを保持できていない挙動が出たため、3回目のコードを再送し、5回目以降は毎回「最新のコードを添付して依頼する」運用に切り替えています。
7回目にはテキストファイルとしての出力もされなくなりました。
修正のたびに文脈を張り直すと1往復あたりの情報密度が落ち、同じ場所を行き来することになるのだと思います。
実際、4回目で直した箇所が5回目でエラーになる手戻りも発生しました。
設計思想の違いが、評価の割れ方を生んだのでは
評価が割れたのは、同じ仕様書から出てきたコードの方向性が正反対だったためと考えています。
Claude:自前ロジック型(206行)
うるう年判定も曜日算出も自力で実装。
曜日はツェラーの公式を使い、サブルーチンを CHKINP / CHKDAT / CALCWD の3つに分割しています。
C EVAL WZH = %REM(WDD
C + %DIV(13 * (WZM + 1): 5)
C + WZK + %DIV(WZK: 4)
C + %DIV(WZJ: 4) + 5 * WZJ: 7)
C EVAL WWD = %REM(WZH + 5: 7) + 1
処理系の日付機能に依存しないぶん環境差には強いのだと思います。
その反面、公式そのものが正しいかを人間がレビューする必要があります。
またサブルーチン分割とコメントの厚みが、そのままステップ数の多さになっています。
Gemini:組込み機能活用型(88行)
こちらは処理系の日付型と BIF に寄せました。
TEST(DE) で妥当性を検証し、基準日(1899-12-31=日曜)からの経過日数を %DIFF で求めて7で割る発想です。
C *ISO0 TEST(DE) P_DATE
C IF %ERROR
C EVAL P_ERRFLG = '1'
C RETURN
C ENDIF
(中略)
C EVAL W_DAYS = %DIFF(W_DATE : D_BASE : *DAYS)
C EVAL W_REM = %REM(W_DAYS : 7)
うるう年判定を自前で書いていないのに、テストケース No.9(1900年)まで正しく弾けています。
処理系に任せているからこそ正しいのだと思いますし、実コード33行という簡潔さも魅力です。
一方で、組込み機能の細かい仕様(*ISO か *ISO0 か)を外すと動かないため、往復が伸びる原因にもなりました。
往復回数で負けた理由と、可読性で勝った理由が同じ設計判断から来ているように感じました。
3段階評価とその理由
冒頭の表を、評価基準とあわせて再掲します。
| 評価項目 | 基準・観点 | Claude | Gemini |
|---|---|---|---|
| コーディング | テストが通るまでのやり取り回数 (〇:3回以下 / △:6回以下 / ×:それ以上) |
〇 (3回) |
× (7回) |
| 保守性/可読性 | 主観評価(コメントの見やすさ、 処理が無駄に複雑になっていないか) |
× | 〇 |
| 使いやすさ | 主観評価(推測の精度の高さなど) | 〇 | △ |
コーディングは往復回数のみの機械的な判定なので、3回 vs 7回がそのまま出ています。
保守性/可読性は逆転しました。
Claude は処理概要やサブルーチンの説明が細かく、処理内容は Gemini と同等なのにステップ数が伸びています。
サブルーチン化そのものは良いと感じましたが、今回のような単純なプログラムではシンプルなほうがよいのではと考え、加点はしていません。
使いやすさは、少ない表現で意図を汲んでもらえたかどうかです。
Claude は短い指示で通じました。
Gemini は会話履歴を忘れるまでが早く使いにくさを感じましたが、プランや実行環境による可能性が高いため × ではなく △ としています。
考察
1. 壁になったのは、RPGLE の文法ではなく「環境ごとの作法」だったように思う
両モデルとも構文そのものは初回から書けていました。
詰まったのは桁位置・コメントの置き方・日付形式といった、その環境で通るかどうかの部分です。
人間が学ぶときにつまずくのも、たぶん同じ場所なのだと思います(少なくとも私はそうでした)。
2. 差がついたのは、コード生成能力よりも修正フェーズの安定性ではないか
初回コードの完成度に決定的な差はなかったように見えます。
開いたのは2回目以降の修正の効き方だと感じています。
Claude は指摘に対して設計ごと切り替えたのに対し、Gemini は同じ方式内での微修正を繰り返しました。
3. 「早く通る」と「あとで読める」は別の指標
3段階評価が割れたのが、この検証の一番の収穫でした。
往復回数だけを見れば Claude ですが、納品後に他人が読むコードとしては Gemini のほうが扱いやすそうに感じます。
モデルを1つの軸で評価すると判断を誤りそうだ、というのが今回の実感です。
ただし Claude の冗長さは「なぜその実装にしたか」がコメントに残る利点と表裏でもあり、ステップ数だけでは測れないとも思いました。
学び:次に同じことをやるなら
初回プロンプトに「環境の作法」を必ず入れる
両モデルが1往復目を桁位置の修正に費やしたのは、仕様書に「何を作るか」しか書いていなかったからだと思います。
次回はコーディング規約(各仕様書記号の開始桁、コメントの書き方、1行の最大長)を添付するつもりです。
評価軸を先に決めておく
評価項目は検証後に整理しましたが、先に決めておけば「保守性を上げるにはどんな指示を足せばよかったか」まで踏み込めたかもしれません。
特に Claude の冗長さは、「サブルーチンを使わずシンプルに」と指定していれば結果が変わった可能性があります。
「動くコード」より「エラーの伝え方」が成果を左右する
Gemini の5回目以降は「エラーが発生している行を指摘する」形に切り替えてから収束が早まりました。
コンパイルエラーの行番号とメッセージをそのまま貼るのが、結局いちばん速い伝え方だったように思います。
AIに直させる過程が、そのまま RPGLE の勉強になった
*ISO と *ISO0 の違い、MOVE と %DATE の使い分け、CTDATA が環境によって扱えないこと——どれもエラーに突き当たって初めて調べた内容でした。
AIが出したコードを読み、原因を突き止め、次の指示を組み立てる往復が、そのまま RPGLE の学習サイクルになっていた気がします。
保守性の評価にしても、コードを読んで良し悪しを判断できなければ付けられません。
この検証の限界
- N=1 です。もう一度やれば順位が入れ替わる可能性は十分にあります。
- 保守性/可読性と使いやすさは主観評価で、評価者が変われば結果も変わると思います。
-
実行環境が揃っていません。(Claude はアプリ、Gemini はブラウザ)
会話履歴の保持挙動の差は、モデルではなく環境やプランの差かもしれません。
次回は環境をそろえるか、それ自体を比較項目として明記すべきでした。 -
初回プロンプトに桁位置の指定がありませんでした。
テストケースも10件のみで、限定的です。
まとめ
- 同じ仕様書からのRPGLE生成で、コンパイル完了まで Claude 3往復 / Gemini 7往復
- 最終成果物は両者ともテスト10件を全件パス。品質の到達点に差はなかった
- 3段階評価はコーディングは Claude、保守性/可読性は Geminiときれいに割れた
- 生成されたコードは自前ロジック型 vs 組込み機能活用型と、設計思想が正反対だった
生成AIを開発に使うなら、収束までの往復コストと出来上がったコードを他人が保守できるかを分けて見る必要がありそうです。
今回はその2つが、きれいに別のモデルに分かれました。
もっとも研修としての手応えは勝敗の比較ではなく、エラーを1つずつ潰していく過程で RPGLE の作法が少しずつ身についたことにありました。
生成AIは「答えを出してくれる道具」というより間違いを含んだ叩き台を高速に出してくれる道具で、それを読んで直せるかどうかは結局こちら次第なのだと感じました。
当記事の著作権はIBMに帰属します。詳細はこちらをご参照ください。