- 複雑な Python アプリケーションは規模が大きくなるほど、単純な実装方法だけではテストや変更に対応しにくくなります。本書はその解決策として、アーキテクチャパターンをコード例で扱います
- MADE.com のオンライン家具販売とグローバルサプライチェーンを例に、現実の運用課題をソフトウェアモデルへ移すドメインモデリングを中心に据えています
- 中核となる軸は TDD、DDD、イベント駆動アーキテクチャであり、高速な単体テストと少数の E2E テスト、インフラから分離されたモデル、メッセージベースの統合を目指します
- Flask、SQLAlchemy、pytest、Docker、Redis を使用しますが、特定の技術選択が実装の詳細へ押し下げられる構造を作ることに焦点を当てています
- 複雑な Python アプリケーションを扱った経験があれば読める内容で、DDD や古典的なアプリケーションアーキテクチャパターンを事前に知っている必要はありません
テストしやすい構造から出発した問題意識
- Harry の前著 Test-Driven Development with Python の後、アプリケーションをどのように構造化すればテストしやすくなるのかという問いが残りました
- 重要なのは、ビジネスロジックを単体テストで十分に扱いながら、統合テストと E2E テストの数を最小限に抑える構造を作ることです
- 「Hexagonal Architecture」「Ports and Adapters」「Functional Core, Imperative Shell」といった概念には触れていたものの、当時は実際には十分に理解したり実践したりできていない状態でした
- Bob はチーム内にソフトウェアアーキテクチャを担う人がいなかったためアーキテクトになり、Ian Cooper からコードの書き方と思考法に関する新しいアプローチを学びました
MADE.com の事例:サプライチェーンをソフトウェアでモデル化する
- 2人の著者は欧州の e コマース企業 MADE.com で働き、本書の手法を実際のビジネス課題をモデル化する分散システムの構築に適用しました
- 例題のドメインは、Bob が MADE で最初に作ったシステムを基にしており、新しいプログラマーがチームに加わる際に教えるべき内容を整理する目的があります
- MADE.com は貨物パートナーとメーカーからなるグローバルサプライチェーンを運営しています
- コストを下げるため、在庫を倉庫に長く積み上げないよう配送を最適化しようとしています
- 理想的には、顧客がソファを購入したまさにその日に港へ到着し、保管を挟まず顧客の家へ配送される流れを望んでいます
- コンテナ船で商品が到着するまでに3か月かかることもあり、タイミング調整は困難です
- 実際の運用では、破損、浸水、嵐による遅延、物流パートナーの処理ミス、書類の不足、顧客の注文変更といった変数が絶えず発生します
- こうした問題に対処するため、現実世界の運用をソフトウェアで表現し、可能な限り多くの業務を自動化しようとします
Python プロジェクトが大きくなると見えてくる限界
- Python は急速に成長し成熟してきましたが、C# や Java の世界が長く扱ってきた種類の問題を、いま本格的に担い始めた段階だと見ています
- スタートアップは実際のビジネスになり、Web アプリやスクリプトによる自動化はエンタープライズソフトウェアへと成長していきます
- Python の哲学には “There should be one—and preferably only one—obvious way to do it” がありますが、プロジェクト規模が大きくなると、最も obvious な方法が複雑さや要件変更を管理するうえで常に適しているとは限りません
- 本書で扱う手法やパターンは新しいものではありませんが、その多くは Python の世界では比較的新しいものだと見ています
- Eric Evans の Domain-Driven Design、Martin Fowler の Patterns of Enterprise Application Architecture を置き換えようとする本ではなく、それらの古典を頻繁に参照し、読むことを勧めています
- 既存文献のコード例は Java や C++/# で書かれていることが多く、Python 開発者には読む負担が大きい場合があります
複雑さを管理するための3つの道具
- テスト駆動開発(TDD) は正しいコードを作り、回帰を恐れずにリファクタリングしたり機能を追加したりできるようにします
- できるだけ高速にテストを実行する方法
- 高速で依存関係のない単体テストから、できるだけ多くのカバレッジとフィードバックを得る方法
- 遅く不安定な E2E テストを最小限に抑える方法を扱います
- ドメイン駆動設計(DDD) はビジネスドメインのよいモデルを作ることに集中させます
- モデルがインフラ上の関心事に縛られないようにする方法
- 変更しにくいモデルにならないようにする方法を扱います
- メッセージで統合される疎結合のマイクロサービス、ときに reactive microservices と呼ばれる方式は、複数のアプリケーションやビジネスドメイン間の複雑さを管理する解決策として扱われます
- Flask、Django、Celery など Python エコシステムの既存ツールとどう組み合わせるかは、常に明確とは限りません
- マイクロサービスを使わない、あるいは関心がない場合でも、本書の大半のパターンとイベント駆動アーキテクチャの内容の多くはモノリシックアーキテクチャにも適用できます
読者と前提知識
- 本書は、ある程度複雑な Python アプリケーションを身近に扱ったことのある読者を想定しています
- 複雑さの管理から生じる痛みを経験した読者に向けられています
- DDD や古典的なアプリケーションアーキテクチャパターンに関する事前知識は必要ありません
- 説明はサンプルアプリケーションを中心に、章ごとに積み上げていく形です
- 著者たちは仕事で TDD を使っているため、まずテストコードを示し、その後に実装を示す流れをよく使います
- Flask、SQLAlchemy、pytest、Docker、Redis を使いますが、すでに慣れていれば役立つというだけで必須ではありません
- 主要な目標の1つは、特定の技術選択が些細な実装の詳細になるアーキテクチャを作ることです
本の構成
- 本書は2部に分かれています
-
第1部:ドメインモデリングを支えるアーキテクチャ
- ドメインモデリングと DDD は第1章、第2章、第7章で扱います
- 複雑なビジネス課題をコード内のドメインモデルに反映すべきだという前提に立ちます
- 外部依存がなく、高速な単体テストが可能なモデルから始める方法を説明します
- その後、適切な aggregate の選択とデータ整合性の問題を改めて扱います
- Repository、Service Layer、Unit of Work パターンは第2章、第4章、第5章で扱います
- これらのパターンは、モデルを不要な依存関係から切り離すために互いを補完します
- 永続ストレージの周囲に抽象化層を作り、システムの入口と主要なユースケースを捉えるサービス層を置きます
- Flask API や CLI のような薄い入口を作りやすい構造を示します
- 抽象化とテストに関する議論は第3章と第5章へ続きます
- Repository パターンを紹介した後、抽象化を選ぶ方法と結合の仕方における抽象化の役割を扱います
- Service Layer パターンの後には、テストピラミッドと、可能な限り高い抽象化レベルで単体テストを書く方法を扱います
-
第2部:イベント駆動アーキテクチャ
- イベント駆動アーキテクチャは第8章から第11章で扱います
- Domain Events、Message Bus、Handler パターンを紹介します
- Domain Events は、システム内のある相互作用が別の動作を引き起こすという概念を表す手段です
- Message Bus は、動作がイベントを発生させ、適切な handler を呼び出せるようにします
- イベントをマイクロサービスアーキテクチャにおけるサービス間統合パターンとして使う方法を扱います
- commands と events を区別し、アプリケーションは本質的にメッセージ処理システムになります
- 第12章では CQRS の例を、イベントを使う方式と使わない方式の両方で扱います
- 第13章では明示的・暗黙的な依存関係を整理し、簡単な依存性注入フレームワークを実装します
- エピローグでは、新しく始める単純な例ではなく、既存ソフトウェアにこうした原則を適用する方法と追加の読み物を提供します
サンプルコードと実際に試す方法
- 本書は1つのサンプルプロジェクトを中心に構成され、章が進むにつれてプロジェクトを段階的に拡張します
- 読者が実際にコードに触れ、パターンがどのように機能するのか感覚を得ることを重視しています
- すべてのコードは GitHub にあり、各章ごとに別ブランチがあります
- 進め方として3つの方法が提案されています
- 自分でリポジトリを作り、本書の例に沿ってアプリを構築し、必要に応じて著者たちのリポジトリを参照する
- 各パターンを章ごとに自分の小さなプロジェクトへ適用してみる
- 各章の「Exercise for the Reader」と、一部が空欄になっている GitHub のコードを使って素早く実習する
- 特に自分のプロジェクトにパターンを適用しようとする読者にとっては、単純な例を先に扱うことが安全な練習になります
- 少なくとも各章を読む際には、リポジトリから
git checkout でコードを取得し、実際に動くアプリの文脈でコードを確認することを勧めています
ライセンスと形式
- コードとオンライン版は Creative Commons CC BY-NC-ND ライセンスです
- 印刷版は別ライセンスに従い、再利用に関する懸念がある場合は O’Reilly に問い合わせるよう案内しています
- 本書の表記規則では、イタリック、固定幅、固定幅太字、固定幅イタリックを区別して使います
- イタリックは新しい用語、URL、メールアドレス、ファイル名、拡張子を表します
- 固定幅はプログラムリストとコード要素を表します
- 固定幅太字は、ユーザーがそのまま入力すべきコマンドやテキストを表します
- 固定幅イタリックは、ユーザーが提供する値、または文脈に応じて決まる値で置き換えられるテキストを表します
1件のコメント
日本語版が出ています。Pythonで見るアーキテクチャパターン