基礎概念:責任分離とは何か
責任分離の本質的な意味と、なぜそれが重要なのかを理解しましょう
責任とは何か?
「責任」の定義
ソフトウェア設計における「責任」とは、あるモジュールが果たすべき役割や機能のことです。より正確には、「そのモジュールを変更する理由」と定義できます。
責任を識別する観点
- 何をするモジュールか(機能)
- 誰のためのモジュールか(アクター)
- いつ変更が必要になるか(変更理由)
責任が混在したコードの問題
❌ 責任が混在している例
class OrderService {
calculateTotal(items) {
let total = 0;
for (const item of items) {
total += item.price * item.quantity;
}
// 税金計算(ビジネスロジック)
const tax = total * 0.1;
const finalTotal = total + tax;
// データベース保存(永続化)
database.save('orders', { items, total: finalTotal });
// メール送信(通知)
emailService.send(customerEmail,
`注文合計: ${finalTotal}円`);
// ログ記録(監査)
logger.info(`Order created: ${finalTotal}`);
return finalTotal;
}
}
✅ 責任が分離された例
// 計算の責任
class OrderCalculator {
calculateTotal(items) {
const subtotal = items.reduce(
(sum, item) => sum + item.price * item.quantity, 0
);
const tax = subtotal * 0.1;
return { subtotal, tax, total: subtotal + tax };
}
}
// 永続化の責任
class OrderRepository {
save(orderData) {
return database.save('orders', orderData);
}
}
// 通知の責任
class OrderNotifier {
notifyCustomer(email, orderTotal) {
emailService.send(email, `注文合計: ${orderTotal}円`);
}
}
責任混在がもたらす問題
- 理解の困難さ:一つのクラスを理解するために、複数の概念を同時に把握する必要がある
- テストの複雑化:データベースやメールサービスをモック化しないと計算ロジックのテストができない
- 変更の波及:税率が変わったときに、なぜかメール送信部分も再テストが必要になる
- 再利用の困難:計算ロジックだけを別の場所で使いたくても、不要な依存を引きずる
凝集度と結合度
高凝集・疎結合の原則
良い設計の基本は「高凝集・疎結合」です。
凝集度(Cohesion)
- モジュール内の要素がどれだけ関連しているか
- 高凝集 = 関連する機能が一つのモジュールにまとまっている
- 低凝集 = 無関係な機能が一つのモジュールに混在している
結合度(Coupling)
- モジュール間の依存関係の強さ
- 疎結合 = モジュール間の依存が少ない、または抽象的
- 密結合 = モジュール間が具体的な実装に強く依存している
責任分離の歴史と進化
設計思想の発展
責任分離の考え方は、ソフトウェア工学の発展とともに洗練されてきました。
- 1970年代:構造化プログラミング - 機能の分割
- 1980年代:オブジェクト指向 - データと振る舞いのカプセル化
- 1990年代:デザインパターン - 再利用可能な設計の型
- 2000年代:SOLID原則 - オブジェクト指向設計の指針
- 2010年代〜:マイクロサービス - システムレベルの責任分離