前回の復習
前回は、保守しやすいシステムを構築する手段として利用可能なサービス・プログラムを、FFRPG で作成する方法を解説しました。金額を引数で受け取り、税込価格を戻り値として戻す簡単な関数の作成を通して、サービス・プログラムの基本はおおよそ理解していただけたと思います。複数のプログラムで共通で使用するロジックがあれば、サービス・プログラムにユーザー関数としてまとめておくことにより、プログラム作成者はその関数を各プログラムから呼び出すだけで、ロジックを知らなくても結果を取得することができるようになります。また、引数や戻り値が変わらないのであれば、サービス・プログラムの更新だけで、それを使用するプログラムは一切変更せずにロジックを修正することができることも解説しました。保守しやすいシステム実現にサービス・プログラムが有効であることを理解していただけたと思います。 今回は、このサービス・プログラムをさらに詳細に解説していきます。修正の際の考慮点、プロトタイプ定義の共通化などを取り上げます。それでははじめましょう!サービス・プログラムの修正
前回、税込価格を計算する関数 getIncludeTax を税率 8% で作成し、それを呼び出すプログラム icafe023 を作成しました。その後、税率を 10% に変更してサービス・プログラムを再作成しましたが、icafe023 はなんら変更することなく実行することができましたね。これは、icafe023 とこの関数との接点である引数と戻り値を何も変更していないからです。内部ロジックを見えないようにカプセル化し、外部との接点を最小限にしておく、この疎結合の考え方がお互いを独立させ保守の容易性を飛躍的に高めているのです。 ただし、税率 8% のロジックを持つ関数を icafe023 から一度実行し、その後 10% でサービス・プログラムを更新して再度 icafe023 を実行しても、結果は変わらず 8% で計算されていました。変更した税率を有効にするにはサインオンし直して、再度プログラムを実行しなければなりませんでしたね。どうしてサービス・プログラムの更新がすぐに有効にならないのでしょうか? この理由を明らかにするには、バインディング処理の理解が必要です。 「第三回 – プログラムの基本構造」で解説した通り、サブ・プロシージャーは静的呼び出しで実行されます。ユーザー関数もサブ・プロシージャーなので、呼び出しは静的呼び出しです。この呼出しは各関数のアドレスを使用して行われるのですが、この一連のアドレス解決をバインディング処理といいます。実際のバインディング処理は以下の通りです。- プログラムを実行(活動化)
- そのプログラムで使用するサービス・プログラムが活動化(メモリーにロード)
- 内部の各関数のアドレス解決を実施
- ジョブを終了する(対話型の場合はサインオフ)
- RCLACTGRP コマンドを使用する
RCLACTGRP ACTGRP(QILE)
プロトタイプ定義の共通化
icafe023 は、icafesrv サービス・プログラム内に定義された getIncludeTax を呼び出すために、プロトタイプ定義が必要でした。これは、コンパイラーにプログラム内で呼び出す関数名、引数の数とそれぞれの属性、戻り値の型を知らせる目的で記述します。コンパイラーは、実際に関数呼び出しのコーディングがプロトタイプ定義と一致しているかをチェックし、一致していなければ *MODULE オブジェクトを作成しません。 プログラム作成には、CRTPGM コマンドの実行が必要ですが、このステップではコマンドで指定(BNDSRVPGM パラメータ)したサービス・プログラム内に呼び出す関数が存在しているかのチェックは行いますが、引数や戻り値についてはチェックされません。これを記号解決(名前解決)といいます。- モジュールのコンパイル時
- プロトタイプ定義通りにその関数が呼び出されるようコーディングされているかチェック
 
- プログラム作成時
- 使用している関数名がサービス・プログラム内に存在しているかチェック
 
- サービス・プログラム作成者が、全関数のプロトタイプ定義だけをまとめたソースを作成する
- 関数を使用するプログラムの作成者が、各モジュールのコーディング上で上記のソースを /copy や /include で記述する
 これは、プログラム・ソースにコンパイル時にコピーするものなので、単独でコンパイルはしません。それでは、icafe023 を以下のように修正して、prototype.rpgle を組み込むように変更しましょう。
/include を記述すると、その箇所に指定したファイル(./prototype.rpgle)がコンパイル時に挿入されます。ファイル名の前の「./」はカレントディレクトリを意味します。この共通ファイルをどこに置くかでこの記述方法を変更しなければならない点については注意しておきましょう。
それではプログラムを再作成します。前回の記事を参考に icafe023 を再作成しましょう。
これは、プログラム・ソースにコンパイル時にコピーするものなので、単独でコンパイルはしません。それでは、icafe023 を以下のように修正して、prototype.rpgle を組み込むように変更しましょう。
/include を記述すると、その箇所に指定したファイル(./prototype.rpgle)がコンパイル時に挿入されます。ファイル名の前の「./」はカレントディレクトリを意味します。この共通ファイルをどこに置くかでこの記述方法を変更しなければならない点については注意しておきましょう。
それではプログラムを再作成します。前回の記事を参考に icafe023 を再作成しましょう。
- モジュール icafe023 をメニューのオプション 12 で作成
- プログラム icafe023 をメニューのオプション 14 で作成(サービス・プログラム icafesrv を指定)
- ユーザー関数を設計する(名前、引数の数と個々の属性および戻り値の決定)
- プロトタイプ定義を専用ファイル(今回の例ではrpgle)に記述する
- rpgle を /include で組み込んでユーザー関数を含むモジュールをコンパイルする ・この時点で実際の関数とプロトタイプ定義が一致する
- ユーザー関数を含むモジュールでサービス・プログラムを作成する
- 各プログラムにrpgle を /include で組み込んでモジュールおよびプログラムを作成する ・プロトタイプ定義は実際の関数と一致しているので実行時のエラーを防げる
 因みに、そのモジュール内で使われていない関数に対するプロトタイプ定義が存在してもコンパイルには何ら影響しませんので、プロトタイプ定義用ファイルにはすべてのプロトタイプ定義を含めるようにしましょう。
因みに、そのモジュール内で使われていない関数に対するプロトタイプ定義が存在してもコンパイルには何ら影響しませんので、プロトタイプ定義用ファイルにはすべてのプロトタイプ定義を含めるようにしましょう。
 
バインド・ディレクトリ(*BNDDIR)
連載第八回までは、プログラムの作成は CRTBNDRPG コマンド(メニューのオプション 1)を使用していました。しかし、サービス・プログラムを使用する icafe023 は、CRTRPGMOD でモジュールを作成し、その後 CRTPGM を使用して作成しました。これは、使用するサービス・プログラムを指定するパラメータが CRTPGM にしかないためです。ILE 言語の本来の作成手順は後者であることを今一度認識しておいてください。 一方で、先ほどのプロトタイプ定義の問題と同様のことが CRTPGM でも発生します。それは、プログラムを作成するプログラマーが、使用するサービス・プログラムがどのライブラリーにあるのか、名前が何かなどの情報を知らないと作成できないということです。プログラマーは使用したいユーザー関数情報は知っていますが(知らなければコーディングできない)、その関数がどのサービス・プログラムにあるのかまでは知らないかもしれません。この問題を解決するために利用可能なのがバインド・ディレクトリです。 CRTPGM 実行時に行われるのは名前解決でしたね。そのプログラムに含む予定のモジュール内で使用されている関数が BNDSRVPGM に指定したサービス・プログラムで EXPORT されているかをチェックすることで実現します。この名前解決に使用するサービス・プログラムを予めリスト化しておき、プログラム作成時に利用するために用意されているのがバインド・ディレクトリというオブジェクト(*BNDDIR)です。関連コマンドは以下の通りです。- CRTBNDDIR(バインド・ディレクトリの作成)
- ADDBNDDIRE(バインド・ディレクトリ項目の追加)
- DSPBNDDIR(バインド・ディレクトリの表示)
- CRTBNDDIR BNDDIR(*CURLIB/ICAFEBNDDR)
- ADDBNDDIRE BNDDIR(*CURLIB/ICAFEBNDDR) OBJ((*LIBL/ICAFESRV *SRVPGM))
 バインド・ディレクトリは、CRTPGM コマンド(メニューのオプション 14)の BNDDIR で指定します。F9 コマンドを押してすべてのパラメータを表示し、次ページを表示すると以下の画面が表示されます。
バインド・ディレクトリは、CRTPGM コマンド(メニューのオプション 14)の BNDDIR で指定します。F9 コマンドを押してすべてのパラメータを表示し、次ページを表示すると以下の画面が表示されます。
 バインド・ディレクトリを指定すればサービス・プログラム名を個別に指定する必要はありません。名前解決はバインド・ディレクトリに登録されているサービス・プログラムを順番に検索することで実施します。オブジェクトを探索するのにライブラリー・リストを使用するのと似ています。バインド・ディレクトリはサービス・プログラム作成者が保守し、プログラマーはバインド・ディレクトリ名だけを知っていいれば良いことになりますね。
BNDDIR パラメータは、CRTBNDRPG コマンドにも存在します。つまり、icafe023 を CRTBNDRPG コマンドで作成することもできるわけです。
メニューのオプション 1 で F9 キーを押すと表示される BNDDIR パラメータに ICAFEBNDDR を指定するか、icafe023.rpgle 内の制御ステートメントで以下の記述を追加すれば、プログラムの作成が可能です。実際に icafe023.rpgle を修正してメニューのオプション 1 で作成できることを確認しましょう。
バインド・ディレクトリを指定すればサービス・プログラム名を個別に指定する必要はありません。名前解決はバインド・ディレクトリに登録されているサービス・プログラムを順番に検索することで実施します。オブジェクトを探索するのにライブラリー・リストを使用するのと似ています。バインド・ディレクトリはサービス・プログラム作成者が保守し、プログラマーはバインド・ディレクトリ名だけを知っていいれば良いことになりますね。
BNDDIR パラメータは、CRTBNDRPG コマンドにも存在します。つまり、icafe023 を CRTBNDRPG コマンドで作成することもできるわけです。
メニューのオプション 1 で F9 キーを押すと表示される BNDDIR パラメータに ICAFEBNDDR を指定するか、icafe023.rpgle 内の制御ステートメントで以下の記述を追加すれば、プログラムの作成が可能です。実際に icafe023.rpgle を修正してメニューのオプション 1 で作成できることを確認しましょう。
 上記 bnddir 内のバインド・ディレクトリ名はライブラリー名の修飾も可能なので引用符で囲む必要があります。大文字小文字を区別しますので、ここでは必ず大文字で定義するようにしてください。
上記 bnddir 内のバインド・ディレクトリ名はライブラリー名の修飾も可能なので引用符で囲む必要があります。大文字小文字を区別しますので、ここでは必ず大文字で定義するようにしてください。
 
終わりに
前回に引き続き、サービス・プログラムを解説しましたがいかがだったでしょうか。今回は解説が多く、プログラムの新規作成はなかったので分かりづらかったかもしれません。しかし、実際の基幹システムでサービス・プログラムを活用する場合は、今回の解説内容は最低限理解しておかなければならないことだと思っています。何度も読み返してしっかり理解するようにしてください。 サービス・プログラムについては、まだ解説しなければならないことがあります。- 引数の様々な種類と渡し方
- 業務で利用開始されたサービス・プログラムを変更する場合の考慮点






 
				

 
						



