メニューボタン
IBMi海外記事2026.03.11

救いにも害にもなるCRTSRVPGMのパラメーター

Gregory Simmons 著

午前2時、電話が鳴り止みません。本番ジョブで障害が発生し、エラー ログがまったく意味を成しません。1時間掛けてあれこれ調べた結果、ようやく犯人が正体を現しました。サービス プログラムで間違ったプロシージャーがバインドされていたということです。どういうわけか、暗黙の重複がこっそり忍び込んでいて、下流側のすべてが壊れていました。そのような状況に置かれた経験がある方なら、「it compiles, it runs(コンパイルできた、動いた)」という考え方は、サービス プログラムを作成する際には最悪の考え方だということがお分かりだと思います。CRTSRVPGMのパラメーターは、それぞれ存在する理由があるため、それらをないがしろにすると、考え得る最悪の時間帯に、簡単なビルドが悪夢と化すことがあります。

サービス プログラムについて言えば、CRTSRVPGMを実行する際に、IBMから提供されているどのデフォルト設定でもそのまま利用するという罠に陥っている開発者があまりにも多いようです。彼らが気にするのは、「コンパイルできた、動いた」ということだけで、本番で何かが動かなくなると、急に皆で、システムが実際にどのプロシージャーをバインドしているのか解明しようと慌て始めます。サービス プログラムはモダンなRPG設計の中核となる部分ですが、その作成について軽く考えているというのは、メンテナンスの悪夢のお膳立てをしているようなものです。それでは、CRTSRVPGMの最も重要なパラメーターをいくつか見てみましょう。それらが、一般に思われている以上に重要である理由についても見て行きます。

まずは、バインディング ディレクトリーです。理論上、それらは非常に有難いものです。よく使用するモジュールまたはサービス プログラムをすべて1か所にまとめて、作成コマンドでそのディレクトリーを指定すれば、バインドしているすべてのものの名前を覚えている必要はありません。そのような利便性は、何百ものモジュールによる大規模なアプリケーションでは特に魅力的です。問題は、この同じ利便性によって、実際に起こっていることが隠されてしまうことです。複数のバインディング ディレクトリーが連鎖されている場合に、知らないうちに間違ったバージョンのプロシージャーにバインディングしてしまっていたということもあります。突然、昨年のコードを呼び出して、新しいロジックがなぜ実行されないのか誰も解明できません。

私が実践している大まかなルールはこうです。バインディング ディレクトリーは、意図を明確にして使用するようにします。つまり、サービス プログラムごとに、それが必要とするモジュールのみが含まれる独自のバインディング ディレクトリーを持たせるようにするべきだということです。十分に説明がなされているユーティリティ ルーチン用のディレクトリーがあってもよいでしょうし、ビジネス ロジック用のディレクトリーがあるというのも合理的です。しかし、注意してください。何にバインドしているかを明示的に指定するには、最初により多くの時間を掛けることが必要になるかもしれません。しかし、そうすることで、プロシージャーがどこに由来するかについて疑問の余地がなくなるということでもあります。

もうひとつ、注意を払う必要があるパラメーターはOPTIONです。デフォルトでは、このパラメーターはブランクであり、あまり害はなさそうに思えますが、そのブランクという値は、実際には重複プロシージャー(*DUPPROC)と重複変数(*DUPVAR)の両方を許可することを意味します。これは静かな地雷のようなものです。重複を可能にしている場合、異なるモジュールで同じ名前の2つのプロシージャーまたは変数があったとしても、システムはエラーを出しません。システムはどちらか1つを選ぶだけですが、それはこちらで想定している方ではないかもしれません。チームで何時間も費やしてデバッグした結果、間違ったバージョンのプロシージャーを呼び出していた原因が、単に間違ったものがバインドされていただけだったということもありました。修正は簡単です。すなわち、明示的にOPTION(*NODUPPROC *NODUPVAR)を設定し、それをショップ全体の標準にすることです。名前の競合があるなら、今すぐにそれらを修正します。そうすれば、今後は、際限のない面倒な問題を回避できるでしょう。

次に、何をエクスポートするかという問題があります。安易な方法を選んで、EXPORT(*ALL)を使用した場合、誰にも使用させるつもりがなかった小さな内部ヘルパーを含め、サービス プログラム内のあらゆるプロシージャーが公開されることになります。それは、自宅を訪れたすべての訪問客に道具小屋の鍵を渡しているようなものです。何も問題が起こらないかもしれませんが、誰かが道具を「借用」してそれを壊されたりしたら、後悔することになるはずです。より適切な方法は、バインダー ソースでエクスポートするものをコントロールすることです。EXPORT(*SRCFILE)を使用して、公開するものを明示的にリストすることにより、サービス プログラムのインターフェースを制限し、内部のルーチンをそれらが所属するところで非公開にします。

現在の私のショップでは、こうした方針を強化する命名規則も採用しています。エクスポートされるプロシージャーの名前はすべて、そのプロシージャーが属するサービス プログラムの名前から始まるようにしています。たとえば、mshrmutilsという名前の、マッシュルームに関連があるユーティリティがたくさんあるサービス プログラムがあったとしたら、mshrmutils_save_new_species、mshrmutils_is_edibleなどのようなプロシージャーをエクスポートすることになるでしょう。私たちは、同じ命名規則をどのグローバル変数にも使用しています(もっとも、そもそもグローバル変数の使用は控えめにすべきですが)。ほとんどの場合、ローカル変数の方がより良い選択肢です(ローカル変数が望ましい理由については、そのテーマについて深掘りした以前の記事、「 プロシージャー主導型RPGでは、変数はローカルに保たれる」を参照してください)。この単純なルールは、2つの大きなメリットをもたらします。第1に、異なるサービス プログラムで同じ名前の2つのプロシージャーまたは変数を偶然作成してしまうことは決してありません。これにより、OPTION(*NODUPPROC *NODUPVAR)を適用しやすくなります。第2に、コードを読んでいて、プロシージャーの呼び出しを見たときに、プロシージャー名または変数名の最初の単語を見るだけで、それがどのサービス プログラムに由来するかが正確に分かります。つまり、いろいろ調べることが少なくなり、トラブルシューティングが速くなり、「これはどこで定義されているのか」と考える瞬間が少なくなるということです。

結論はこうです。すなわち、CRTSRVPGMは、「compile it and forget it(コンパイルできたら、後は気にしない)」でよいコマンドではないということです。このコマンドのパラメーターはすべて、理由があって存在しています。そして、それを理解できていれば、悲痛な驚きに見舞われずに済むようになります。バインディング ディレクトリーは、慎重に検討した上で使用する。重複プロシージャーおよび変数は許可しない。エクスポートするものを制限する。これらの設定に関して手を抜いていると、直ちに痛い目に遭うというわけではありませんが、いざそうなったときには、大変なことになります。今のうちにその作業を行っておけば、サービス プログラムは、予測可能性が向上し、保守が容易になり、管理するのにストレスがかなり少なくなります。

次回の記事では、バインダー ソースについてさらに深掘りし、エクスポート制御だけでなく、バージョン管理にも活用できる方法について見て行きます。しかも、それはあなたの作業を複雑にするのではなく、むしろシンプルにしてくれるはずです。

あわせて読みたい記事

PAGE TOP