コードの結合度と凝集度って何? 初心者がステップアップするための設計思想入門
プログラムを書き始めたばかりのころは、自分の思い通りに動くだけでも最高に嬉しいものですよね。
しかし、少し規模の大きなアプリを作り始めると、コードがワケのわからない複雑なものになってしまうことがあります。
1箇所を直しただけなのに全く関係のない別の場所でエラーが出たり、どこに何を書いたか分からなくなったりした経験はありませんか。 こうしたプログラミングのイライラや限界を解消するために生み出されたのが、今回ご紹介する結合度と凝集度という設計のモノサシです。
これらの言葉は一見すると難しそうですが、一度理解してしまえばコードの見え方が劇的に変わります。 エンジニアとして10年間さまざまなシステムを開発し、たくさんの失敗を乗り越えてきた私の視点も交えながら、初心者向けに分かりやすく解説します。
なぜプログラミングで設計を意識する必要があるのか?¶
プログラムを書く作業に少しずつ慣れてくると、次の一歩として綺麗でメンテナンスしやすいコードを書きたいという欲求が湧いてきます。 そもそも、なぜ私たちは単に動くだけのコードを卒業して、設計という概念を意識しなければならないのでしょうか。
最初は動けば正義、でも後から地獄を見る理由¶
プログラミングの学習を始めた初期段階では、とにかく画面に正しい結果が表示されればそれが正解です。 しかし、コードの行数が数百行、数千行と増えていくにつれて、動けば何でも良いというアプローチは通用しなくなります。
機能を追加しようとするたびにコード全体を読み直さなければならなくなり、開発のスピードが急激に落ちてしまうからです。 昨日書いたばかりの自分のコードなのに、まるで他人が書いた暗号のように見えてしまうことすらあります。
このように、行き当たりばったりで書かれたコードは、時間が経つほど修正や拡張が難しい負債へと変わっていきます。 この問題を未解決のまま放置すると、最終的にはプログラム全体を作り直さなければならない事態に追い込まれることも珍しくありません。
そうした最悪のシナリオを回避し、いつでも安全に楽しくコードを書き換えるために、先人たちが作り上げた知恵が設計思想です。 設計を学ぶことは、未来の自分の時間を守り、プログラミングのストレスを減らすための最強の自己投資になります。
【関連記事】 綺麗なコードって何?初心者から一歩抜け出す「リーダブルコード」の3つの基本
スパゲッティコードの罠¶
ここで、私が新人のころにやらかしてしまった苦い経験を少しお話しさせてください。 当時の私は、とにかく素早く機能を実装することだけに集中しており、1つのファイルに何千行もの処理を詰め込んでいました。
あるとき、ユーザーのログイン処理を少し変更してほしいという単純な依頼を先輩から受けました。 ほんの数行書き換えてテストしてみたところ、なぜか全く関係のない商品の決済機能が完全に壊れてしまったのです。
どこがどう繋がっているのか分からず、冷や汗を流しながら徹夜でコードを探る羽目になりました。 このように、1つの変更があちこちに飛び火して絡み合っている状態を、エンジニアの世界ではスパゲッティコードと呼びます。
この手痛い失敗をきっかけに、私はコードを適切に分割し、それぞれの関係性を整理する設計の大切さを身に染みて学びました。 そのときに先輩エンジニアから教えてもらったものが、今回深く掘り下げる凝集度と結合度という概念です。
凝集度(ぎゅうしゅうど/Cohesion)とは?¶
設計思想の第一歩として、まずは凝集度という言葉から詳しく見ていきましょう。 この概念を理解すると、関数やクラスをどのくらいの大きさに区切れば良いのかという迷いが綺麗に消え去ります。
1つの部品に役割をどれだけギュッと詰め込めているか¶
凝集度とは、簡単に言うと、1つの関数やクラスが持つ機能の専門性の高さを表す指標です。 その部品の中に、どれだけ関連性の高い処理がギュッと凝縮されて詰め込まれているかを意味します。
凝集度が高い状態の部品は、1つのことだけに特化したプロフェッショナルであり、無駄な機能が一切混ざっていません。 逆に凝集度が低い状態の部品は、あれもこれもと欲張って何でもこなそうとする便利屋のような状態です。
優れたプログラムを作るためには、この凝集度をできる限り高めることが大原則とされています。 役割が明確で専門性が高ければ高いほど、その部品のコードは短くなり、パッと見ただけで何をしているかが理解しやすくなるからです。
身近な例え:整理整頓された引き出しとカオスなゴミ箱¶
凝集度の違いを、私たちの身の回りにある日常品に例えてイメージしてみましょう。 凝集度が高い状態とは、文房具の引き出しの中にハサミやペンだけが綺麗に分類されて収まっている状態です。
ハサミを使いたいときはその引き出しを開ければ一瞬で見つかりますし、中身を整理するのも非常に簡単ですよね。 一方で凝集度が低い状態とは、何でも放り込んである部屋の隅の大きなゴミ箱や、カオスな物置のようなものです。
その中には、古い雑誌もあれば、食べかけのお菓子も、使い古した工具も一緒くたに入っています。 何か1つの道具を取り出したいだけなのに、すべてのゴミをひっくり返して探さなければならず、非常に効率が悪いです。
プログラムの世界でも全く同じであり、何でもできる関数を作ってしまうと、その中身はカオスなゴミ箱になってしまいます。 引き出しを開けるように、目的の機能だけがスマートにまとまった高凝集なコードを目指すのが理想的です。
凝集度の7段階を初心者向けに徹底解説¶
実は、凝集度にはその良し悪しに応じて、専門的に7つの段階が定義されています。 ここからは、最も好ましくないレベルから順番に、どのような特徴があるのかを噛み砕いて解説していきましょう。
段階が進むにつれて、処理のまとまりが不自然なものから、論理的で美しいものへと進化していく様子を感じてみてください。
1. 偶発的凝集(最も悪い)¶
偶発的凝集とは、特にこれといった理由や関連性がなく、たまたま同じ場所にコードが集まっている状態です。 例えば、ファイルが長くなったからという理由だけで、適当に100行目で区切って別の関数にしたようなケースが該当します。
中身の処理同士には何の繋がりもないため、コードを読む人を激しく混乱させる最も避けるべき状態です。 実務でこれを見かけることは滅多にありませんが、設計を全く意識しないと稀に生まれてしまうことがあります。
2. 論理的凝集¶
論理的凝集とは、一見すると関連性があるように見えて、実は大雑把なジャンルだけでまとめられた状態です。 よくある失敗例としては、出力に関する処理だからという理由で、画面表示とファイル書き込みと印刷を1つの関数に入れるケースです。
これらはすべて出力という共通の言葉で括れますが、実際の処理内容や動くタイミングは全く異なります。 関数を呼び出す側が、どの処理を動かすかをわざわざフラグで指示しなければならないため、使い勝手が悪くなります。
3. 時間的凝集¶
時間的凝集とは、プログラムを実行するタイミングが同じであるという理由だけで、処理をまとめた状態です。 最も分かりやすいのが、システムの起動時に動く初期化処理(初期設定)を1つにまとめた関数です。
データベースの接続準備や、画面のサイズ設定、ログファイルの作成など、異なる役割のコードが同時に動くからという理由だけで同居します。 論理的凝集よりは少しマシですが、後からデータベースの接続設定だけを変更したいときに、関係のないコードまで巻き込んでしまうリスクがあります。
4. 手続き的凝集¶
手続き的凝集とは、あらかじめ決められた実行手順の通りに処理が並んでいるからという理由でまとめた状態です。 例えば、ユーザーから入力を受け取り、それをチェックし、エラーがなければファイルに保存するという一連の流れです。
順番通りに実行されるため一見すると自然に思えますが、これらを1つの大きな関数に閉じ込めてしまうと問題が起きます。 入力チェックのルールだけを他の場所で再利用したくなったときに、ファイル保存の機能が邪魔をして切り離せなくなってしまうのです。
5. 通信的凝集¶
通信的凝集とは、同じデータ(入力や出力)を利用する処理同士を、1つの場所にまとめた状態です。 例えば、同じ売上データを使って、合計金額を計算する処理と、平均値を算出する処理を1つの関数に書くケースです。
扱う対象のデータが同じであるため、これまでの段階に比べるとかなり関連性が強く、まとまりが綺麗になってきます。 実務のコードでもよく見かけるレベルですが、計算ロジックが複雑になると関数が肥大化しやすいので注意が必要です。
6. 順次的凝集¶
順次的凝集とは、ある処理の出力データが、次の処理の入力データへとバケツリレーのように直結している状態です。 例えば、ファイルを読み込んでテキストを取り出し、そのテキストの暗号化を行い、最後に解析レポートを作成する流れです。
前の処理の結果がないと次の処理が絶対に始められないため、部品としての結びつきは非常に強固で合理的です。 実務でも十分に許容される良いレベルであり、流れが一本道なのでコードの動向を追いやすいという特徴を持っています。
7. 機能的凝集(最も良い)¶
機能的凝集とは、単一の明確な目的や役割だけを実行するために、すべての要素が完璧に調和してまとまっている状態です。 例えば、与えられた数値の消費税を計算するだけの関数や、文字列がメールアドレスの形式を満たしているかチェックするだけの関数です。
これ以上分解する余地がないほどシンプルであり、外から見ても何をする部品なのかが100%一発で分かります。 プログラミングにおいて、私たちが最終的に目指すべき最高峰のゴールが、この機能的凝集を散りばめたコードです。
【コード例】悪い凝集度(何でも屋)から良い凝集度(専門家)へ¶
言葉での説明が続きましたので、ここからはPythonの具体的なコードを使って、凝集度のリファクタリングを体験してみましょう。 まずは、典型的な悪い例として、1つの関数が複数の役割を抱え込んでいる何でも屋のコードをご覧ください。
以下のコードブロックは、ユーザーの注文データを処理するプログラムです。
def process_order(order_data):
# 1. データのバリデーション(チェック)
if not order_data.get("item_id") or order_data.get("amount") <= 0:
print("エラー: 注文データが正しくありません。")
return False
# 2. 料金の計算
price = order_data["amount"] * 1000
if order_data.get("is_premium_member"):
price = int(price * 0.9)
print(f"計算された合計金額: {price}円")
# 3. データベースへの保存
print(f"アイテム {order_data['item_id']} の注文をデータベースに保存しました。")
return True
この process_order という関数は、チェック、計算、保存という全く毛色の違う3つの仕事を1人でこなしています。
これは手続き的凝集にあたり、もし将来的に料金の計算ルールだけを変えたい場合でも、この大きな関数全体を触らなければなりません。
では、このコードの凝集度を極限まで高めるために、それぞれの役割を専門家に切り分けてみましょう。 綺麗にリファクタリングした後のコードが、以下のプログラムです。
def validate_order(order_data):
"""注文データの正しさをチェックする専門家(機能的凝集)"""
return bool(order_data.get("item_id") and order_data.get("amount") > 0)
def calculate_price(amount, is_premium):
"""料金の計算だけに特化した専門家(機能的凝集)"""
base_price = amount * 1000
return int(base_price * 0.9) if is_premium else base_price
def save_order(item_id):
"""データベースへの保存だけを行う専門家(機能的凝集)"""
print(f"アイテム {item_id} の注文をデータベースに保存しました。")
def process_order_refined(order_data):
"""それぞれの専門家を順番に呼び出して統括する関数"""
if not validate_order(order_data):
print("エラー: 注文データが正しくありません。")
return False
price = calculate_price(order_data["amount"], order_data.get("is_premium_member"))
print(f"計算された合計金額: {price}円")
save_order(order_data["item_id"])
return True
いかがでしょうか、1つひとつの関数が驚くほど短くなり、何をしているかが一目瞭然になったと思います。
計算ロジックにバグが見つかったときは calculate_price だけを見れば良いので、修正時に他の場所を壊すリスクが消え去ります。
このように、大きな仕事を小さな専門家に分けていく作業こそが、凝集度を高めるということの実体です。
結合度(けつごうど/Coupling)とは?¶
凝集度について理解が深まったところで、次はもう1つの重要なモノサシである結合度へと進みましょう。 凝集度が部品の「中身」に関する話だったのに対し、結合度は部品と部品の「関係性」に関するお話です。
部品と部品の「依存関係」の強さを表す指標¶
結合度とは、異なる関数やクラス同士が、どれだけお互いに強く結びついてしまっているかを表す指標です。 別の表現を使うなら、部品間の依存関係の強さと言い換えることもできます。
結合度が強い状態(密結合)は、ある部品を変更したときに、その影響が他の部品へとドミノ倒しのように伝わってしまう危うい状態です。 逆に結合度が弱い状態(疎結合)は、それぞれの部品が自立しており、お互いの内部事情に深く干渉しないスマートな状態です。
プログラミングの設計においては、凝集度とは真逆で、結合度はできるだけ低く(弱く)保つのが鉄則とされています。 お互いの繋がりが緩やかであればあるほど、部品の交換や修正が自由自在になり、安全なシステムが作れるからです。
身近な例え:直付けされたイヤホンとワイヤレスなBluetooth¶
この結合度の違いも、私たちの身の回りにある家電やツールの接続方法に例えると一発で理解できます。 まず、結合度が最も強い密結合の状態とは、古い携帯ゲーム機にスピーカーの配線が直接ハンダ付けされているようなイメージです。
もしスピーカーが壊れて新しいものに取り替えたいと思ったら、本体を分解して配線を切断し、複雑な修理作業をしなければなりません。 これに対して、結合度が最も弱い疎結合の状態とは、現代のスマートフォンとBluetoothイヤホンの関係性です。
両者は電波を通じて緩やかに繋がっているだけなので、イヤホンが壊れたら新しい別のメーカーのイヤホンへ一瞬で切り替えられます。 スマホ側の内部構造を改造する必要は一切ありませんし、イヤホン側もスマホの機種が何であるかを深く知る必要はありません。
プログラムの部品同士も、このBluetoothのような関係性で繋いでおくことが、変化に強いシステムを作るための秘訣です。
結合度の6段階をスッキリ整理¶
結合度にも、凝集度と同じように、その結びつきの強さに応じて6つの段階が明確に定義されています。 ここでも、最も危険な密結合のレベルから順番に、その特徴を分かりやすく紐解いていきましょう。
それぞれの段階で、部品同士がどれだけ相手のプライベートな領域に踏み込んでいるかに注目してみてください。
1. 内容結合(最も悪い)¶
内容結合とは、ある部品が、別の部品の内部にあるデータやコードを直接書き換えたり、勝手に参照したりしている状態です。 オブジェクト指向プログラミングにおいて、クラスのプライベートな変数(隠されているべきデータ)を外部から無理やり書き換えるようなケースが該当します。
相手の内部構造を完全に知っている前提で動くため、片方を1行でも修正すると、もう片方が確実にクラッシュする最も恐ろしい結合状態です。
2. 共通結合¶
共通結合とは、複数の部品が、システム全体で共有されている巨大なグローバル変数をみんなで読み書きしている状態です。 どの関数がいつ、どのタイミングでそのグローバル変数の値を書き換えたのかを追跡するのが非常に難しくなります。
ある日突然データがおかしくなったときに、原因を作った犯人の関数を見つけ出すために、すべてのコードを捜索する羽目に陥ります。
3. 外部結合¶
外部結合とは、プログラムの外部にある共有要素(特定のファイルや、特定の形式のデータベースなど)に、複数の部品が依存している状態です。 共通結合と似ていますが、依存している対象がプログラムの外側にあるという点が異なります。
外部の仕様が少しでも変わると、それを参照しているすべての関数が一斉に動作不良を起こすため、油断できない結合度です。
4. 制御結合¶
制御結合とは、ある関数を呼び出す側が、相手の動きをコントロールするためのフラグ(スイッチ)を引数として渡す状態です。 呼び出される側の関数は、受け取ったフラグの値に応じて、内部のif文で全く異なる処理へと分岐することになります。
これは呼び出し側が、相手の内部にどんな分岐があるかを詳しく知っていなければならないため、関係性が一歩踏み込みすぎています。
5. スタンプ結合¶
スタンプ結合とは、関数にデータを渡す際、必要な値だけでなく、複数のデータが詰まった大きな複合オブジェクト(構造体やクラスのインスタンス)を丸ごと渡してしまう状態です。 例えば、ユーザーの年齢だけを知りたい関数なのに、名前や住所、クレジットカード情報まで入ったユーザーオブジェクトを丸ごと渡すケースです。
関数側は余計なデータまで見えてしまうため、無駄な依存関係が生まれ、他の場所でその関数を再利用するのが難しくなってしまいます。
6. データ結合(最も良い)¶
データ結合とは、関数が処理を実行するために必要な最低限のデータだけを、単純な引数として個別に受け取る状態です。 例えば、金額と消費税率だけを受け取って、計算結果の数値を返すような非常にシンプルな関係性です。
お互いは引数と戻り値という細い糸だけで繋がっており、相手の内部がどうなっているかには1ミリも興味を持っていません。 このデータ結合こそが、プログラムの独立性を最高に高めてくれる、私たちが目指すべき理想の接続スタイルです。
【コード例】強い結合(密結合)から弱い結合(疎結合)へ¶
それでは、実際のPythonコードを使って、強い結合(密結合)を美しい疎結合へと生まれ変わらせるリファクタリングの手順を見ていきましょう。 まずは、呼び出し側と呼び出される側がベッタリと癒着してしまっている、悪い結合度のコードをご覧ください。
以下のコードブロックは、商品の配送状況を更新するプログラムの例です。
class DeliveryManager:
def __init__(self):
self.status = "準備中"
class OrderProcessor:
def __init__(self):
self.manager = DeliveryManager()
def ship_order(self):
# 内容結合の悪い例:別クラスの内部変数を直接書き換えている
self.manager.status = "出荷完了"
print("注文を出荷しました。")
このコードでは、OrderProcessor が DeliveryManager の内部にある status という変数を外から直接書き換えています。
もし将来、管理クラス側の仕様が変わって変数の名前が delivery_status に変更されたら、このコードは即座にエラーになります。
では、この2つのクラスの結合度を弱くして、お互いをBluetoothのように自立した関係にリファクタリングしてみましょう。 修正後のクリーンなコードが、以下のプログラムです。
class RefinedDeliveryManager:
def __init__(self):
self._status = "準備中"
def update_status(self, new_status):
"""外部に公開された安全な窓口(データ結合)"""
self._status = new_status
class RefinedOrderProcessor:
def ship_order(self, manager_instance):
# 疎結合の良い例:相手の内部を知らず、メソッドを通じて最低限のデータだけを渡す
manager_instance.update_status("出荷完了")
print("注文を出荷しました。")
リファクタリング後は、RefinedOrderProcessor は相手の内部に変数が存在することすら知りません。
ただ用意された窓口である update_status を呼び出し、必要な文字列を渡しているだけです。
これなら、管理クラス側が内部の変数をどれだけ自由に書き換えても、呼び出し側のコードに影響が及ぶことは絶対にありません。 これこそが、結合度を低く保つということの大いなるメリットです。
凝集度と結合度の関係性を表でマスターしよう¶
ここまで、高めるべき凝集度と、低く抑えるべき結合度という、2つの重要なモノサシを個別に学んできました。 ここで一度、頭の中を整理するために、これら2つの概念が織りなす関係性を一覧にまとめてみましょう。
目指すべき理想は「高凝集・疎結合」¶
優れたソフトウェア設計の共通言語として、常に語られるキーワードが高凝集・疎結合(こうぎゅうしゅう・そけつごう)です。 これは、1つひとつの部品は自分の仕事だけに熱中し(高凝集)、部品同士の繋がりは最低限のあっさりした関係に保つ(疎結合)という意味です。
この絶妙なバランスが達成されたとき、プログラムは驚くほど頑丈で、いくらでも形を変えられる柔軟性を手に入れます。 逆に、何でも屋の部品が集まってお互いにベッタリ依存している状態(低凝集・密結合)は、最悪のスパゲッティコードを生み出します。
一覧表で見る特徴とメリット・デメリット¶
それぞれの組み合わせがシステムにどのような影響を与えるのかを、一覧の表にまとめました。 自分の書いているコードが今どのエリアに属しているかを、コンパスのように確認してみてください。
各状態がもたらす開発現場でのリアルな特徴を、以下の表に表示します。
| 状態の組み合わせ | コードの見た目・特徴 | 開発におけるメリット | 運用におけるデメリット |
|---|---|---|---|
| 高凝集 × 疎結合(理想郷) | 1つの関数が短く、依存が少ない | 修正が超簡単でバグが起きない | 最初だけ設計を考える頭が必要 |
| 高凝集 × 密結合(おしい) | 役割は綺麗だが、単体で動かせない | 処理の場所は探しやすい | 片方を直すと全体がドミノ倒しになる |
| 低凝集 × 疎結合(もったいない) | 依存はないが、1つの関数が巨大 | 外部への影響は少ない | 関数の中身が複雑すぎて読めない |
| 低凝集 × 密結合(破滅の罠) | 何でも屋がグローバル変数で合体 | 最初の数行は勢いで早く書ける | どこを触っても壊れる維持不能な状態 |
この表を見れば分かる通り、私たちが目指すべき方向は一番上の高凝集・疎結合の一択しかありません。 プログラミングの現場で先輩たちが「もっと関数を細かく分けよう」と言うのは、この理想のバランスへコードを近づけるためなのです。
10年の経験から伝える「高凝集・疎結合」を実践するための思考法¶
頭では理論を理解できても、いざ真っ白なエディタを前にすると、どうやってコードを書けば良いか迷ってしまうものですよね。 ここからは、エンジニア歴10年の私が日々の開発で実践している、高凝集・疎結合を自然に生み出すための具体的な思考テクニックをお伝えします。
単一責任の原則(SRP)を日常生活に落とし込む¶
高凝集なコードを書くための最も強力な呪文は、単一責任の原則(Single Responsibility Principle)です。 これは、1つのクラスや関数は、たった1つの責任(変更する理由)だけを持つべきだという教えです。
これを日常生活に例えるなら、スマートフォンの便利機能ではなく、単機能の道具をイメージすると分かりやすいでしょう。 例えば、爪切りに小さなナイフやヤスリが何個も折りたたまれてついている多機能ツールがありますよね。
一見便利ですが、爪切りの切れ味が悪くなって買い替えるとき、まだ使えるハサミやナイフまで一緒に捨てることになります。 プログラムも同様に、スマートフォンのように何でもできる多機能を目指すのではなく、洗練された単機能の道具を並べる感覚で設計してみてください。
関数に名前をつけるときに、and(〜と〜をする)という言葉が頭に浮かんだら、それは役割が多すぎる危険なサインです。 その瞬間に、関数を2つに分けるチャンスが訪れたと捉える習慣をつけましょう。
引数の数を減らすことが疎結合への近道¶
結合度を劇的に下げるための最も簡単なハックは、関数の引数の数を限界まで減らすことです。 関数が受け取る引数の数が多いということは、それだけ外部の世界と多くのパイプで繋がっているという決定的な証拠になります。
目安として、1つの関数が受け取る引数は、多くても3つ以内に収めるのが理想的です。 もし引数が4つも5つも必要になったら、それは関数が他人の領域のデータに首を突っ込みすぎている可能性があります。
必要な値だけを厳選して渡すように意識するだけで、コードの結合度は自然とデータ結合のレベルまで下がっていきます。 呼び出し側のコードもすっきりと短くなり、テストコードを書くのも驚くほど楽になります。
【関連記事】 argsとkwargs とは?「可変長引数」を正しく理解しよう!
未来の自分を救うためのリファクタリング習慣¶
最後に強くお伝えしたいのは、最初から完璧な高凝集・疎結合のコードを書ける人は世界のどこにもいないということです。 どんなに経験豊富なシニアエンジニアであっても、最初に頭からひねり出すコードは泥臭くて汚いものです。
大切なのは、一度動いた後に、コードを綺麗に整えるリファクタリングの時間を必ず確保することです。 動いた、嬉しい、終わり、とするのではなく、一息ついてからコード全体を優しく見つめ直してみてください。
この関数は少し長すぎないか、別のクラスの変数に触りすぎていないか、とセルフチェックを行うのです。 このわずか5分の見直し習慣が、3ヶ月後の自分を絶望から救い、チームの仲間から信頼される綺麗なコードを生み出す源泉になります。
【関連記事】 早期リターンでネストを浅く! 読みづらいif文をスッキリさせるリファクタリング手法
まとめ¶
今回は、結合度と凝集度について詳しく解説しました。 一見難しそうな理論ですが、その本質は、役割をきっちり分けることと、お互いに干渉しすぎないことという、シンプルなルールです。
これらのモノサシを頭の片隅に置いておくだけで、日々のコードレビューの意図が深く理解できるようになり、自分の書くコードの質が爆発的に向上します。 プログラミングは、ただマシンに命令を下すだけでなく、人間にとっても読みやすい芸術作品を作るクリエイティブな活動です。
焦らずに、まずは今日の開発でつくる小さな関数から、高凝集・疎結合の第一歩を実践してみましょう!
ここまでお読みいただきありがとうございました。