1年前、友人のRoberto Ciattiが 、Robert Martinがクリーンアーキテクチャと呼ぶ概念を紹介しました。 ボブおじさんは会議でこの概念について多くのことを話し、それについて非常に興味深い記事を書いています。 「クリーンアーキテクチャ」とは、厳密なルールを超えて、ソフトウェアシステム、参加者のさまざまな層と役割に関する一連の合意を構成する方法です。
彼がすでに記事「Pure architecture」 (Habréの翻訳)で述べたように、アプローチ自体のアイデアは新しいものではなく、過去3〜10年にわたって多くのソフトウェア開発者によって推進されてきた多くの概念に基づいています。 最初の実装の1つは、1992年に公開されたIvar Jacobksonの傑作であるオブジェクト指向ソフトウェアエンジニアリング:先行指向アプローチで提案されたBoundary-Control-Entityモデルにあります。 しかし、Martinはこのアーキテクチャの他の最新バージョンもリストしています。
ここで彼がすでに説明したことを繰り返しません(彼よりも上手くできない)、これらの概念に慣れるためにあなたが見ることができるいくつかのリソースへのリンクを単に投稿します:
- 「クリーンアーキテクチャ」は、アーキテクチャの目標を簡潔に説明するRobert Martinの投稿です。 また、同様のアーキテクチャを持つリソースもリストします。
- オープン・クロージャの原則-Robert Martinによる記事。クリーンアーキテクチャの概念とは強く関係していませんが、分離の概念を理解するために重要です。
- 客家ラボ:ロバート「ボブおじさん」マーティン- 建築:客家ラボのロバート・マーティンの失われた年のビデオ。
- DDDおよび Lauri Taimilaのテスト戦略
- (近日公開)ロバートマーティンの Prentice Hallから出版されたPure Architectureの本。
この記事の目的は、クリーンなアーキテクチャーを使用してゼロからPythonでWebサービスを作成する方法を示すことです。 この多層設計の主な利点の1つはテスト容易性であるため、TDDアプローチに従ってプログラミングします。 このプロジェクトはもともと約3時間でゼロから開発されました。 プロジェクトのキャラクターの特性を考慮して、最終コードを簡素化するためにいくつかの決定が行われました。 これらの簡略化を指摘し、必要に応じて説明します。
PythonのTDDについて詳しく知りたい場合は、 このカテゴリの記事を読んでください。
プロジェクトの概要
Rent-O-Maticプロジェクト( Tentacle Dayファンはリンクをキャッチできます)の目標は、いくつかの値で記述されたオブジェクトのデータセットの上に単純な検索エンジンを作成することです。 この検索エンジンでは、フィルターを設定して検索を絞り込むこともできます。
データレコードは、賃貸料の保管施設であり、次の値で説明されます。
- 一意の識別子
- 平方メートル単位の面積
- ユーロ/日でのレンタル価格
- 座標(緯度と経度)
純粋なアーキテクチャには、システムのさまざまな層の分離が含まれます。 アーキテクチャ自体は、4つ以上の実際のコードモジュールで実装できる4つの層で記述されます。 これらのレイヤーについて簡単に説明します。
エンティティ
これは、ドメインモデルが記述されるレベルです。 ここで、データベースに保存されているデータに関するストレージ機能を表すクラスを作成する必要があります。 私の意見では、このクラスはビジネスプロセスの実装に必要な情報も提供します。
このレイヤーのモデルは、Djangoなどのフレームワークの通常のモデルとは異なることを理解することが重要です。 これらのモデルはデータストレージシステムに関連していないため、これらのクラスのメソッドを使用して直接保存または取得することはできません。 これらには、ビジネスルールに関連するヘルパーメソッドが含まれています。
シナリオ
この層には、システムに実装されたスクリプトが含まれています。 この単純な例では、指定されたフィルターに従ってストレージ施設のリストが表示されるシナリオは1つだけです。 ここにスクリプトを配置して、倉庫に関する詳細情報、または倉庫の予約、商品の充填など、その他の必要なビジネスプロセスを表示することもできます。
インターフェースアダプター
この層は、ビジネスロジックと外部システムの境界に対応し、それらとデータを交換するために使用されるAPIを実装します。 ユーザーインターフェイスのようなストレージシステムは、このレイヤーの外部システムであり、スクリプトとデータを交換する必要があります。 そして、この層は、そのようなデータストリームのインターフェイスを提供します。 このプロジェクトでは、外部Webサービスを構築できるJSONシリアライザーを介してビューとの通信が提供されます。 ストレージアダプタは、さまざまなストレージシステムで動作する共通のAPIを記述します。
外部インターフェース
アーキテクチャのこの部分は、前の層で定義されたインターフェースを実装する外部システムで構成されています。 ここでは、たとえば、JSONシリアライザーを介して(スクリプトの一部として)データにアクセスする(REST)エントリポイントを実装するWebサーバーを見つけることができます。 たとえば、MongoDB用のストレージ実装もあります。
APIとシェード
クリーンなアーキテクチャでは、APIという言葉は重要です。 各レイヤーには、 エントリポイント (メソッドまたはオブジェクト)の固定セットであるAPIを使用してアクセスできます。 「修正済み」とは、「各実装で同じ」ことを意味します。明らかに、APIは時間とともに変化する可能性があります。 各プレゼンテーション方法は同じシナリオと同じ方法を参照して、この特定のシナリオから生じるドメインモデルを取得します。 これらはプレゼンテーション層に移動し、このデータは、HTML、PDF、画像などの情報の特定の表現に従ってフォーマットされます。 拡張ベースのアーキテクチャを理解している場合は、分割されたAPI駆動型コンポーネント(またはレイヤー)の基本概念を既に理解している必要があります。
同じ概念がストレージレイヤーにも当てはまります。 各ストレージ実装は同じメソッドを提供する必要があります。 スクリプトを扱う場合、どのストレージシステムが使用されているかを考える必要はありません。ローカルのMongoDB、クラウドストレージシステム、または簡単なインメモリテーブルなどです。
レイヤー間の分離、および各レイヤーのコンテンツは、常に変更されたままであるとは限りません。 適切に設計されたシステムは、パフォーマンスやその他の特定の要件などの問題に対処する必要があります。 アーキテクチャを設計するとき、何を、どこで、なぜ知っていることが重要です。 ルールを自分で「微調整」する時期を知ることは特に重要です。 すべての質問に明確に「黒」または「白」で回答できるわけではありません。 多くの決定は「灰色の影」です。つまり、何を、なぜ、どこに置くべきかを自分で決めなければなりません。
しかし、主なことは、純粋なアーキテクチャの構造を混乱させることではありません。 特に、 データフローの問題で揺るぎないようにする必要があります(Robert Martinの記事の「境界線を越える」セクションを参照)。 データフローを中断すると、構造全体が破壊されます。 繰り返しますが、データの流れを中断しないでください。 データフロー違反の例は、このクラスを表すのではなく、何らかのスクリプトによるPythonクラスの発行です(たとえば、JSON文字列として)。
プロジェクト構造
プロジェクトの構造を見てみましょう。
Cookiecutterを使用してプロジェクト構造を構築しました。 この部分を流walkに説明します。 rentomatic
カタログには、次のサブディレクトリが含まれています。
-
domain
-
repositories
-
REST
-
serializers use_cases
これらのディレクトリは、前のセクションで示した階層構造と、テストを簡単に見つけられるように作成されたテストディレクトリの構造を反映しています。
ソースコード
このGitHubリポジトリでソースコードを見つけることができます 。 彼から分岐し、実験し、変更し、この記事で説明する問題を解決するためのより成功する方法を探してください。 ソースコードにはタグ付きのコミットが含まれています。これにより、記事で説明されている作成プロセスをたどることができます。 ラベル<Gitタグ:タグ
>は、記事自体の見出しの下に配置されます。 ラベルは、GitHubのタグを持つコミットへのリンクです。これにより、githubに移動して、コードを複製せずにコードを確認できます。
プロジェクトの初期化
Gitタグ: Step01
更新: この cookiecutter パッケージは、このセクションとまったく同じ環境を作成します。 次の説明では、依存関係と構成を管理する方法を説明し、このツールを詳しく調べます。次のプロジェクトで使用する可能性があります。
通常、プロジェクト内にPython仮想環境をデプロイするのが好きなので、一時的な仮想環境を作成して、Cookiecutterを設定し、プロジェクトを作成して、virtualenvを削除します。 cookiecutterは、初期ファイル構造を提供するために、あなたとプロジェクトについていくつか質問をします。 独自のテスト環境を作成するので、 use_pytest
「no」と言う方が良いでしょう。 これはデモプロジェクトであり、公開する必要がないため、 use_pypi_deployment_with_travis
にuse_pypi_deployment_with_travis
「no」と回答できます。 プロジェクトにはコマンドラインインターフェイスがありません。作成者ファイルを安全に作成し、ライセンスを使用できます。
virtualenv venv3 -p python3 source venv3/bin/activate pip install cookiecutter cookiecutter https://github.com/audreyr/cookiecutter-pypackage
質問に答えてから、次のコードを使用してプロジェクトを完了します
deactivate rm -fR venv3 cd rentomatic virtualenv venv3 -p python3 source venv3/bin/activate
Cookiecutterが作成したrequirements_dev.txtファイルを取り除きます。 私は通常、virtualenvの依存関係を異なる階層ファイルに保存して、本番環境、開発環境、およびテスト環境を分離するため、 requirements
ディレクトリと対応するファイルを作成しましょう。
mkdir requirements touch requirements/prod.txt touch requirements/dev.txt touch requirements/test.txt
test.txt
ファイルには、プロジェクトのテストに使用される特定のパッケージが含まれます。 プロジェクトをテストするには、開発環境用のパッケージをインストールする必要があるため、ファイルに開発の依存関係を含める必要があります。
-r prod.txt pytest tox coverage pytest-cov
dev.txt
ファイルには、開発プロセス中に使用されるパッケージと、テストおよび本番用のインストールパッケージが含まれます。
-r test.txt pip wheel flake8 Sphinx
( test.txt
すでにprod.txt
含まれているという事実を利用しています)。
最後の基本的なrequirements.txt
ファイルは、単にrequirements/prod.txt
インポートしrequirements/prod.txt
-r prod.txt
明らかに、ニーズや好みに最適なプロジェクト構造を見つけることができます。 この構造はこのプロジェクトに適していますが、次のすべてのプロジェクトで使用することを強制しているわけではありません。
この分離により、コンピューターに本格的な開発環境をインストールし、Travisなどのテスト環境にテストツールのみをインストールし、実稼働環境へのインストールの依存関係の数を減らすことができます。
ご覧のとおり、依存ファイルではタグバージョンを使用していません。 これは、このプロジェクトが運用環境で起動されないため、環境を凍結できないためです。
virtualenv
内に開発依存関係をインストールすることを忘れないでください
$ pip install -r requirements/dev.txt
さまざまな構成
pytest
テストpytest
構成する必要があります。 これは、 pytest.ini
ファイルを介して行われます。このファイルは、ルートディレクトリ(setup.pyファイルがある場所)に作成できます。
[pytest] minversion = 2.0 norecursedirs = .git .tox venv* requirements* python_files = test*.py
プロジェクト開発中にテストを実行するには、単に実行します
$ py.test -sv
カバレッジを確認する場合、つまり テストによって実行されるコードの量、実行
$ py.test --cov-report term-missing --cov=rentomatic
テストカバレッジの詳細については、 Coverage.pyおよびpytest-covパッケージの公式ドキュメントをご覧ください 。
flake8
パッケージを使用して、 PEP8との互換性についてPythonコードをテストすることを強くお勧めします。 setup.cfg
ファイルに配置する必要があるflake8
設定は次のsetup.cfg
です。
[flake8] ignore = D203 exclude = .git, venv*, docs max-complexity = 10
コードがPEP8標準に準拠していることを確認するには、次を実行します。
$ flake8
この投稿の各ステップは、100%のコードテストとカバレッジを作成することに注意してください。 クリーンアーキテクチャの利点の1つは、レイヤー間の分離であり、これにより、より高いテスト可能性が保証されます。 ただし、このチュートリアル、特にRESTセクションでは、アーキテクチャの簡単な説明のために一部のテストが省略されることに注意してください。
パート2に続きます。