趣味開発の CLI アプリを clean architecture 風に作ってみた
概要
趣味開発のアプリを、書籍Clean Architectureで紹介されているclean architectureという作法に従うように改修してみた。コードはこちら。 自分用に使うAtcoder出場支援CLIコマンドで、pythonで書かれている。
Clean Architecture って?
Uncle Bob によって 2012 年に提唱された アーキテクチャ。以下の図が有名。
コンポーネント間をレイヤーに分けて、依存の方向性を制御することに肝があるっぽい。
元のブログに書いてあることは私の理解だと以下の通りだ。
「コンポーネントは以下のレイヤーに分けた方がいい。上に紹介するレイヤー程えらく、下のレイヤーから参照される。逆に、上のレイヤーは下のレイヤーを参照してはいけない。」
- エンティティ: 扱いたい話の中核となる、 企業内全体において共通する ルールや構造を置くレイヤー。重要なデータ構造とかはここ
- ユースケース: アプリ固有の使われ方 などを置くレイヤー。データがどう渡されてどう流れていくかの情報を持つ
- インターフェースアダプター: GUIとか DB とつなぐためのデータ変換などをする
- フレームワークやドライバ: DBとかweb フレームワークとか。我々がここのコードを書きまくることはあまりない
また、上で紹介した和訳には「典型的なシナリオ」と題して Java で構築したウェブベースアプリの構成図がある。 (和訳第1版1刷p204)
これらを踏まえた上で以下のように実装した。
自分の実装方針
インターフェースを適切に切ることで結合を疎にし、依存性注入(もしくは依存物注入)ができるようにする
Clean Architecture の思想の根幹部分だと思う。
OutputBoundaryとInputBoundaryを別個に設けない
元の構成図だと、Webであることもあって Controller と Presenter が別個に用意されている。
Interactor のインスタンスは Presenter の実装を持っていて Presenter のメソッドを呼び出し、Controller のインスタンスは Interactor のインスタンスを持っていて Interactor のメソッドを呼び出すようになっている。
今回はCLIアプリなので、 ControllerがBoundaryのメソッドを呼び出したら、Boundaryから普通のメソッド返り値として値が帰ってくれば十分と考えた。
DIライブラリを使う
Injectorというライブラリを採用した。
詳細は前に私が書いた記事を参照してほしい。(TODO: 記事へのリンクを書く)
ディレクトリ構成
上記の点を踏まえて、以下のようなディレクトリ構成になった。
- エンティティ層(entities)にはデータ構造を保持する
- ユースケース層(application)には以下を定義する
- まさに日常語の意味でのユースケースを定義したユースケースインターフェース
- ユースケースの実装であるインタラクタ
- インタラクタを実装するために必要なリポジトリインターフェース(File System、ネットなどの外界とのデータのやり取りを全部ここに押し込めた)
- インターフェースアダプター層(adapter)には以下を実装する
- ユーザーとのCLIのやりとりを行うコントローラー
- repositoryとの実装であるインフラストラクチャ
まとめ・感想
たくさん記事を読んだが、どうしても内容が抽象度の高い話なので具体的な実装に落とすのに苦労した。
書籍 Clean Architecture に書いてあった Java での web アプリ構成例は大いに参考になった。
Discussion