凝集度とは?

公開日:
最終更新日:

イントロダクション:凝集度を一言で言うと? 🧩

凝集度(Cohesion)とは、 「1つのモジュールの中に入っている要素同士が、どれくらい密接に関係しているか」 を表す指標です。

ここでの「モジュール」は、クラス・関数・ファイル・パッケージなど 「ひとまとまりの単位」 だとイメージしてください。

中に入っている処理やデータが、 1つのはっきりした目的に向かってきれいにつながっている状態が「凝集度が高い」 と言い、 バラバラでたまたま同じ場所にいるだけの寄せ集め状態を 凝集度が低い」 と言います。

1. なぜ「凝集度」が大事なの? 🔍

モジュールの凝集度が低いと、次のような問題が起きやすくなります。

  • 読んでも役割が分からない
    1つのクラスや関数の中で、ログ出力・画面制御・DBアクセスなど、バラバラなことをしていて、 「このモジュールは何のためにあるのか?」が一言で言えない。
  • 変更の影響範囲が読みにくい
    ある機能の仕様変更をしたいだけなのに、 他の目的のコードまで同じモジュールに混ざっていて、どこまで影響するか分からない。
  • 再利用しづらい
    「ここだけ別のところでも使い回したい」と思っても、 目的の違う処理がくっついていて、きれいに切り出せない。

逆に、 凝集度が高いモジュールは「役割が一言で説明できる」ので、読みやすく直しやすい のが特徴です。 単一責任原則(SRP)や疎結合とも相性の良い、設計の基本観点の1つです。

2. 凝集度の7つのレベル(低い → 高い)

凝集度には、一般的に「レベル1〜レベル7」までの段階があります。 ここでは、クイズで使っている解説に沿って整理し直します。

レベル1:暗合的強度

たまたま同じ場所に置かれただけの寄せ集め。 要素同士に特別なつながりがなく、再利用もしにくい状態です。

レベル2:論理的強度

「入力系」「出力系」など、 抽象的なラベルとしては似ている ものの、実際の処理同士の関係が弱い状態です。 「なんとなく同じジャンルだからまとめた」レベルです。

レベル3:時間的強度

起動時にまとめて実行する初期化処理など、 「同じタイミングで動くから」 という理由だけで集めた状態です。 処理同士の意味的なつながりは薄く、時間以外の共通点が乏しい段階です。

レベル4:手順的強度

大きな手順の一部分だけを1モジュールにしていて、 処理の流れ全体とは切り離しづらい 状態です。 「この処理の後には必ずあの処理が来る」といった手順依存が強く、独立性が低いです。

レベル5:連絡的強度

手順的強度に加えて、 同じデータの受け渡しや参照 をしている状態です。 まだ1モジュールの中に複数の役割が混ざっており、 「データは同じだが、やっていることはバラバラ」という段階です。

レベル6:情報的強度

あるデータ構造(例:ユーザー情報)を扱う複数の処理を1か所に集めた状態です。 入り口(メソッド)ごとに役割は1つ になっていて、 「このモジュールはこの情報を扱う場所」という意味がはっきりしてきます。

レベル7:機能的強度

中の命令がすべて 1つの目的達成のためにきれいにつながっている、理想的な状態 です。 モジュールに「これをする場所」という明確なゴールがあり、 他の目的の処理が混ざっていません。

実務では、常にレベル7を完璧に目指すのは難しいですが、 「せめて情報的強度以上に寄せていく」 ことを意識するだけでも、設計の質が大きく変わります。

3. 凝集度を高めるための考え方 💡

凝集度を高める基本的なコツは、 「このモジュールは何のために存在するのか?」 を一言で説明できるようにすることです。

  • 目的ごとにモジュールを分ける
    「バリデーション」「集計」「保存」「通知」といった 役割単位 でクラスや関数を分け、 1つのモジュールに複数の目的を詰め込まないようにします。
  • 名前で役割をはっきりさせる
    クラス名・関数名・ファイル名を見ただけで、 「何をするものか」イメージできるようにします。 名前が曖昧だときは、中身の役割も混ざっているサインです。
  • 「これもついでに」は要注意
    近い場所にあるからといって、 「ついでにこの処理もここに入れてしまおう」とすると、凝集度が下がります。 別の目的なら、別のモジュールに切り出せないか検討してみましょう。
  • リファクタリングで少しずつ整える
    いきなり理想の構造を目指すのではなく、 長すぎる関数を分割する・重複をまとめる・名前を見直す といった小さなリファクタリングを重ねて、徐々に凝集度を高めていきます。

図解で見る「低凝集度」と「高凝集度」

1つのモジュールの中に「データ取得」「計算」「表示の整形」などが混在している状態(低凝集)と、 役割ごとにモジュールを分けた状態(高凝集)を、箱とラベルでイメージできる図解です。

低凝集度:1つのモジュールに関心ごとが混ざっている例

「データ取得」「計算」「表示の整形」「ログ出力」など、性質の違う処理が1つのモジュールに詰め込まれているイメージです。 役割がぼやけて、再利用や変更が難しくなります。

モジュールA
データ取得 計算 表示の整形 バリデーション ログ出力

1つの箱の中に、性質の違う機能がいくつも同居しており、 「このモジュールは何をする場所か?」が一言で言えない状態 です。

高凝集度:役割ごとにモジュールを分けた例

「データ取得」「計算」「表示の整形」を、それぞれ専用のモジュールに分離したイメージです。 1つのモジュールが1つの目的に集中することで、読みやすさと変更のしやすさが向上します。

モジュールA
データ取得だけ
モジュールB
計算だけ
モジュールC
表示の整形だけ

「このモジュールは◯◯だけを担当する」 と説明できるので、役割が明確になり、 テスト・変更・再利用のどれもがやりやすくなります。

JavaScriptで見る「低凝集度」と「高凝集度」の例

「データ取得」「計算」「表示の整形」を題材に、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つのモジュールの中の要素同士が、どれくらい強く関係しているか を表す指標です。
  • レベル1(暗合的強度)からレベル7(機能的強度)までの 7段階のイメージ を持っておくと、「今のこのコードはどのあたりか?」を振り返りやすくなります。
  • 「このモジュールは何のためにあるのか?」を一言で説明できるか をチェックポイントにすると、 凝集度を高める方向に自然とリファクタリングしやすくなります。
  • 疎結合(モジュール同士の依存を減らす)と合わせて、 「高凝集・低結合」 を目指すことが、 読みやすく・変更に強い設計への近道です。

まずは、 「このクラス(関数)、本当に1つの目的だけに集中できているか?」 と問いかけるところから、凝集度の感覚を育てていきましょう。

このページの著者

もちもちみかん(システムエンジニア)

社内SEとしてグループ企業向けの業務アプリを要件定義〜運用まで一気通貫で担当しています。

経験:Webアプリ/業務システム

得意:PHP・JavaScript・MySQL・CSS

個人実績:フォーム生成基盤クイズ学習プラットフォーム

詳しいプロフィールはこちら!  もちもちみかんのプロフィール

もちもちみかん0系くん
TOPへ

もちもちみかん.comとは


このサイトでは、コーディングがめんどうくさい人向けのお助けツールとして、フォームやCSSをノーコードで生成できる、
 もちもちみかん.forms
 もちもちみかん.css1
 もちもちみかん.css2
と言ったジェネレーターを用意してます。

また、このサイトを通じて、「もちもちみかん」のかわいさを普及したいとかんがえてます!