AsaHP
Top > 高品質・高速な開発のためのソフトウェア方法論

モジュール分割


ソフトウェアが中規模以上になるとモジュール分割が必要になる。主に可読性向上と共通化による開発量削減の目的で行われる。

処理をだらだらと書くのは絶対に避けなければならない。処理全体をまとめて作成し、同時に共通化やモジュール分割を行うべきだ。

各モジュールの関連性は低い方がいいと言われるが、必ずしも正しくない。関連性が低いと開発効率や実行速度の点で悪影響がある。関連性の強さは階層的であり、機能が近ければ強く、遠ければ弱くすべきだ。

関数に対しては凝集度と結合度という評価基準がある。関数内部での凝集度は高く、関数外部の結合度は低い方がいい。凝集度を関数内部の関連性、結合度を関数外部の関連性と考えると、関数内部は関連性を強く、関数外部は関連性を弱くした方がいい。関数は機能に基づいてまとめるのが最も凝集度が高くなる。

中規模以上のソフトウェアではモジュール分割は階層的に行われる。上記の凝集度と結合度は関数のみだが、実際には関数による分割、クラスによる分割、ライブラリによる分割、実行ファイルによる分割など様々な分割階層が存在する。細かい階層なら関連性は強く、荒い階層なら関連性は弱くなる。これらも機能面からの分割が必要である。

機能の正しい理解が必要で、データや処理のすべてを機能面から理解しなければならない。単にデータや処理を羅列するのでなく、それらの目的や意味を理解する必要がある。これは困難な作業であり、開発中は常に機能を検討し続けなければならない。

処理速度が問題になる場合には、ループ回数が多く速度のネックになる場所でのモジュール分割を避けなければならない。これは単純な処理回数のみの問題であり、機能に基づくモジュール分割を多少犠牲にする必要がある。

現在ではAPIやアドインなどの外部連携が非常に必要になっており、すべての製品やサービスにおいて検討した方がいい。高度な外部連携だと難解な動作になり、作成も利用も高度な技術力が必要になる。

開発が小規模の場合、モジュール分割はそれ程重要ではない。しかし規模を増やそうとすると行き詰るので最初から考慮すべきだ。

サブルーチン・関数・ソースファイル・クラスについて詳細な説明書を作るのは過剰である。ソースの可読性を上げて対応する方がいい。細かく書類を書いても修正により実態と合わなくなり意味がない。

データの整理


十分な検討と整理の継続が情報処理の実務の根幹となる。モジュール分割をする際もまずこの点を注意すべきだ。

モジュール分割は処理よりもデータを中心に行うべきだ、データと処理は強く関係しており、データの方が少ないので整理しやすい。

各プログラム言語ごとのメモリと変数方式を良く理解する必要がある。データごとの影響範囲を理解する事は必須である。ローカルとグローバルの変数を適切に分けないと扱いにくいデータ構造になる。

処理を書く前に必要な変数は分かる。その時点で各変数がどこまでの範囲で必要なのかを考える。必要最小限の範囲で各変数を扱うように配置すれば、特定の処理内で扱われる変数の数を減らす事ができる。この配置には下記のサブルーチン・関数・ソースファイル・クラスなどの分割を含む。その後で各変数を扱う処理を書けば容易にモジュール分割ができる。

データだけでなく処理の整理も必要だが、データの整理後に行った方がやりやすい。

同一のデータが数カ所にバラバラに存在する状況は避けるべきだ。処理も複雑になるしバグも起こりやすい。どうしても複数個所に置く必要がある場合は、同一構造にするなどして一括でコピーする方法を考えるべきだ。

サブルーチンと関数


サブルーチンは処理の一部分を別の個所に切り出したもので、最も基礎的なモジュール分割方法である。関数はこれにパラメータと戻り値を追加したもので、コールスタックと言う仕組みで実装される。

特に開発量削減において有効である。同一の処理はできる限り同じサブルーチンや関数にまとめるべきだ。一見同じ処理をしていないと思われる場合でも、機能的に同じであれば処理を工夫する事でまとめられる可能性がある。データの種別を示すIDや配列はまとめる際に有用だ。

長い処理を単に短くするために分けるのでなく、機能を考慮して分ける必要がある。どんな機能があるかを把握し、機能ごとに分けないと扱いにくくなる。

同一のデータを扱うサブルーチンや関数は近くに置くべきだ。オブジェクト指向ならクラスを使い、そうでない場合は同じソースファイルにまとめるのがいい。扱うデータの形式(クラスや構造体など)を同じにする事も有効だ。

関数呼び出しは明確に処理速度が落ちる。これを避けるためにC++ではインライン関数が用意されている。処理速度が問題になる場合は利用すべきである。

ソースファイル


ソースファイルの分割も重要だ。純粋なモジュール分割ではないが、分割管理するという意味では同じである。

長大なソースファイルは可読性が落ちるので、可読性向上において有効である。内部がサブルーチンや関数に分かれていても、ソースが長大だと関連性がわからなくなる。

サブルーチンや関数の上位階層になり、機能の近いサブルーチンや関数でまとめる。

オブジェクト指向の場合はサブルーチンや関数がクラスでまとまっている。ソースファイルには機能の近いクラスをまとめて入れる。あまり大量のクラスを入れると可読性が落ちる。

ソースファイルごとにアクセス可能なデータを分けると、マルチスレッドなどでデータアクセス規制をする時の管理が楽になる。C/C++ならばヘッダファイル中にデータアクセス手段をまとめてしまえば、そのヘッダを使わないアクセスは発生しなくなる。

ソースファイルが膨大な数になる場合、ソースファイルを階層的なフォルダに入れるのも分割効果がある。コンパイラやリンカの指定により直接ビルドすればいい。

クラス


クラスはオブジェクト指向によりデータと処理をまとめた構造である。オブジェクト指向でない場合よりモジュール分割は容易になる。

クラスを作ればモジュール分割がうまくいくという事ではない。クラスの内容に機能的な不整合があれば意味のないモジュール分割になる。

クラス作成時は内部データを隠蔽して抽象化する方法が用いられる。過度にこれを行うと逆に可読性が悪化し開発量が増大する可能性がある。実行速度が問題になる場合は速度低下も注意しなければならない。

クラスにはpublicやprivateなどのアクセス制限があるが、これらの検討よりもクラスの機能について検討する方が重要である。publicとprivateを開発途中で切り替える事は容易だが、機能を途中で切り替えるのは容易でない。

クラスが大量にある場合には、クラスごとの関連性も重要になる。クラスをまとめるための別クラスを作り、そこから他のクラスへアクセスするなどの手段が必要になる。継承が有効な手段になる。GUI上の表示物のように同じ機能を有するクラスを継承でまとめれば、管理するクラスは親クラスだけを処理すれば済む。

ライブラリ


複数のサブルーチンや関数やクラスをコンパイル後にまとめたファイルがライブラリである。コンパイル後のファイルであるため、他者にファイルを渡すのが楽になる。渡すファイルが少なく、ソースを読まれる可能性もなく、誤って修正される可能性もない。

C/C++の場合には静的ライブラリと動的ライブラリがある。静的ライブラリはビルド時にリンクされ、動的ライブラリは実行時にリンクされる。Javaは動的ライブラリのみである。静的ライブラリはソースファイルに近い特徴を持ち、動的ライブラリは実行ファイルに近い特徴を持つ。実行時に入れ替えでき動的ライブラリの方が関連性は低くなる。

動的ライブラリは実行時に変更できるため、コンパイル時に想定したライブラリ以外が実行されるとうまく動かない場合がある。動的ライブラリが必要である事を依存と呼ぶ。依存関係は実行時に整理さている必要がある。

ライブラリを外部から使用する際には、仕様機能を制限して外部との依存性を低くする必要がある。すべての関数が外部から使用可能だとライブラリ化する意味がなく、逆に管理しにくくなる可能性もある。通常の関数から一段階区切った管理方法を取るべきである。C/C++の場合はライブラリ関数を定義した外部用のヘッダを用意すると管理しやすい。Javaの場合はinterfaceという外部化用のクラスがある。

WindowsやLinuxなどのOSでは、機能の大半を動的ライブラリで実装している。OSのフォルダを探すとdllまたはsoという拡張子の付いた動的ライブラリが大量に見つかる。これらのファイルはOS自体が依存関係を管理しているので、同名の動的ライブラリを別の所から持って来るとうまく動かない場合がある。

ライブラリを利用者から使えるようにする場合には説明書が必要になる。利用者が社内でソースを理解できる場合にはソースで代用してもかまわない。ヘッダなどに細かいコメントを書き込めば済む場合もある。

APIとアドイン


直接的な関係のない相手にライブラリを渡す場合、外部から利用できる関数群をまとめ、その説明書も渡す必要がある。この関数群をAPIと呼ぶ。自分が対応できない相手に渡すので、問題が起こらないか、起こっても対応できるような形でまとめる必要がある。APIの説明書は辞書のようなものであり、正しい使い方を網羅しなければならない。使い方をわかりやすくするにはサンプルや別の文書を添付する。網羅的な説明書なしで概要の説明書のみを渡すと、細かい機能の利用や問題発生時の対処ができなくなる。

APIはライブラリで実装される事が多いが、そうでない場合もある。スクリプトなどではソースファイルごと渡す事になる。

逆に実行ファイルが任意の動的ライブラリを呼び出せるようにしたものをアドインと呼ぶ。アドオンやプラグインと呼ばれる場合もある。任意の動的ライブラリを呼ぶために特殊な実装方法が必要になる場合がある。APIとは逆に、利用者が説明書に合わせてライブラリを作成する。これもライブラリでない場合がある。

APIとアドインは関連性が低く独立性が高い上に様々な機能を実現できる。実行速度も遅くならない。製品やサービス同士の連携において特に重要である。

大規模な開発の場合は各担当チームごとにAPIを作成する場合がある。全体の共通部品を作る場合、そのAPIの性能が全体の性能を大きく左右する。最も技術力の高い担当者に集中して開発させるべきである。

高度な実装ではスクリプト言語そのものを製品の一部とする場合もある。スクリプト言語が製品と連動するため、APIやアドインよりも簡単に複雑な処理を作成できる。ただしスクリプト言語の実装にはかなりの開発工数が必要になる。

実行ファイルと通信


実行ファイル自体も他の実行ファイルと連動できる。関連性の低いモジュール分割である。連動には標準入出力やファイルやメッセージを利用する。関数経由でないので複雑な連動は難しい。

関連性が低いので、多くの開発者が並行して作成するには適している。品質の悪いものが混ざっても他への影響が出にくい。製品全体を管理する実行ファイルを作る場合は、APIと同じように最も技術力の高い担当者を選ぶ必要がある。

ライブラリのような柔軟性がないので、何らかの方法で実行ファイルを制御する仕組みが必要になる。GUIの場合は画面、CUIの場合はコマンドオプションを利用する。設定ファイルはどちらの場合でも有効な手段である。

ある程度規模が大きい開発だと、実行ファイルやライブラリが複数になる。実行ファイルや入出力ファイルなどの適切な管理が重要になる。資料も含め1か所にまとめて管理し、説明書を作るべきである。最初にしっかりやっておけば大した手間にはならない。処理の内容説明書だけで実行ファイルなどの説明書がないと管理できなくなる可能性がある。

外部ツールなどを使う場合、誰が何のために作ったかや、権利などを明確にしておく必要がある。曖昧だと管理上だけでなく権利面からも問題が発生する。

最近ではHTTP通信により外部連携する場合も増えてきた。実行ファイルよりさらに関連性が低い。HTTP通信用のツールが広まっているため実装も比較的容易である。これも説明書がないと管理が難しくなる。専用ツールが利用できればHTTP以外の通信も考えられる。

Top > 高品質・高速な開発のためのソフトウェア方法論