はじめに
頑張れば、何かがあるって、信じてる。nikkieです。
新年明けましておめでとうございます🎍🐮
ブログの書き初めは、冬の休暇に手を動かした、PythonでClean Architecture本についてです。
この1年Clean Architectureについて学ぶ機会が多かったのですが、Pythonで独力で書ける気が全然しませんでした。
— nikkie (@ftnext) 2020年12月30日
よく作りたいけどCAで具体的にどうすればいいか分からず結局いつもの作り方。。
そこでキャッチアップが重要と考えEuroPythonで知った https://t.co/8Fmen5sDOh を写経開始
目次
- はじめに
- 目次
- Clean Architectureと私
- 『Clean Architectures in Python』(1st edition)
- Part 2 - Chapter 2 での学び
- Clean Architecture以外での学び
- 終わりに
Clean Architectureと私
ソフトウェアはやっぱりソフトに(=変更しやすいように)作りたいなと私は強く思います。
2020年はClean Architectureについてたびたびインプットしました。
例えばnrslibさんのYouTube配信です。
こういったインプットを経て、「Clean Architecture、概念の理解は深まったと思うけれど、Pythonで具体的にどうやればいいんだろう?」という課題感を感じていました。
層の概念はいわゆる"完全に理解した"けれど、それをPythonのコードに落とし込んだらどうなるのかが分からなかったわけです。
7月のEuroPythonで『Clean Architectures in Python』という本を知りました1。
これは積ん読になっていたのですが、ヴァケイションには「緊急なことじゃなくて、自分にとって重要なことをやろう」と写経してみました。
学んだことをここにアウトプットします。
『Clean Architectures in Python』(1st edition)
この本では、物件情報を一覧にするWeb APIを例にClean Architectureが解説されます。
本は2つのPartに分かれます:
- 前半(Part 1)はTDD導入パート
- ユニットテストコードの書き方を解説する
pytest
やモックについてカバー
- 後半(Part 2)は物件情報一覧API(面積や賃料、緯度経度)を実装
- TDDで進める(まずテストコードが出てくる)
Flask
製
nikkieのレベル感は以下です:
- ふだんは
unittest
でTDD。pytest
のコードも雰囲気で読めそうなのでPart 1はskip Flask
はHello Worldから先はあまり踏み込めておらず。この本では blueprint や configuration を駆使2してAPIを実装。Flask
の本ではないとのことですが、ドキュメントへのリンクは充実しています。深く理解しているわけではない概念についてもキャッチアップしてついていけました
今回はClean Architectureの理解が目的なので、pytest
やFlask
の厳密な理解はヤクの毛刈りと考え、あまり深追いせずに進めました。
Part 2 - Chapter 2 での学び
ビジネスロジック部分をClean Architectureで作ると、UIはCLIでもWeb APIでもなんでも採用できそうという感触を得ました。
12月のPHPカンファレンスでnrslibさんが共有していた、「次のフレームワークに持っていく」ってこういう考え方なんですね!
PythonはWebフレームワークが乱立してますが、Clean Architectureで作ったビジネスロジック部分は移動しやすそうです。
そう思った2章のコードはこちら:
repo = mr.MemRepo([room1, room2, room3]) use_case = uc.RoomListUseCase(repo) result = use_case.execute()
やっていることは
これだけ!
このコード以外はCLIを扱うコードでもWeb APIを扱うコードでもいいわけです。
3つの層:エンティティ/ユースケース/外部システム
この本ではClean Architectureを3つの層のアーキテクチャとして紹介しています(Part 2 - Chapter 1参考)。
- エンティティ=ドメインモデルの表現(例:部屋 Room)
- ユースケース=アプリケーションの処理(例:部屋の一覧を取得)
- 外部システム=ユースケースが使うインターフェースを実装(例:特定のフレームワークやデータベース)
3つの層は
内側:エンティティ < ユースケース < 外部システム:外側
という包含関係にあります。
これらの層の間には
Talk inwards with simple structures, talk outwards through interfaces
(意訳:内側の層に対してはPythonのデータ構造やエンティティに定義された単純なデータ構造で依存せよ。外側の層に対してはインターフェースを介して依存せよ)
という原則があります。
この本を読んで、一番腑に落ちたのは
というところです。
先のコードで use_case.execute()
を実行すると
class RoomListUseCase: def __init__(self, repo): self.repo = repo def execute(self): return self.repo.list()
ユースケース初期化時に渡されたリポジトリのlist
メソッドを呼び出します。
ユースケースはリポジトリ(外部システム)のAPIを知っていて、list
を呼び出せば物件が取得できると分かっているわけです。
ユースケースという概念
今回ユースケースという概念を知れたのが大きいと思っています。
私がプログラミングに入門したとき、クラスの入門例がDogやCat、CarやSuperCarでした。
これらの例は、現実の具体的な事物と対応しているので(私が過学習してしまって)、現実の具体的な事物と対応しないクラスは独力ではなかなか思いつきません。
処理を表すクラス(現実の具体的な事物と対応するわけではない)を作るというのを知ったときは衝撃でした。
今回のユースケースもそのときと同じくらいの衝撃です。
ユースケースを初期化する時にリポジトリを渡すというのも変更しやすさの妙だなと思います。
Chapter 2ではインメモリのリポジトリを渡していますが、これはDBに接続するリポジトリに変わるでしょう。
そうなってもユースケースからはlist
というAPIを使うだけなので、リポジトリを付け替えるだけで動作確認が簡単にできますよね。
DBを準備しなくてもインメモリのリポジトリを用意すれば動作させられます(nrslibさんたちが言ってたやつだ!)
用語:モデル/リポジトリ
この本でありがたかったのは、用語の誤解に先手を打っていたこと。
エンティティはドメインモデルの表現と説明する中で、ドメインモデルはDjangoなどのフレームワークにおける"モデル"とは異なると言っています。
ドメインモデルは軽量(lightweight)なモデルで、自身をストレージに保存するメソッドや、JSON文字列としてダンプするメソッドは持ちません。
リポジトリもGitのリポジトリとは無関係です。
外部システムのストレージにアクセスするものはリポジトリと呼ばれます。
リポジトリはドメインモデルを返します。
先の例ではユースケースはリポジトリから返ってきたドメインモデルを扱うわけです。
Clean Architecture以外での学び
JSON文字列を返すためのserializer実装
json.JSONEncoder
を継承したクラスを定義し、default
メソッドを実装、それをjson.dumps
のcls
引数に指定しています。
pytestのdeprecation
py.test
というコマンドが出てきて気になったのですが、pytest
コマンドが推奨されているそうです。
pytest-flask
向けにtests/conftest.py
を作ったところ、@pytest.yield_fictures
にPytestDeprecationWarning
が上がりました。
deprecateされていて、@pytest.fixture
でいいそうです。
終わりに
「Clean Architecture、Pythonで具体的にどうやればいいんだろう?」
冒頭の問に対して暫定的な答えは得られました。
ユースケースを使った実装を練習していきます!
層の数の違いなどUncle Bobの『Clean Architecture』とは厳密には違うのかもしれませんが、「変更しやすい設計でどう作ればいいか」かなり具体的に分かったので、今の私としては大満足です。
今回のコードはこちら
続くChapter 3では部屋を絞り込む機能を追加します。
実装する上で、リポジトリへのリクエストを表すオブジェクトとレスポンスを表すオブジェクトが登場しました。
これらの扱いも学びが多く、またの機会にアウトプット予定です!
ここまで読んで『Clean Architectures in Python』に興味を持った方、先日2nd Editionがリリースされました🎉
サンプルは変わっていないそうですが、dataclass
を使っていたり、分かりやすそうな図が追加されていたりするので、復習がてら読んでみようかと思います。
Clean Architectures in Python
— Leonardo Giordani (@tw_lgiordani) 2020年12月31日
A practical approach to better software design
Thanks to more than 14k people who downloaded the first edition
The second edition is out todayhttps://t.co/rC7Mhoxucu#Python #TDD #pycabook #clean #architecture pic.twitter.com/jpLZF3hcE7
そしてなんと、月末にはUncle Bobの話が聞ける機会があるので、今よりもう少し理解度を上げて参加するのを目指します。
【1/29(金) オンライン開催】Clean Architectureの提唱者であるRobert C. Martin氏が登壇する「ON AIR #3 クリーンアーキテクチャ」の詳細を公開しました。Uncle Bobに直接質問できる機会も設けております。是非ご参加ください。#buildersbox
— Builders Box (@BuildersBox) 2020年12月24日
▼詳細/新規会員登録はこちらからhttps://t.co/K8ITQlsOGa pic.twitter.com/HSDSlTWLsU
それでは!
-
Clean Architectures in Python — EuroPython 2020 Online · 23-26 July 2020 ↩
-
Flask
、Hello Worldで入門するのは簡単ですけど、うまく使おうと思ったらblueprintやconfiguration など結構キャッチアップがいりますよね(キャッチアップの総量はDjangoとあまり変わらない感覚)↩