低凝集度:1つのモジュールに関心ごとが混ざっている例
「データ取得」「計算」「表示の整形」「ログ出力」など、性質の違う処理が1つのモジュールに詰め込まれているイメージです。 役割がぼやけて、再利用や変更が難しくなります。
1つの箱の中に、性質の違う機能がいくつも同居しており、 「このモジュールは何をする場所か?」が一言で言えない状態 です。
凝集度(Cohesion)とは、 「1つのモジュールの中に入っている要素同士が、どれくらい密接に関係しているか」 を表す指標です。
ここでの「モジュール」は、クラス・関数・ファイル・パッケージなど 「ひとまとまりの単位」 だとイメージしてください。
中に入っている処理やデータが、 1つのはっきりした目的に向かってきれいにつながっている状態が「凝集度が高い」 と言い、 バラバラでたまたま同じ場所にいるだけの寄せ集め状態を 「凝集度が低い」 と言います。
モジュールの凝集度が低いと、次のような問題が起きやすくなります。
逆に、 凝集度が高いモジュールは「役割が一言で説明できる」ので、読みやすく直しやすい のが特徴です。 単一責任原則(SRP)や疎結合とも相性の良い、設計の基本観点の1つです。
凝集度には、一般的に「レベル1〜レベル7」までの段階があります。 ここでは、クイズで使っている解説に沿って整理し直します。
たまたま同じ場所に置かれただけの寄せ集め。 要素同士に特別なつながりがなく、再利用もしにくい状態です。
「入力系」「出力系」など、 抽象的なラベルとしては似ている ものの、実際の処理同士の関係が弱い状態です。 「なんとなく同じジャンルだからまとめた」レベルです。
起動時にまとめて実行する初期化処理など、 「同じタイミングで動くから」 という理由だけで集めた状態です。 処理同士の意味的なつながりは薄く、時間以外の共通点が乏しい段階です。
大きな手順の一部分だけを1モジュールにしていて、 処理の流れ全体とは切り離しづらい 状態です。 「この処理の後には必ずあの処理が来る」といった手順依存が強く、独立性が低いです。
手順的強度に加えて、 同じデータの受け渡しや参照 をしている状態です。 まだ1モジュールの中に複数の役割が混ざっており、 「データは同じだが、やっていることはバラバラ」という段階です。
あるデータ構造(例:ユーザー情報)を扱う複数の処理を1か所に集めた状態です。 入り口(メソッド)ごとに役割は1つ になっていて、 「このモジュールはこの情報を扱う場所」という意味がはっきりしてきます。
中の命令がすべて 1つの目的達成のためにきれいにつながっている、理想的な状態 です。 モジュールに「これをする場所」という明確なゴールがあり、 他の目的の処理が混ざっていません。
実務では、常にレベル7を完璧に目指すのは難しいですが、 「せめて情報的強度以上に寄せていく」 ことを意識するだけでも、設計の質が大きく変わります。
凝集度を高める基本的なコツは、 「このモジュールは何のために存在するのか?」 を一言で説明できるようにすることです。
1つのモジュールの中に「データ取得」「計算」「表示の整形」などが混在している状態(低凝集)と、 役割ごとにモジュールを分けた状態(高凝集)を、箱とラベルでイメージできる図解です。
「データ取得」「計算」「表示の整形」「ログ出力」など、性質の違う処理が1つのモジュールに詰め込まれているイメージです。 役割がぼやけて、再利用や変更が難しくなります。
1つの箱の中に、性質の違う機能がいくつも同居しており、 「このモジュールは何をする場所か?」が一言で言えない状態 です。
「データ取得」「計算」「表示の整形」を、それぞれ専用のモジュールに分離したイメージです。 1つのモジュールが1つの目的に集中することで、読みやすさと変更のしやすさが向上します。
「このモジュールは◯◯だけを担当する」 と説明できるので、役割が明確になり、 テスト・変更・再利用のどれもがやりやすくなります。
「データ取得」「計算」「表示の整形」を題材に、1つの関数に詰め込んだ低凝集度の例と、 責務ごとに役割を分けた高凝集度の例を並べて比較できるコードスニペットです。※コードのコメントを読むだけでも理解できるかと思います。
データ取得・計算・表示整形・スタイル調整まで、1つの関数に詰め込んだ例です。 責務が混在しているため、変更や再利用がしづらくなっています。
// 低凝集度の例:1つの関数に「データ取得・計算・表示の整形」がすべて入り込んでいる
function showSalesLowCohesion() {
const button = document.getElementById('showButtonLow');
const result = document.getElementById('lowCohesionResult');
// データ取得(ついでにデフォルトデータもここで決める)
let orders = JSON.parse(localStorage.getItem('orders') || '[]');
if (orders.length === 0) {
orders = [
{ price: 1200, qty: 1 },
{ price: 500, qty: 3 }
];
localStorage.setItem('orders', JSON.stringify(orders));
}
// 計算ロジック(税率もここでベタ書き)
let subtotal = 0;
for (let i = 0; i < orders.length; i++) {
const item = orders[i];
subtotal += item.price * item.qty;
}
const taxRate = 0.1;
const tax = Math.round(subtotal * taxRate);
const total = subtotal + tax;
// 表示の整形(テキスト組み立てもここ)
const text =
'低凝集度: ' +
'小計 ' + subtotal.toLocaleString() + ' 円 / ' +
'税額 ' + tax.toLocaleString() + ' 円 / ' +
'合計 ' + total.toLocaleString() + ' 円';
result.textContent = text;
// ついでにスタイル調整もここでやってしまう
result.style.backgroundColor = '#fff7e6';
result.style.border = '1px solid #f0b74a';
button.disabled = true;
}
「データ取得」「計算」「表示テキスト整形」「UI更新」をそれぞれ専用の関数に分けた例です。 1つの関数が1つの目的に集中するようになり、テストや変更がしやすくなります。
// 高凝集度の例:責務ごとに関数を分ける
// データ取得だけを担当
function loadOrdersFromStorage() {
const stored = localStorage.getItem('orders');
if (stored) {
return JSON.parse(stored);
}
const defaultOrders = [
{ price: 1200, qty: 1 },
{ price: 500, qty: 3 }
];
localStorage.setItem('orders', JSON.stringify(defaultOrders));
return defaultOrders;
}
// 計算だけを担当
function calculateTotals(orders, taxRate) {
const subtotal = orders.reduce(
(sum, item) => sum + item.price * item.qty,
0
);
const tax = Math.round(subtotal * taxRate);
const total = subtotal + tax;
return { subtotal, tax, total };
}
// 表示テキストの整形だけを担当
function formatTotalsText(totals) {
return (
'高凝集度: ' +
'小計 ' + totals.subtotal.toLocaleString() + ' 円 / ' +
'税額 ' + totals.tax.toLocaleString() + ' 円 / ' +
'合計 ' + totals.total.toLocaleString() + ' 円'
);
}
// UI をつなぐ薄い層
function showSalesHighCohesion() {
const button = document.getElementById('showButtonHigh');
const result = document.getElementById('highCohesionResult');
// データ取得
const orders = loadOrdersFromStorage();
// 計算
const totals = calculateTotals(orders, 0.1);
// 表示テキストの整形
const text = formatTotalsText(totals);
// 表示
result.textContent = text;
button.disabled = true;
}
まずは、 「このクラス(関数)、本当に1つの目的だけに集中できているか?」 と問いかけるところから、凝集度の感覚を育てていきましょう。
経験:Webアプリ/業務システム
得意:PHP・JavaScript・MySQL・CSS
個人実績:フォーム生成基盤/クイズ学習プラットフォーム 等
詳しいプロフィールはこちら! もちもちみかんのプロフィール