21世紀のRPG IVスタイル
「今のスタイルやつくりが心地良すぎるゆえに、もうこのままでよい、と思ってしまうこともありえる」 - リン・アビー、米国作家
今までもよく私が話してきたことですが、RPGほど変化の速いコンピュータ言語はありません。その起源は40年以上前に遡りますが、RPGはパンチカードの遺産から進化してわずか10年余りで現代のビジネス・アプリケーションの多くをリードする豊富な機能を備えた言語となりました。
しかしRPGの進化に伴って皆さんはプログラミング・スタイルを進化させているでしょうか。RPG IVのスタイル・ガイドを私が初めて書いたのはわずか数年前で、以後何度か改訂してはきましたが、そのスタイルや標準、ベスト・プラクティスに対して私が昔から使いやすいものにしようとしてきた取り組みは、新しいリリースが出るたびに時代遅れのものになってきていました。本稿では、スタイリッシュなRPG IVコードを記述するための私からの提言を見直して改訂します。
自由を謳歌しよう
固定フォーマットのRPG計算はいまや過去の遺産となっています。今となってはほぼ10年間に渡ってRPG IVはフリー・フォーマットの仕様を計算仕様の代替えとしてサポートしてきました。新しいRPGプログラムはすべてフリー・フォーマットで記述してください。固定フォーマットのコードに比べて読みやすく、ドキュメントもしやすく保守が容易だからです。しかもフリー・フォーマットの構文は現代の他の言語と一貫性があるのです。
フリー・フォーマットの仕様で記述すれば、多くの場合その結果として、おのずと標準化をうまく進めることができます。新しい仕様では固定フォーマットのC仕様のような時代遅れでお粗末な方法が使えなくなっているからです。また、各リリースにおいてRPGの新しい機能はフリー・フォーマットでしかサポートされなくなってきています。
算術式、文字列、論理式、代入や比較、値のセットなど、可能な限りフリー・フォーマットの式を使用してください。また、必要に応じて字下げしてコードを記述することで読みやすくしてください。ただし、カラムを利用して式を揃えることを全くしないようにと言っているわけではありません。式が複数行に渡るときは式を揃えて書いた方が良いでしょう。
オプションの命令コードを省略する。
フリー・フォーマットの構文では各行は命令コードで始まることと規定されています。ただしEvalとCallpだけは例外です。これらの命令ではエクステンダを使用する必要がある場合を除いて、命令コードを省略してください。たとえば、
Eval Regpay = Reghours * Rate;
Callp Genpay();
と書く代わりに以下のように書きます。
Regpay = Reghours * Rate;\
Genpay();
こう書くと他の言語で記述したのと同様に、プログラムが読みやすくなります。エクステンダを使用する必要がある場合は、命令を明示的にコードとして記述しなければならないということを覚えておいてください。
SQLにはフリー・フォーマットを使用する。
リリース5.4から、組み込みSQL文でフリー・フォーマットのExec SQLディレクティブがサポートされるようになり、プログラムのSQL部分に固定フォーマットを使用する必要がなくなりました。フリー・フォーマットでコーディングした組み込みSQL文の例を図1に示します。各SQL文はExec SQLコンパイラ・ディレクティブで始まり、セミコロンで終わります。
ILEを取り入れる
RPG IVとILEは非常に密接に連携しています。RPG IVの構文とILEを組み合わせて使用すると、アプリケーション・プログラミングのモジュール化を促進することができます。モジュール化することでアプリケーションを整理でき、プログラムの保守性が向上し、複雑なロジックを表に出さずに済み、再利用が可能な場面で効率的な再利用を進めることができます。
再利用可能なコードをプロシージャとして独立させる。
単一で万能の怪物を作るのではなく、より小さい、単機能のコンパイル単位でコードを記述し、そのコードを必要とする他のプログラムと結合させてください。コードの重複はその大小にかかわらず排除してください。コーディングする際の信条は「1回だけ書く」です。
わかりづらいコードを書き直し、きれいにドキュメント化された、わかりやすい名前のプロシージャにする。
ときには努力しているにもかかわらず、かなりのコメントを追記しないとコードの塊が何をしようとするものなのかわかりづらくなってしまう場合もあるかもしれません。そのような分量の多い、十分にテストされたコードを分離してプロシージャにすることで、のちにそのコードを解読するプログラマの手間を軽減することができます。
各プロシージャには戻り値を持たせる。
呼び出し側のプログラムに戻り値を戻さないプロシージャを記述することは可能ですが、すべてのプロシージャは少なくともエラーが発生することなく処理が終了したのか否かを示すyes/no (データ・タイプN型)を戻すべきです。戻り値を無視していいような場合(ほとんどないと思われる)は無視しても構いませんが、戻り値を使用する可能性がある限り戻り値を戻すべきです。次に示すコードは同じプロシージャを呼び出していますが、2行目はCallp (implied)を使用していており、その戻り値を無視しています。
Grossokay = Grosspay();
Grosspay();
プロトタイプは/COPYメンバーに格納する。
各モジュールに対してエキスポートされる各プロシージャのプロシージャ・プロトタイプを含んだ/COPYメンバーを記述します。次に、呼び出された要素中のプロシージャを参照する各モジュール内でこの/COPYコンポーネントに対する参照を記述します。こうすることで、プロトタイプが必要になるたびにプロトタイプを入力する手間が省け、それによりエラーの発生確率を小さくすることができます。小さな/COPYメンバーをたくさん用意する代わりに、再利用可能なプロシージャのすべてまたはほとんどに対するプロトタイプを含むマスターの/COPYメンバーを用意することもできます。
また、RPGの条件付きコンパイル・ディレクティブを使用することで、汎用的な/COPYメンバーを使用する代わりに実際のプロシージャのソースからプロトタイプを使用することができます。このテクニックを使用することで、利用されたことのないプロトタイプがコンパイル・プロセスを通らないようにできますが、コンパイル時に利用されたことのないプロトタイプがあったからといって実行時にペナルティがあるわけではありません。
モジュールのプロトタイプと同じ/COPYメンバーの中にそのモジュールに対する定数宣言を記述してください。そして、呼び出される側のモジュールを参照する任意のモジュール中の/COPYメンバーを参照すれば、上記の定数を事実上グローバルに宣言したことになります。
*Entry Plistの使用を避ける。
(固定フォーマットの構文を必要とする)*Entry Plistを使用する代わりに、プログラムのメイン・プロシージャ用のプロトタイプとプロシージャ・インタフェースを用意してください。これらの項目はプログラム中で最初の定義(ファイル仕様の直後)として記述しなければなりません。メイン・プロシージャのプロトタイプには他のプロトタイプには必ずしも当てはまらない固有の要件がいくつかあります。
- Extpgmキーワードを含んでいなければならない(プログラム名では大文字と小文字が区別されます)。
- メイン・プロシージャ・インタフェースの前になければならない。
- メイン・プロシージャ・インタフェースには名前が付いていなければならない。- プロトタイプと同様。
メイン・プロシージャのプロトタイプとインタフェースには標準的な名前(たとえばMainなど)をつけなければなりません。図2の*Entry Plistの代わりに、図3のようなコードを記述するようにしてください。
パラメータを渡す方法が適切かどうか注意してください。パラメータを適切に渡すことでパラメータ値をうっかり変更してしまうことを防ぐことができます。適切な方法でパラメータを渡していれば、プロシージャの呼び出しをコーディングする際の柔軟性も大幅に増します。パラメータを渡す方法には以下の3つの方法があります。
- 参照渡し(デフォルト)
- 値渡し
- 読み出し専用渡し
それぞれの方法についてここでは詳細には説明しませんが、知っておくべき経験則があります。
プロシージャ間でパラメータを渡す際に使用する方法は通常は値渡しとしてください。値渡しにするにはプロトタイプにVALUEキーワードを指定します。この方法を使用すると、プロシージャ間でパラメータのファイヤー・ウォールができることになります。つまり、呼び出されたプロシージャはパラメータの値を変更することができますが、その変更は呼び出し側には反映されません。値によるパラメータ渡しはプログラム呼び出しでは使用できません。
プログラム間でパラメータを渡す際は読み出し専用参照の方法で渡してください。読み出し専用参照でパラメータを渡すにはプロトタイプでCONSTキーワードを使用します。この方法を使用すると、間違って値を変更してしまうことを防ぐことができます。たとえば呼び出されたプログラムもプロトタイプされている場合、パラメータの値の変更をコンパイラが許可しません。パラメータを変更する可能性のある、呼び出された側のプロシージャでコードが変更されるのを防ぎたい場合、プロシージャの呼び出しにも読み出し専用参照でのパラメータ渡しを使用することができます。
デフォルト設定である参照渡しは、呼び出し側と呼び出された側とで値を共有する必要が本当にあるパラメータのみに対して使用してください。1つの例はエラー・メッセージを呼び出し側に渡す際に使用するパラメータです。
パラメータを値渡しまたは読み出し専用参照渡しするときは、呼び出しの際にリテラルや式を使用することができます。
Tax = Statetax('CO' : Regpay + Ovtpay );
参照渡しとする場合は、パラメータは何らかの変数に関連付けられていなければなりません。
Tax = Statetax(State : Grosspay);
同じプロトタイプの中でパラメータ渡しの方法を組み合わせて使用することができます。図4では、最初の2つのパラメータは値渡しですが3番目のパラメータは参照渡しになっています。
一貫性のあるバインド・ディレクトリを使用する。
バインド・ディレクトリはプログラムの作成に必要なそれぞれの要素を整理するのに便利なオブジェクトです。バインド・ディレクトリを使用して頻繁に再利用されるモジュールやサービス・プログラムをリストにしておくと、プログラムをCreate Program (CRTPGM)コマンドやCreate Service Program (CRTSRVPGM)コマンドでバインドする際に必要となるコンポーネントを明示的にリストする代わりに、バインド・ディレクトリを参照すればよいので、エラーを防ぐことができます。バインド・ディレクトリを効果的に使用するには一貫性のある戦略が必要です。その1つの方法としては、1つのアプリケーションだけに関係するコード用のアプリケーション固有のバインド・ディレクトリの他に、複数のアプリケーションに渡って再利用されるコードを参照する汎用的なバインド・ディレクトリを用意しておくというものです。
頻繁に再利用するプロシージャをサービス・プログラムとしてパッケージ化する。
サービス・プログラムはプロシージャを必要とする各プログラム中にそのプロシージャを物理的にコピーすることなく再利用できるようにした、洗練された方法です。パッケージ化のガイドラインとしては、1つのプロシージャが複数のプログラム中で必要となったら、そのプロシージャをサービス・プログラムとしてパッケージ化してください。
バインダ言語を使用してサービス・プログラムのシグニチャーを制御する。
CRTSRVPGMコマンドでEXPORT(*ALL)を指定してサービス・プログラムのシグニチャーをバインド・プログラムに処理させたくなりますが、そうすると保守が大変になります。バインダ言語のソースを利用するとサービス・プログラムのシグニチャーを明示的に制御することができますが、さらに重要なのは、サービス・プログラムが複数のシグニチャーを保守できることです。つまり、サービス・プログラムに対してプロシージャの追加、変更、削除をしたり、パラメータを修正したりするなどといった大幅な変更をしながらも、そのサービスを利用するプログラムには一切変更をしないで済むということになります。
IMPORTとEXPORTはグローバルなデータ項目のみに使用する。
IMPORTキーワードとEXPORTキーワードを使用すると、プログラム間で明示的にデータをパラメータとして渡さなくてもデータを共有することができます。つまり、プロシージャ間の隠れたインタフェースを提供することになります。これらのキーワードを使用するのは、プログラム中で本当にグローバルなデータ項目だけにしてください。通常は、値を一度だけ設定して以後変更されないようなデータ項目がこれに相当します。
宣言を一箇所に集中させる
RPG IVでは定義仕様を使用してプログラムに関連するすべてのプロトタイプ、定数、変数を宣言します。すべての定義はプログラムの1つのエリアに統一された構文で記述します。D仕様を使ってすべての宣言を予測可能な順序で以下の定義タイプごとに整理します。
- メイン・プロシージャのプロトタイプ
- メイン・プロシージャのプロシージャ・インタフェース
- その他のプロトタイプ定義
- 名前付き定数
- データ構造
- 独立変数
各定義タイプ内では宣言をアルファベット順に並べます。
リテラルを使用する代わりに名前付き定数で宣言する。
ここでの忠告は「謎の値は使わない」です。リテラル値の代わりに名前付き定数を使用することでコードのドキュメント化が楽になり、保守も容易になります。唯一例外として認められるのは0と1の使用です。ただし、文脈の中でその意味が明確な場合に限ります。たとえば、加算器フィールドを初期化したりカウンターを増やしたりする場合、0や1をソースコード中にハードコードしても構わないでしょう。
ビジネス固有の値に名前付き定数を使用する以外にも、IBMが提供している値を使うと良いでしょう。たとえば、事前に定義されている%Statusコードやキーストロークの16進数値は名前付き定数として宣言してください(/COPYメンバーに格納してください)。たとえば
On-error 1211:1218;
と記述する代わりに、以下のように書いたほうがずっとわかりやすいでしょう。
On-error Fileclosed : Recordlocked;
データ項目名を字下げして読みやすさとデータ構造のドキュメント化を容易にする。
RPGの他の多くのエントリと違って、定義された項目の名前はD仕様中で左揃えにしておく必要はありません。この機能の利点を利用して図5に示すようにコードのドキュメント化を容易にしてください。コードの読みやすさのために7カラム目は常に空白にしておいてください。
データ構造の宣言では位置記法ではなく長さ記法を使用する。
D仕様では、フィールドをコーディングする際にどこからどこまでという位置を指定する方法とフィールドの長さを指定する方法があります。一貫して長さ記法を使用することで混乱を避けることができ、フィールドのドキュメント化が容易になります。たとえば、
D Rtncode DS
D Packednbr 15P 5
と書く代わりに次のように書いてください。
D Rtncode DS
D Packednbr 1 8P 5
位置記法を使用するのはデータ構造内での実際の位置が重要な意味を持つときのみとしてください。たとえば、プログラム・ステータスのデータ構造やファイル情報データ構造、APIからの戻り値データ構造などをコーディングするときは、フィールドの特定の位置まで、あるいはフィールドとフィールドの間の特定の位置をプログラムが無視する場合に位置記法を使用することになるでしょう。ただし、使用していない位置を読み飛ばす場合でもフィラー変数を使用せずに長さ記法を使用することができます。次に示す例はデータ・エリアの最初の144個を読み飛ばしています。
D APIRtn DS
D 144
D Rtncode 15P 5
オーバーラップするフィールドを定義するときは位置記法ではなくOverlayキーワードを使用する。
Overlayキーワードは子供の変数の宣言とその親変数の宣言を明示的に結び付けます。Overlayはこの関係をドキュメント化するだけではなく、親の変数がプログラム・コード内の他の位置に移動した場合に子供の変数がそれについていくということを保証します。
共通のデータ構造は外部に記述する。
すべてのプログラムに渡って一貫性を保つには、以下の共通して使われるデータ構造は外部に記述してください。
- プログラム・ステータス・データ構造
- ワークステーション・ファイル情報データ構造(Infds)
- プリンタ・ファイル情報データ構造(Infds)
- データベース・ファイル情報データ構造(Infds)
上記のような複雑な構造も、一旦記述してしまえば2度と探す必要はありません。
コンパイル時配列は使用しない。
プログラムを個々のプロシージャに分解する際、すべての関連するコードの塊を物理的にも論理的にも自己充足型にしておくと便利です。従来のコンパイル時配列を使用してコーディングすると、配列の定義と配列データがプログラム中で何千という行を隔てて分離されてしまいます。プロシージャはローカルなスコープを持つコンパイル時配列をサポートしていません。配列をデータ構造内にコーディングするというより良い解決策を図6に示します。
データ構造を複数回記述しない。配列データ構造はプログラム中で標準の配列記法を使用しているので優れたコンストラクトといえます。また配列データ構造は同じ行中で1度しか処理できないという制限はなく、入れ子になった配列(多次元配列)が便利な場合も処理できます。
修飾データ構造を使用する。
修飾データ構造を使用すると、そのサブフィールド名をデータ構造の名前で修飾しなければなりません(たとえばCustomer.NameやCustomer.Addressなど)。この機能を利用するとデータ項目をきれいにドキュメント化できるだけでなく、異なるデータ構造間で全く同じサブフィールド名を使用することができます(たとえばBefore.NameとAfter.Nameなど)。修飾データ構造を定義するには定義中でQualifiedキーワードを使用します。
LikedsキーワードとLikerecキーワードもまた、データ構造がそのサブフィールドを他のデータ構造やレコード・フォーマットから継承する際に便利です。必要に応じて、*All、*Input、*Ouput、*Keyなどのフィールドを指定することで、Likerecデータ構造や外部で記述されたデータ構造中に表記されているサブフィールドを制御できます。
Templateキーワード(リリース6.1にあるキーワード)を使用すると、データ構造用の格納域を割り当てなくてもそのデータ構造を記述することができます。そしてこのテンプレートをLikedsデータ構造の親として使用することができます(しかしこれ以外の目的には使用できません)。プログラムのメモリのサイズを最小限に抑えるにはTemplateキーワードを使用してください。
プレフィックス・フィールド名を使用する。
リリース6.1では、外部記述ファイルのレコード・フォーマット用の修飾名を使用できるようにQualifiedキーワードをサポートしています。Input仕様とOutput仕様は修飾ファイル用には使用できませんし、生成もできませんので、すべてのファイル入出力命令は結果データ構造を使用しなければなりません(Likerecデータ構造は暗示的に修飾されています)。
修飾ファイルを使用していない場合は、ファイル仕様でPrefixキーワードを使用することでファイルからの個々のフィールド名を修飾することができます。
Fmyfile IF E Disk Prefix('MYFILE.')
上記のファイル中のフィールドはMyfile.Name、Myfile.Addressなどといったように参照できます。プレフィックス中にピリオド(.)を含めるにはプレフィックスをすべて大文字にして引用符で囲まなければなりません。
ファイル入出力には結果データ構造を使用する。ファイル入出力用の命令コード(CHAIN、READ、READE、READP、READPE、UPDATE、WRITE、EXFMT)は結果データ構造をサポートしています。命令用に結果データ構造をコーディングすると、システムはファイルとデータ構造間でデータを直接転送し、そのファイル用のInput仕様やOutput仕様は無視されます。実際、プログラム中のすべてのファイル入出力命令が結果データ構造を使用している場合、I仕様やO仕様は生成されません。結果データ構造の使い方を図7に示します。
リリース6.1では、RPGを使用するとプロシージャ内でファイルを宣言できます。つまりローカルなスコープを持つファイルです。ローカルなスコープを持つファイルはI仕様やO仕様を生成しませんので、入出力命令用の結果データ構造を使用しなければなりません。
名前の付け方の規約を拡張する
プログラミング・スタイルの最も重要な側面はデータ項目(たとえば変数や名前付き定数)やルーチンへの名前の付け方でしょう。従来の6文字を使った名前の付けの規約を拡張し、変数やその他の識別子を完全に識別できるようにしてください。この拡張した文字を使ってプログラム・コードとプログラムに関する記述との間で差をつけることができます。
項目に名前をつけるときはその項目を完全にしかも正確に表現する名前を付ける。
名前は曖昧さがなく、読みやすく、しかも明白なものでなければなりません。RPG IVで使える長い名前を利用しても構いませんが、長すぎて扱いにくい名前にならないようにしてください。通常は10文字から14文字の長さがあれば十分で、多くの仕様において長すぎる名前は実用的ではありません。
データ項目に名前を付けるときはその項目の意味を表現するようにしてください。戻り値のあるプロシージャに名前を付けるときは、戻り値にちなんだプロシージャ名とするか、またはそのプロシージャがデータ値を取得したりデータに値を割り当てたりする場合はget/setという名前付けの規約を利用してください。
戻り値のないサブルーチンやプロシージャに対しては動詞/目的語を組み合わせたの構文(CLコマンドと同様のもの)を使用してプロセスを記述してください。名前付けの規約を標準化するには名前、動詞、目的語のディレクトリを作って管理してください。
大文字小文字を混ぜて使い、特殊文字は使用しない。
RPG IVではコード中で大文字と小文字を使用できます。RPGの記号名をコーディングするときは大文字と小文字を組み合わせて使用し、名前を付けた項目の意味と使用方法を明確にしてください。また、項目に名前を付けるときは特殊文字(@、#、$など)を使用しないでください。こうした特殊文字の一部は、一部の文字セットでコンパイル・エラーの原因となるからです。RPG IVではアンダースコア(_)を名前の中で使用することができますが、大文字と小文字をうまく組み合わせればこのアンダースコアを使わずに簡単にできます。
標識のないコードを書く
歴史的に見ると、標識はRPG構文の特徴を識別するものでしたが、RPG IVでは急速にそれ以前の時代からの遺物となっています。プログラムで標識を使用する箇所を減らすことは、プログラムの読みやすさを向上させるために最も重要なことの1つです。
RPGのソースから数字付き標識を排除する。
RPG IVでは条件標識と結果標識を使用する必要性が完全に排除され、フリー・フォームの仕様ではこれらはサポートされていません。標識データ構造(INDDSキーワード)といくつかの組み込み関数のおかげで事前に定義された数字付き標識を使わないで済むようになりました。ファイル入出力の結果を%Eof関数や%Found関数で指し示すことができるということを覚えておいてください。エラーを取得するにはE命令エクステンダを使用しておいてから%Error関数と%Status関数の値をチェックします。
標識を使用しなければならない場合は名前をつける。
RPG IVでは標識と同じ目的を果たすBooleanデータ型(N)がサポートされています。INDDSキーワードと表示ファイル使用を組み合わせて使用することでデータ構造と表示ファイルまたは印刷ファイルの標識を関連付けることができます。こうすることで標識に対して意味のある名前を割り当てることができます。
使用する標識にはすべて記述を含める。
数字付き標識を使用しなくて済むようにはなりましたが、事前に定義された標識がいくつか残るかもしれません(たとえばL0-L9レベルのブレーク標識やU1-U8の外部標識など)。こうした標識はプログラムを読んだだけではその目的がはっきりしないので、ドキュメント化しておくことが重要です。プロローグ部分にそれをリストしておくと良いでしょう。
グループとループ
構造化プログラミングのテクニックを常に実践することで、そのコードを読む人がプログラムを理解できるようにしてあげてください。いわゆる構造化命令コードと呼ばれるIF、DOU、DOW、WHENなどはフリー・フォーマットの式をサポートしており、固定フォーマット時代のものより読みやすくなっています。一般的には、命令コードがフリー・フォーマットで記述できればフリー・フォーマットで記述してください。この規則はDO命令コードにも当てはまります。フリー・フォーマットのFOR命令の方が良い選択肢だからです。
フリー・フォーマットのRPGはGOTOやTAGをサポートしていませんが、ITERを使ってループの繰り返しを実行したり、LEAVEやLEAVESRを使用してそれぞれループやサブルーチンを途中で抜けたりすることができます。
SELECT/WHEN/ OTHER/ENDSLでマルチパスの比較を実行する。
入れ子が深いIFxx/ELSE/ENDIFコード・ブロックは読みづらく、入れ子のグループの終わり付近にENDIFが集まって不恰好になってしまいます。ELSEIFを使用すれば状況はいくらか改善されますが、通常はSELECT/WHEN/OTHERを使用したほうが良く、しかもその方が汎用的です。
文字列と事象
IBMはRPG IVの機能を大幅に強化し、文字列操作が容易になりました。RPGの以前のバージョンで使用しなければならなかったコツの多くはもはや過去のものとなっています。これらの新しい機能を活用してソースコードをモダナイゼーションしてください。
文字列定数を配列やテーブルに格納するのではなく、名前付き定数を使用して文字列定数を定義する。
文字列(たとえばCLコマンド文字列など)を名前付き定数として宣言することで、配列名やそのインデックスを介して文字列を参照するのではなく文字列を直接参照することができます。名前付き定数を使用してプログラムの実行中にその値が変わらないような値を宣言します。「謎の値は使わない」という忠告を思い出してください。
配列やデータ構造を使用せずに文字列やテキストを処理する。
その代わりに、新しい文字列操作関数や式を使用してください。
可変長フィールドを使用して文字列操作を簡素化する。
すべての文字列操作サブプロシージャのCONSTパラメータやVALUEパラメータ、およびと作業フィールドに対して可変長フィールドを使用してください。こうすることでコードが読みやすくなる(たとえば%TRIM関数をなくすことができる)だけでなく、固定長のフィールドを使用するより実行速度が速くなります。
コメントを賢く使う
良いプログラミング・スタイルというものは他人がソースコードを理解するのに役立つドキュメントとしての役割を果たします。コードを記述する際に良いテクニックを実践していると、ソースコードに書くコメントは少ない方がわかりやすいということに気づくでしょう。コメントを書きすぎるのはコメントが少なすぎるのと同じくらい良くないことです。コメントを書く際の具体的なガイドラインを以下にいくつか挙げます。
二重スラッシュ記号のコメントだけを使用する。
RPG IVでは従来の7カラム目にアスタリスク(*)を書く代わりに二重スラッシュ記号(//)で行を始めることでコメントを記述することができるようになりました。一般的に、コメントは8カラム目から80カラム目の間であればどこからでも書き始めることができ、フリー・フォーマットのコードでは既存の実行可能文と同じ行に書いても構いません。
コードを繰り返すのではなくコードの意味を明確にするコメントを書く。
コードに書かれていることを単に繰り返すだけのコメントはプログラムの量を増やすだけで価値はありません。一般的に、コメントは以下の3つの目的のためだけに使用してください。
- プログラムやプロシージャの簡単な要約を提供する
- サブルーチン、プロシージャ、その他のコード部分にタイトルを付ける
- ソースを読んだだけでは明白でないテクニックを説明する
プログラムやプロシージャの始まりには常に簡単な要約をつける。
このプロローグ部分には以下の情報を記載してください。
- プログラムまたはプロシージャのタイトル
- プログラムまたはプロシージャの目的の簡単な記述
- 変更日付、変更したプログラマ名、変更の目的などの変更履歴
- 標識の使用の要約
- プロシージャ・インタフェースの説明(戻り値とパラメータ)
- プロシージャの呼び出し方の例
一貫性のあるマーカー・ライン・コメントを使用してコードの主要なセクションを分割する。
たとえば、ダッシュ記号(-)の行を使用して宣言、メイン・プロシージャ、各サブルーチン、サブプロシージャを明確にセクション分けしてください。各セクションには簡単なリファレンスをつけて識別してください。
空行を使用して関連するソース行をグループにまとめてわかりやすくする。
一般的に、空白のコメント行ではなく完全に空白の行を使用してコードをグループにまとめます。ただし、コメントの塊を記述している場合を除きます。空行を複数行連続して使用するとプログラムが読みづらくなるので空行は1行としてください。
81カラムから100カラムに右寄せまたは行末のコメントは使用しない。
右寄せのコメントはコードを単に繰り返すだけのコメントになりがちで、プログラムの保守時になくなってしまったり、コメントしている行の内容とつじつまが合わなくなったりしやすいものです。特に、コメントをコードの中に記述できるようになったのですから、右寄せのコメントは記述しないでください。
陳腐化を避ける
RPGは古い言語です。さらに、40年も経たオリジナルの機能の多くは陳腐化しているにもかかわらずまだ利用可能です。しかしだからといってそれらの機能を使うべきだという意味ではありません。
既にコンパイル時配列や*Entry Plistなどいくつかの陳腐化したコンストラクトを使用しないように説明しましたが、これに関するガイドラインをいくつか加えておきます。
陳腐化した命令コードを排除する。
陳腐化した命令コードをどのように見つければよいのでしょう。その答えは簡単です。その命令コードがフリー・フォーマットの仕様でサポートされていなければそれは陳腐化した命令コードです。GOTOとTAGを例外とすれば、陳腐化した命令にはすべて代替えの命令があります。陳腐化した命令の代わりに代替えの命令を常に使用してください。
一部の命令コードでは、命令コードを関数で代用し、式の中で関数を使用することができます。命令コードと同じ機能を提供していれば関数の方を使用することをお勧めします。
プログラム記述ファイルを使用しない。
外部定義ファイルが利用可能であれば外部定義ファイルを使用してください。
ネイティブ日付データ・タイプを使用して日付を操作する。
長年にわたって収集し、懸命に守ってきた日付と時間を処理するための賢いルーチンを捨ててください。RPG IVの日付関連関数の方がずっと効率的で、わかりやすく、モダナイゼーションされています。データベース中にレガシーなフォーマットの日付が含まれている場合でも、日付関数(%Date、%Diff、%Subdt、%Daysなど)を使用して日付を操作してください。
2進数ではなく整数を使用する。
RPG IVは整数(データ・タイプI)と符号なし整数(データ・タイプU)を直接サポートするようになりました。2進数(データ・タイプB)の代わりにこれらのデータ・タイプを使用してください。2進数は陳腐化したものとされています。整数は2進数と同じ内部表現を使用していますが、整数の方が柔軟性や互換性が高く、実行も高速です。
整数は3桁、5桁、10桁、20桁でそれぞれ1バイト、2バイト、4バイト、8バイトで格納されます。整数はゼロ小数点位置で定義しなければなりません。
1~5カラムにプログラムの行番号を並べない。
もうパンチカードの束を落としたりはしないでしょうから、プログラムの行番号エリアは不要です。RPG IVでは、このカラムはコメント用のみに使用されています。プログラム中で行が変更になったことや字下げレベルの構造を識別するためにこのカラムを使用しても構いませんが、右寄せのコメントと同様の罠にはまるかもしれません。
その他のガイドライン
RPG IVのコードを改善するのに役立つその他のスタイル・ガイドライン集を以下に記載します。
プログラミングの芸当を使用しない。
芸当を使ったプログラミングはその芸当を知らない他の人にとっては賢明なものではありません。コードの集合がどのように動作するのかをコメントで追加する必要があると思ったら、コードの目的が明確になるように書き換えるか、またはコードの複雑さをプロシージャの中に隠蔽するか、どちらかにしてください。曖昧なビット操作関数(%Bitand、%Bitnot、%Bitor、%Bitxorなど)を使用するのは、コードがわかりやすくなっていないことの兆候かもしれません。
キーワードをサポートしているすべての仕様ではキーワードは1行に1個という制限を守る。
仕様全体に渡って複数のキーワードや値を散らばせるのではなく、キーワードは1行に1個、あるいは少なくとも密接に関連したキーワード(たとえばDATFMTとTIMFMTなど)だけを使用するという制限を守ればプログラムは読みやすく、扱いやすくなります。
H仕様のキーワードは8カラム目から始めて7カラム目は空白にする。
キーワードと6カラム目で必要とされるH仕様を分離することで読みやくなります。
最後のアドバイス
良いプログラミング・スタイルと効率的な実行時性能は必ずしも相容れない場合があります。これらの間で競合が生じたときはいつでも、良いプログラミング・スタイルの方を選択してください。読みづらいプログラムはデバッグが難しく、保守も容易ではなくて、正しく動作するプログラムになりづらくなってしまいます。プログラムの正確さは常にその実行速度よりも優先されなければなりません。ブライアン・カーニハンとP.J.プラウガーが「The Elements of Programming Style」(McGraw-Hill, 1978)の中で書いた以下の忠告を常に頭において置いてください。
- まず正しく動作するようにしてから速くする
- 速くするときは正しく動作することを維持する
- まずわかりやすいコードにしてから速くする
- 効率を少しだけ向上させるためにコードの明確さを犠牲にしない