概要
Pythonで開発する場合でもレイヤードアーキテクチャーをベースとした設計をすることがあります。
その時、依存の方向性をチェックしたくなる時があります。
project_root/
├ infrastructure/
│ └ db
├ interface/
│ └ controllers
├ application/
│ └ service
└ domain/
└ entity
例として上記の様なパッケージ構成を考えます。
依存の方向性をinfrastructure -> interface -> application -> domain
と言った形で定義しているとします。
開発時にルールを破っているインポートを自動でチェックするにはimport-linterを使うと簡単に解決できます。
サンプルのリポジトリを用意しました。ソースコード全体はこちらを参照してください。
使い方
$ pip install import-linter
setup.cfg
か.importlinter
でレイヤーの定義と依存の方向性を定義します。
まずは[importlinter]
のセクションでレイヤーの定義をします。
[importlinter]
root_packages =
infrastructure
interface
application
domain
type = layers
はレイヤードアーキテクチャ用のルール設定です。
依存の方向性をレイヤーの順序で表現しています。
[importlinter:contract:1]
name = layered architecture contract
type = layers
layers =
infrastructure
interface
application
domain
様々なオプションがあり柔軟なルールを構成することができます。
例えばflaskのパッケージのインポートを特定のレイヤーに限定したい場合などは、include_external_packages
を有効にして下記のようにtype = forbidden
で定義することができます。
[importlinter]
root_packages =
infrastructure
interface
application
domain
include_external_packages = True
[importlinter:contract:2]
name = Do not use `flask` outside the interface layer.
type = forbidden
source_modules =
infrastructure
application
domain
forbidden_modules =
flask
チェックする
ルールの設定が完了したら以下のコマンドでチェックを行います。
$ lint-imports
pipenv run lintfix ✘ 1 main ✚ ✱ ◼
Skipped 2 files
=============
Import Linter
=============
---------
Contracts
---------
Analyzed 14 files, 15 dependencies.
-----------------------------------
Layered architecture contract BROKEN
Do not use `flask` outside the interface layer. BROKEN
Contracts: 0 kept, 2 broken.
----------------
Broken contracts
----------------
Layered architecture contract
-----------------------------
domain is not allowed to import application:
- domain.entity -> application.repository (l.5)
Do not use `flask` outside the interface layer.
-----------------------------------------------
infrastructure is not allowed to import flask:
- infrastructure.db -> domain.entity (l.4)
domain.entity -> flask (l.3)
application is not allowed to import flask:
- application.repository -> domain.entity (l.4)
domain.entity -> flask (l.3)
- application.service -> domain.entity (l.6)
domain.entity -> flask (l.3)
domain is not allowed to import flask:
- domain.entity -> flask (l.3)
ルール違反を行なっているコードが存在する場合はエラーを表示してくれます。
CIツールに定義してPR時にチェックしてもらいましょう。