疎結合
Loose Coupling
疎結合は、部品同士が必要な契約を通じて連携し、内部の変更へ依存しすぎない関係です。依存がゼロであることではなく、変更の影響を制御しやすくする考え方です。
🐾 猫で例えると?
アメショと茶トラがそっぽを向き、絶妙な距離感で過ごしています。片方が寝返りを打っても、もう片方まで姿勢を変えずに済みそうですね。この「相手の細かな変化に振り回されにくい」関係が疎結合のイメージです。プログラムでは、必要なやり取りの約束を決め、相手の内部の作りに頼りすぎないようにします。
💻 アプリ・Web開発における「疎結合」とは?
「密結合」のシステムがガチガチに絡まり合ったパズルのようなものなら、「疎結合」なシステムは、レゴブロックのように必要なパーツを自由に入れ替えられる柔軟な構成です。各モジュールやクラスが、相手の中身を気にせず「渡されたデータを受け取り、処理して返す」という最低限の約束(インターフェース)だけで会話するように設計します。
たとえば保存処理を窓口にまとめると、DB製品の変更で直す場所を限定しやすくなります。ただしSQLの機能、トランザクション、性能、データ移行には差があるため、インターフェースを作れば無条件にMySQLとPostgreSQLを差し替えられるわけではありません。
⚠️ 疎結合を実現する設計のポイント
疎結合にするためには、機能の「関心事」を分ける(責務の分離)ことが鍵になります。
// TypeScript:保存先を外から渡す小さな例
interface Storage {
save(text: string): void;
}
class App {
constructor(private storage: Storage) {}
run() { this.storage.save("猫の記録"); }
}
const recorded: string[] = [];
const memoryStorage: Storage = { save: (text) => { recorded.push(text); } };
new App(memoryStorage).run();
console.log(recorded); この例は本物のDBなしに保存の呼び出しを確認できます。ただしsaveの名前と型だけでなく、失敗の通知、完了まで待つか、保存を保証する範囲なども契約です。窓口があっても、その意味へ強く依存していれば変更時の確認は必要です。
🛠️ 疎結合と賢く付き合うためのポイント
疎結合を目指すことは大切ですが、やりすぎると「過剰設計」になり、コードが細分化されすぎて何をしているか分かりにくくなることもあります。
- ほどよい抽象化を心がける: 疎結合は便利ですが、細分化しすぎると追跡が難しくなります。「将来的に交換する可能性が本当に高いか?」を冷静に判断しましょう。
- インターフェースを明確に定義する: 疎結合の基本は「これさえ守ればOK」というルール作りです。この約束事が曖昧だと、結局は中身を確認しないといけない密な関係に戻ってしまいます。
- 差し替えと変更の範囲を確認: 単独テストができるのは良い手掛かりですが、それだけで十分とは限りません。実装の変更時に契約が守られるか、利用側の修正がどこまで必要かも見ます。
離れて過ごすアメショと茶トラのように、疎結合では相手の内部事情に頼りすぎない関係を作ります。部品を変更するときに他のどこを直す必要があるかを調べると、依存が広がっている箇所を見つける手掛かりになります。