くま's Tech系Blog

基本的には技術で学んだことを書き留めようと思います。雑談もやるかもね!

凝集度について

今回は凝集度(cohesion) について記載しようと思います。

凝集度とはプログラムのひとつの関数・メソッド・クラスなどのモジュールの中に含まれる機能の純粋度を表す尺度です。 1つの関数の中でいくつもの機能が混ざり合っているよりも、機能と関数が1対1になっている方が上手く機能分割されて理解しやすく、修正の影響範囲は確実に減ります。 つまり、凝集度が高いということはメンテナンス性が高くなります。

ここからは凝集度の度合いとその分類を段階別に記載していきます。 上から順に望ましいモジュールになります。

機能的凝集度

機能的凝集度(Functional cohesion)はモジュールがある処理を1つだけ実行する場合です。

イメージは、ケーキ作りの道具をすべてキッチンの1つの専用引き出しに収納している場合です。 ボウルや木製のスプーン、ケーキ型はすべて、ケーキ作りという同じシングルタスクに貢献するため、まとめられています。

function getEquipmentForCake() {
    return  ケーキ作り用の道具(ボウルやスプーンなど);
}

逐次的凝集度

逐次的凝集度(Sequential cohesion)はモジュール内の処理が、受け渡されたデータを加工を施し結果を返却する処理であり、かつ順番に連鎖できる関係性でまとまっている場合です。

1つのモジュールの中に2つ以上の機能が含まれているが、2つの機能は関連性が高く、その順に処理していくことに意味があるため、1つの関数の中に収まっている状態になります。

例えば、コーヒーを飲むまでの流れを考えてみてください。 豆を挽くまではコーヒーを淹れることはできないです。 つまり、豆を挽くプロセスのアウトプットは、コーヒーを淹れるプロセスのインプットです。 したがって、豆を挽くこととコーヒーを淹れることは互いに密接な関係にあると結論づけることができます。

function drinkCoffee() {
    豆を挽く;
    コーヒーを淹れる;
}

連絡的(通信的)凝集度

連絡的凝集度(Communicational cohesion)はモジュール内の処理が同じデータを使用するモジュールです。 ただし、データの共有を除いて処理の関連がないモジュールです。

例えば、同種のレコードの情報を操作するルーチンを集めたモジュールが該当するので、次のような処理が当てはまるかと思われます。

function searchBook() {
    本のタイトルを検索;
    本の値段を検索;
    本の著者を検索;
}

同じ本の情報を検索していますが、処理の関連がないです。

時間的凝集度

時間的凝集度(Temporal cohesion)は同じようなタイミングで発生する、関係ない機能を集めたモジュールです。 実行順序を入れ替えても問題ないという特徴があります。

function prepareToSleep() {
    テレビを消す;
    洗顔をする;
    歯を磨く;
}

手続的凝集度

手続的凝集度(Procedural cohesion)は論理的に似たようなことをするものを集めたモジュール、もしくはお互いに関係ない機能の一つを実行するモジュールです。 時間的凝集に非常に似ており、違いは順序に意味があります。より関連性の高い処理が関数に実装されており、時間的凝集よりは凝集度が高いです。
ただし、機能的には関係ない関数が 1 つの関数にまとめられてしまっているのが問題です。

function buySomething() {
    財布を出す;
    残高を確認;
    支払う;
}

論理的凝集度

論理的凝集度(Logical cohesion)は論理的に似たようなことをするものを集めたモジュール、もしくはお互いに関係ない機能の一つを実行するモジュールです。 例えば、関連のない処理をフラグで切り替える関数などが当てはまります。

function transport() {
    if (isSunny) {
        徒歩で移動;
    } else {
       車で移動;
    }
}

論理的凝集の関数そのものを削除してしまう。もしくは、フラグ値によって処理を切り替える関数は削除可能な場合があるので検討する必要があります。

暗号的(偶発的)凝集度

暗号的凝集度(Coincidental cohesion)は作為に処理が集められた関数.関数の中に複数の処理が存在し、それらの処理はまったく関係がないモジュールです。 最も凝集度が低いため本当に必要なのか、改善する方法を検討した方が良いモジュールです。

function doAnything() {
    ケーキを焼く;
    散歩をする;
    お風呂に入る;
}

まとめ

凝集度の度合いについて記載しました。

機能的凝集度もしくは、逐次的凝集度になるように意識してモジュールを作れれば良いかなと思います。(機能的凝集度にするのが難しいパターンもあるので)
逆に暗号的(偶発的)凝集度や論理的凝集度になっている場合には改善方法を検討した方がいいと思います。

プログラミングにおける関心の分離(責務の分離、Separation Of Concerns)を意識することで凝集度の高いプログラムを作成できると思います。

参照

www.shuwasystem.co.jp

https://www.tsuyama-ct.ac.jp/hata/experiments/4th/software/ja/chapter3/3_cohesion.html#:~:text=%E9%80%90%E6%AC%A1%E7%9A%84%E5%87%9D%E9%9B%86%E5%BA%A6%20(Sequential,%E3%81%A7%E3%81%BE%E3%81%A8%E3%81%BE%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%82

docs.sakai-sc.co.jp