ヘキサゴナルアーキテクチャで学ぶ設計の本質:Pythonで実践する疎結合アプリ構築
1. 導入:なぜ今「ヘキサゴナルアーキテクチャ」なのか?
ソフトウェアの寿命は年々長くなり、保守性と柔軟性がますます求められるようになっています。アプリケーションの要件が変化しても、核となるビジネスロジックを傷つけずに拡張・修正できる構造が求められます。
こうしたニーズに応える設計思想の一つが「ヘキサゴナルアーキテクチャ(Hexagonal Architecture)」、別名「ポートとアダプタアーキテクチャ」です。本記事ではこのアーキテクチャの基本を学び、Pythonで簡単なアプリケーションを構築することで、疎結合設計の本質を実感していただきます。
2. ヘキサゴナルアーキテクチャとは?
ヘキサゴナルアーキテクチャは、以下の特徴を持つアーキテクチャスタイルです:
- ビジネスロジック(アプリケーションコア)を中心に置き、
- 入出力(ユーザーインターフェースやデータベース)を「アダプタ」として周辺に配置し、
- コアとアダプタの間を「ポート」で接続する。
この構成により、コアと外部の依存を逆転させ、テストしやすく拡張性の高い構造が実現します。
図解イメージ(リンク)
以下のサイトでは、構造のイメージをわかりやすく図解しています:
3. Pythonで簡単なヘキサゴナルアプリを作ってみよう
3.1 全体構成
myapp/ ├── domain/ # ビジネスルール │ └── model.py ├── usecase/ # アプリケーションロジック │ └── interactor.py ├── interface/ # アダプタ(入出力) │ ├── repository.py │ └── cli.py └── main.py # エントリーポイント
3.2 ドメイン層(ビジネスルール)
# domain/model.py class User: def __init__(self, user_id: int, name: str): self.user_id = user_id self.name = name
3.3 ポート(インタフェースの抽象)
# usecase/interactor.py from abc import ABC, abstractmethod from domain.model import User class UserRepository(ABC): @abstractmethod def save(self, user: User): pass class UserInteractor: def __init__(self, repository: UserRepository): self.repository = repository def create_user(self, user_id: int, name: str): user = User(user_id, name) self.repository.save(user) return user
3.4 アダプタ層(インフラ実装)
# interface/repository.py from usecase.interactor import UserRepository from domain.model import User class InMemoryUserRepository(UserRepository): def __init__(self): self.users = {} def save(self, user: User): self.users[user.user_id] = user print(f"Saved user: {user.name}")
# interface/cli.py from usecase.interactor import UserInteractor from interface.repository import InMemoryUserRepository def run(): repo = InMemoryUserRepository() interactor = UserInteractor(repo) interactor.create_user(1, "Alice")
3.5 エントリーポイント
# main.py from interface.cli import run if __name__ == "__main__": run()
4. 疎結合のメリットを実感しよう
ヘキサゴナルアーキテクチャを使うことで、以下のようなメリットを享受できます:
- テストの容易さ:ビジネスロジックが外部依存から隔離されており、Mockでテスト可能。
- 保守性の高さ:UIやDBの変更がコアに影響を与えない。
- 拡張性:新しいインターフェース(REST API、CLI、バッチ)を容易に追加可能。
たとえば、CLIをWeb APIに置き換えたくなった場合でも、UserInteractor
には一切変更が必要ありません。
5. トラブルシューティングと注意点
問題 | 原因 | 対策 |
---|---|---|
TypeError: Can't instantiate abstract class |
ポートの抽象クラスを直接インスタンス化しようとした | 実装クラス(アダプタ)を使うこと |
コードが複雑に感じる | 層の分離による初期コスト | 小さく始めてスケールさせる設計を意識 |
循環インポートエラー | ドメイン層とインターフェースが直接参照し合っている | 依存の方向性を守る(コア→外部のみ) |
6. まとめ
ヘキサゴナルアーキテクチャは、複雑なアプリケーションを「コアと外部の明確な分離」という設計哲学で整理する強力な方法論です。Pythonのような動的言語でも、抽象クラスやディレクトリ構成を通じて、この設計手法を実践できます。
今回の例はごく基本的なものですが、実際の業務アプリケーションにも応用可能です。次のステップとしては以下の内容をおすすめします:
参考リンク・書籍
リンク
リンク