このページでは、STS分割・TR分割・ジャクソン法などのモジュール分割技法、モジュール結合度と強度の順番、制御領域と影響領域、コード設計がわかります。
- 一言で言うと:
- プログラムをどう小分け(モジュール分割)するかと、その小分けがうまくできているかをどう評価するかの話
- 良いモジュールは、「他とのつながりは弱く(結合度が弱い)、中のまとまりは強い(強度が強い)」
どう分けるか(分割技法)→ うまく分けられたか(分割の評価)→ コードの付け方(コード設計)
覚え方の軸
- 分割技法は「データの流れ」か「データの構造」かで2つに分かれる
- 流れに注目するのは、STS分割(入力 → 変換 → 出力の3つに分ける)、TR分割(データの種類で枝分かれさせる)、共通機能分割(共通の機能を1つにまとめる)
- 構造に注目するのは、ジャクソン法(出力のデータ構造から)、ワーニエ法(入力のデータ構造から、「いつ、どこで、何回」)
- 評価の物差しは2つで、向きが逆
- 結合度(モジュールの外とのつながり)は、弱いほど良い
- 強度(モジュールの中のまとまり)は、強いほど良い
- どちらも、良い方向に行くほど独立性が高い
- 一番良いものと一番悪いものを押さえる
- 結合度は、一番良いのがデータ結合、一番悪いのが内容結合
- 強度は、一番良いのが機能的強度、一番悪いのが暗合的強度
- 橋渡しの1組
- 引数で機能を選ばせるモジュールは、強度では論理的強度、結合度では制御結合にあたる
- 領域評価は「制御領域 ≧ 影響領域」なら良い
- 自分の決定の影響が、自分の手下(制御領域)の中に収まっていればよい
モジュール分割技法:どう小分けにするか(★)
- モジュール分割技法の2分類:
- データの流れに着目した分割技法と、データの構造に着目した分割技法の2つに大きく分かれる
| 着目点 | 技法 | 一言で |
|---|---|---|
| データの流れ | STS分割 | 入力・変換・出力の3つに分ける |
| データの流れ | TR分割 | 入力データの種類ごとに、処理を枝分かれさせる |
| データの流れ | 共通機能分割 | 共通する機能を、1つの共通モジュールにまとめる |
| データの構造 | ジャクソン法 | 出力データの構造から、プログラム構造を作る |
| データの構造 | ワーニエ法 | 入力データの構造から、「いつ、どこで、何回」で展開する |
① STS分割:入力・変換・出力の3つに分ける
- STS分割:
- データの流れに着目した分割技法
- 基本的なプログラムは「入力・処理(変換)・出力」という構造を持つことに注目する
- プログラムを、入力処理機能(源泉:Source)、変換処理機能(変換:Transform)、出力処理機能(吸収:Sink)の3つのモジュールに分ける
- 頭文字を取って、S・T・S
- 分割の基準:
- どの点で分けるかが重要
- 最大抽象入力点:
- もはや入力とはいえない点。つまり、これ以降は入力データが発生しない点
- 最大抽象出力点:
- はじめて出力データといえる点
- 制御モジュール:
- STSの3つのモジュールに分けたあと、モジュールの階層構造図を作る
- このとき、3つのモジュールを制御する制御モジュールを定義する必要がある
- 例(郵便番号から住所を表示するプログラム):
- 流れは、「郵便番号を読み取る」→(最大抽象入力点)→「住所データベースを検索する」→「住所を得る」→(最大抽象出力点)→「住所を画面に表示する」
- 源泉モジュール(S)は「郵便番号を読み取る」
- 変換モジュール(T)は「住所データベースから住所を得る」
- 吸収モジュール(S)は「住所を画面に表示する」
- その上に、3つをまとめる制御モジュールを置く
- STS分割の例え:
- 料理なら、「食材を受け取る」(源泉)→「調理する」(変換)→「盛り付けて出す」(吸収)に分け、料理長(制御モジュール)が全体を指示する
② TR分割:データの種類で枝分かれさせる
- TR分割(トランザクション分割):
- データの流れに着目した分割技法
- 入力トランザクションの種類によって、実行する処理が違う場合に有効
- データが種類によって分岐していく点に注目して分割する
- 例(在庫ファイルの更新):
- 入庫・出庫・返品の伝票を個別に入力し、在庫ファイルを更新するプログラム
- 「伝票入力処理」(入力モジュール)→「伝票の種類で振り分ける」(振分けモジュール)→「入庫の処理」「出庫の処理」「返品の処理」(処理ごとのモジュール)→「在庫ファイル更新」
- TR分割の例え:
- 郵便局の窓口。届いた用件(トランザクション)が「送る」「受け取る」「振り込む」のどれかで、担当の窓口に振り分ける
③ 共通機能分割:共通の機能を1つにまとめる
- 共通機能分割:
- STS分割やTR分割で分けたモジュールの中に共通する機能があったり、プログラム全体で共通して必要な機能があったりする場合
- その機能を1か所にまとめ、共通モジュールとして独立させる方法
- 共通機能分割の効果:
- 開発効率や、保守・拡張性を高められる
- 例:
- 注文を登録するモジュールP、注文を取り消すモジュールQに、処理の前に「利用者の権限をチェックする」機能を追加する
- 各モジュールに実装するのではなく、共通モジュールR(権限をチェックする)を作り、PからもQからも呼び出して使う
- アスペクト指向プログラミング(AOP:Aspect Oriented Programming):
- 注目されているプログラミング技法の1つ
- 共通モジュールRの呼出処理を各モジュールに書くのではなく、「権限チェック」をアスペクト(横断的関心事)として、呼び出し方などを宣言する
- そうすると、すべてのモジュールに「権限チェック」を織り込むことができる
- アスペクト:
- いろいろな場所で実行することがある共通処理(横断的関心事)のこと
- AOPのイメージ:
- 別の場所に「注文を操作する前にモジュールRを呼び出す」と宣言しておく
- モジュールP、Qには「注文を登録する」「注文を取り消す」とだけ書けばよく、Rを呼び出す処理は書かない
- 共通機能分割とAOPの例え:
- 共通機能分割は、各部屋に「出るときは電気を消す」と貼り紙をする(各モジュールに呼出しを書く)
- AOPは、家全体に人感センサーを付けて、部屋を出たら自動で消えるようにする(呼出しを書かずに織り込む)
④ ジャクソン法:出力のデータ構造から作る
- ジャクソン法(JSP:Jackson Structured Programming):
- データ構造に基づいて分割を進める構造化設計技法
- 「プログラムの構造は、入力と出力のデータ構造から必然的に決まる」という考え方
- 入力と出力のそれぞれの構造を、基本・連続・繰返し・選択の4つの要素を組み合わせた階層的な木構造(JSP木)で表し、対応させる
- そのうえで、出力データ構造を基本形としてプログラム構造を作る
| 要素 | 書き方 | 意味 |
|---|---|---|
| 基本 | Aだけ | それ以上分けない要素 |
| 連続 | Aの下にB、C | BとCが(順に)実行される |
| 繰返し | Aの下にB* | Bが0回以上繰り返される |
| 選択 | Aの下にB°、C° | BとCのどちらかが選ばれる |
- 記号の覚え方:
- *(アスタリスク)は繰返し、°(小さな丸)は選択
- 入力の木:
- 入力データ構造を表したJSP木
- 出力の木:
- 出力データ構造を表したJSP木
- プログラムの木:
- 入力の木と出力の木を対応させて作る、プログラム構造を表したJSP木
⑤ ワーニエ法:入力のデータ構造から作る
- ワーニエ法:
- 集合論に基づく構造化設計技法
- 入力データ構造をもとに、「いつ、どこで、何回」という考え方で、プログラム全体をブレイクダウン(展開)していく
- ジャクソン法との違い(ひっかけ注意):
- ジャクソン法は、主に出力データ構造をもとにする
- ワーニエ法は、入力データ構造をもとにする
- プログラムの基本論理構造:
- 「スタート部」「処理部」「エンド部」の部分集合でできている
- 構造の例:
- プログラム(全体集合)は、スタート部(1回)、処理部1(n回)、エンド部(1回)でできている
- 処理部1の中は、さらに処理スタート部(1回)、処理部2(m回)、処理エンド部(1回)に分かれる
- 例えば、売上集計なら、スタート部で「合計を0にする」(1回)、処理部で「1件ずつ足す」(n回)、エンド部で「合計を印刷する」(1回)
モジュール分割の評価:うまく分けられたか(★試験によく出る)
- 評価の3つの観点:
- 構造上の評価(大きさ、インタフェース)
- 独立性の評価(モジュール結合度、モジュール強度)
- 領域評価(制御領域と影響領域)
① 構造上の評価
- 構造上の評価:
- 複雑なプログラムは、複数のモジュールに分けると、わかりやすく保守しやすくなる
- しかし、1つのモジュールに機能が多すぎたり、モジュール間インタフェースが複雑だったりすると、効果が薄れる
- そのような観点から、モジュールが適切に分けられているかを評価する
- モジュールの大きさ:
- 原則として論理的な単位で分け、できるだけ1つの機能を持った独立性の高いものにする
- ただし、小さすぎると管理が煩雑になるので、その場合は下位モジュールを上位モジュールなどに組み込むことを考える
- モジュール間インタフェース:
- 上位モジュールと下位モジュールのインタフェースは、必要最小限に抑えるなどして、モジュール結合度を弱くする
- 下位(上位)モジュールの変更が、上位(下位)モジュールに影響しないようにする
- モジュール構造図の形:
- 「モジュール構造図は、ピラミッド型を経てモスク(回教寺院)型になる」という、形による評価基準もある
- モスク型は、下のほうに共通モジュールがあり、複数の上位モジュールから呼ばれて、下が少しすぼまった形になる
② 独立性の評価
- 独立性:
- 互いに関連し合うモジュールどうしが、相手のモジュールの影響をできるだけ受けないという特性
- 独立性が高いと良いこと:
- 関連するモジュールが修正されても、影響が少なくて済む
- 保守の効率化と、保守コストの削減につながる
- プログラム開発(製造)でも、並行作業がしやすくなる
- 独立性を評価する尺度:
- モジュール間の関連の強さを示すモジュール結合度
- モジュール内の構成要素間の関連の強さを示すモジュール強度(結束性)
モジュール結合度(6種類。弱いほど独立性が高い)
| 順位 | 結合度 | 中身 | 例え |
|---|---|---|---|
| 強い(悪い) | 内容結合 | 絶対番地を使って直接相手モジュールを参照したり、JUMP命令で相手モジュールに直接分岐したりする | 他人の家に勝手に上がり込んで、冷蔵庫を開ける |
| ↓ | 共通結合 | 大域領域に定義されたデータを参照する | 町内の共有掲示板を、誰でも書き換えられる |
| ↓ | 外部結合 | 大域領域に必要なデータだけを外部宣言し、他のモジュールからの参照を許して共有する | 掲示板のうち、決めた項目だけを共有する |
| ↓ | 制御結合 | 機能コードなど、モジュールを制御する要素を引数で渡し、相手のモジュール内の機能や実行を制御する。モジュール強度の論理的強度にあたる | 「今日は1番の仕事をして」と、相手の仕事内容まで指図する |
| ↓ | スタンプ結合 | 相手が構造体データ(レコード)の一部しか使わない場合でも、構造体データをすべて引数で渡す | 住所だけ知りたい人に、住民票をまるごと渡す |
| 弱い(良い) | データ結合 | 相手モジュールをブラックボックスとして扱い、必要なデータだけを引数で渡す | 住所だけ知りたい人に、住所だけを伝える |
- 大域領域:
- どのモジュールからでも共通に参照できる領域
- グローバル領域、共通領域ともいう
- 試験での出方(試験):
- モジュール結合度が最も弱い(独立性が最も高い)のはデータ結合、が問われる
- 結合度の順番の覚え方:
- 強い順に「内容・共通・外部・制御・スタンプ・データ」
- 「ない(内)きょう(共)、がい(外)せい(制)、スタンプ、データ」と唱える
- 相手の中身に直接触る(内容)→ みんなの領域を共有する(共通・外部)→ 引数で相手を操る(制御)→ 引数で余計なものまで渡す(スタンプ)→ 引数で必要なものだけ渡す(データ)
モジュール強度(結束性)(7種類。強いほど独立性が高い)
| 順位 | 強度 | 中身 | 例え |
|---|---|---|---|
| 弱い(悪い) | 暗合的強度 | プログラムを単純に分割しただけで、モジュールの機能を定義できない。または、複数の機能を持つが、機能間にまったく関連はない | 引き出しに、文房具・薬・電池をごちゃまぜに入れる |
| ↓ | 論理的強度 | 関連した複数の機能を持ち、呼び出すときの引数(機能コード)で、モジュール内の1つの機能が選ばれて実行される。モジュール結合度の制御結合にあたる | 番号を押すと、お茶かコーヒーかジュースが出る自販機 |
| ↓ | 時間的強度 | 初期設定や終了設定モジュールのように、特定の時期に実行する機能をまとめたもの。機能間にはあまり関連はない | 朝にやることリスト(歯みがき、天気を見る、ゴミ出し) |
| ↓ | 手順的強度 | 順番に(逐次的に)実行する複数の機能をまとめたもの | 掃除の手順:机を拭く → 床を掃く → ゴミを捨てる(順番は決まっているが、同じデータを受け渡してはいない) |
| ↓ | 連絡的強度 | 手順的強度のうち、モジュール内の機能間にデータの関連性があるもの | 計算した結果を、すぐ次の処理で使う |
| ↓ | 情報的強度 | 同一のデータ構造や資源を扱う機能を1つにまとめ、機能ごとに入口点と出力点を持つもの | 「口座」に対する入金・出金・残高照会を、1つにまとめる(オブジェクトに近い) |
| 強い(良い) | 機能的強度 | 1つの機能だけからなるもの | 「消費税を計算する」だけをする |
- データの関連性がある:
- 同じデータを参照するという意味
- 試験での出方(試験):
- それぞれのモジュール強度について、具体的なモジュールのイメージができるようにしておく
- 強度の順番の覚え方:
- 弱い順に「暗合的・論理的・時間的・手順的・連絡的・情報的・機能的」
- 「暗(あん)い論(ろん)理の時(じ)間に、手(て)順を連(れん)絡、情(じょう)報で機(き)能する」と覚える
- 関係ない(暗合的)→ 似た仲間を引数で選ぶ(論理的)→ 同じ時期(時間的)→ 順番(手順的)→ 順番+同じデータ(連絡的)→ 同じデータ構造(情報的)→ 1つの機能(機能的)
- 補足:
- 暗合的強度は、「偶発的強度」と呼ばれることもある
例:2つのモジュールを比べる
- ファイル操作モジュール:
- 「読み込む」「書き込む」の2つの機能を1つにまとめ、引数でどちらの機能を使うかを指定する
- 論理的強度(モジュール結合度では制御結合)
- 成績集計モジュール:
- 必ず「合計を計算する」→「平均を計算する」の順に実行され、しかも合計の結果を平均の計算で使う、2つの機能を1つにまとめる
- 連絡的強度
- 比べると:
- 連絡的強度のほうが強いので、成績集計モジュールのほうが独立性が高い
- 例題(結合度):
- ①顧客レコードをまるごと渡し、相手は郵便番号だけを使う
- ②「1なら新規登録、2なら削除」という機能コードを引数で渡す
- ③税抜価格だけを引数で渡し、税込価格を返してもらう
- それぞれ何結合か。また、独立性が一番高いのはどれか
- 例題の答え:
- ①はスタンプ結合、②は制御結合、③はデータ結合
- 独立性が一番高いのは、結合度が一番弱い③データ結合
③ 領域評価
- 領域評価:
- モジュールの制御領域と影響領域を評価すること
- 制御領域:
- そのモジュールが制御する範囲
- モジュール自身と、それに従属する(下にぶら下がる)モジュール
- 影響領域:
- あるモジュールの中での決定が影響を及ぼす範囲
- 例:
- モジュールPの下にQ、R、Tがあり、Qの下にU、Rの下にSがある
- Rの制御領域は、R自身と、従属するS
- R内で決定した判断をPに渡し、PがTを実行するかどうかを制御する場合、Rの決定の影響領域はP、Tに及ぶ
- 影響が制御領域の外にはみ出しているので、「制御領域<影響領域」になっている
- 良い・悪いの判断:
- 「制御領域 ≧ 影響領域」なら良い
- 「制御領域<影響領域」なら、モジュールの独立性が低くなっているので、改善が必要
- 領域評価の例え:
- 係長(R)が自分の部下(S)に指示を出すのは問題ない
- しかし、係長の判断で、部長(P)が別の課(T)の仕事を止めるかどうかが決まるのは、権限の外まで影響が及んでいて良くない
コード設計(時々出る)
- コード設計:
- 処理効率の向上とデータの体系化のために、使う目的に合ったコード体系を設計すること
- 外部設計の重要な作業の1つ
- 例えば、商品コード、社員番号、顧客番号の付け方を決めること
- コード設計の大まかな流れ:
- コード化する対象を選び、コード化の目的をはっきりさせる
- 使用期間とデータ件数を予測する
- コード体系を決める
- コード化作業をして、コード表を作る
- コードファイルを作る
| コードの種類 | 付け方 | 長所 | 短所 |
|---|---|---|---|
| 順番コード(連番コード、シーケンスコード) | データの発生順、または一定の順に並べて、順番に番号を付ける | 少ない桁数でコード化できる。発生順に付けるなら追加が簡単 | 件数が予想以上に増えると、桁数が足りなくなるおそれがある。分類がわからない |
| 区分コード(分類コード) | データをいくつかのグループに分け、グループごとに番号の範囲を割り当て、その中で連番を付ける | 少ない桁数で多くのグループ分けができる | データを追加する場合や件数が多い場合に不便 |
| 桁別コード | データを大分類・中分類・小分類と階層化し、それぞれの層の中で連番を付ける | 分類基準がはっきりしている。各桁が分類上の意味を持つのでわかりやすい | 桁数が大きくなりやすい |
| 表意コード(ニモニックコード) | 商品の略称や記号などをコードにする | コードの値から対象物を連想でき、覚えやすい | 分類には不便 |
- コードの例:
- 順番コードは、「0001、0002、0003…」
- 区分コードは、「001〜099は文房具、100〜199は食品」
- 桁別コードは、「1-2-05」(1桁目が大分類、2桁目が中分類、残りが小分類)
- 表意コードは、「TV-42-LCD」(42型の液晶テレビ)
混同しやすいペア
- データの流れに着目 / データの構造に着目
- データの流れに着目するのは、STS分割、TR分割、共通機能分割
- データの構造に着目するのは、ジャクソン法、ワーニエ法
- STS分割 / TR分割
- STS分割は、入力・変換・出力の3つに分ける
- TR分割は、入力トランザクションの種類で処理を枝分かれさせる
- 最大抽象入力点 / 最大抽象出力点
- 最大抽象入力点は、これ以降は入力データが発生しない点
- 最大抽象出力点は、はじめて出力データといえる点
- 源泉(Source) / 変換(Transform) / 吸収(Sink)
- 源泉は、入力処理
- 変換は、処理(変換)
- 吸収は、出力処理
- 共通機能分割 / アスペクト指向プログラミング(AOP)
- 共通機能分割は、共通モジュールを作り、各モジュールから呼び出す処理を書く
- AOPは、呼出し方を宣言して、呼出しを書かずに全モジュールに織り込む
- ジャクソン法 / ワーニエ法
- ジャクソン法は、出力データ構造をもとにする(JSP木:基本・連続・繰返し・選択)
- ワーニエ法は、入力データ構造をもとに「いつ、どこで、何回」で展開する(集合論:スタート部・処理部・エンド部)
- JSP木の繰返し / 選択
- 繰返しは、*を付ける(0回以上)
- 選択は、°を付ける(どちらか一方)
- モジュール結合度 / モジュール強度
- 結合度は、モジュール間の関連の強さ。弱いほど良い
- 強度は、モジュール内の関連の強さ。強いほど良い
- 内容結合 / データ結合
- 内容結合は、絶対番地やJUMP命令で相手に直接触る。最も強く、最も悪い
- データ結合は、必要なデータだけを引数で渡す。最も弱く、最も良い
- 共通結合 / 外部結合
- 共通結合は、大域領域のデータを参照する
- 外部結合は、大域領域に必要なデータだけを外部宣言して共有する
- スタンプ結合 / データ結合
- スタンプ結合は、一部しか使わなくても構造体データをまるごと渡す
- データ結合は、必要なデータだけを渡す
- 制御結合 / 論理的強度
- 制御結合は、結合度での呼び名(機能コードを引数で渡して制御する)
- 論理的強度は、強度での呼び名(引数で機能を選んで実行する)
- 時間的強度 / 手順的強度
- 時間的強度は、同じ時期に実行する機能をまとめる(機能間にあまり関連はない)
- 手順的強度は、順番に実行する機能をまとめる
- 手順的強度 / 連絡的強度
- 手順的強度は、順番に実行するだけ
- 連絡的強度は、順番に実行し、さらに機能間にデータの関連性がある(同じデータを参照する)
- 情報的強度 / 機能的強度
- 情報的強度は、同じデータ構造を扱う機能をまとめ、機能ごとに入口点と出力点を持つ
- 機能的強度は、1つの機能だけ。最も強く、最も良い
- 制御領域 / 影響領域
- 制御領域は、自分と、自分に従属するモジュールの範囲
- 影響領域は、自分の決定が影響を及ぼす範囲
- 制御領域 ≧ 影響領域なら良い
- 順番コード / 区分コード
- 順番コードは、全体に連番を付ける。分類がわからない
- 区分コードは、グループごとに番号の範囲を割り当てて連番を付ける
- 桁別コード / 表意コード
- 桁別コードは、各桁が大・中・小分類の意味を持つ。桁数が大きくなりやすい
- 表意コードは、略称や記号をコードにする。覚えやすいが分類には不便