概要
Clean Architecture の構成に従ってクラスファイルを定義するツールです。
CLI で UseCase を Scaffolding することができます。
‘Cl‘ean’Arc‘itecture から取り、ツール名称は ClArc としました。
クリーンアーキテクチャ関連記事
◆クリーンアーキテクチャの概要
記事リンク: https://nrslib.com/clean-architecture/
◆クリーンアーキテクチャの右下の図について
記事リンク: https://nrslib.com/clean-flow-of-control/
◆ ClArc.CLI : CleanArchitecture のクラスを生成して登録まで行うツール(イマココ)
記事リンク: https://nrslib.com/clarc-csharp/
github: https://github.com/nrslib/ClArc.CLI
◆ ClArc : ClArc.CLI のコア部分だけを抜き出したライブラリ
github: https://github.com/nrslib/ClArc-CSharp
nuget: https://www.nuget.org/packages/ClArc/
目的
組織的にソフトウェアを作る場合、多くは分業をすることになります。
その場合、ほかのチームの作業が終わらないと作業ができない、という問題が発生しがちです。
この問題を回避して、先行して開発を行えるようにする仕組みを作り、それにともなう冗長部分を補うためのツールを作りました。
ソース
https://github.com/nrslib/ClArc.CLI
ツールのダウンロードは Release から。
ツールの機能
上記図における UseCases レイヤーの定型的ソースコードを生成をするツールです。
ClArc には以下の機能があります。
- UseCase (Production/Development) の Scaffolding
- Dependency Injection の自動登録と切替
- Production と Development での DI 設定切替
- Bus サポート
UseCase の Scaffolding
Production 用の Interactor(UseCase の実装) と development 用の MockInteractor(テスト用の UseCase の実装) を Scaffolding します。
Dependency Injection の自動登録と切替
UseCase を Scaffolding すると Production/Development でどの UseCase を使うかの設定を自動的に登録します。
Production/Development のモードを切り替えることにより、利用する UseCase が切り替わります。
デバッグ時 json 形式記述による Response データの差し替え
MockInteractor が返却する Response のデータはデフォルトでは定義されたプロパティのデフォルト値(null や 0 など)ですが、それぞれ json 形式でデータを記述できるファイルが作成されるので、必要なデータを記述することでサーバーを再起動することなく Response で受け取るデータを書き換えることができます。
Bus サポート
どの Request を用意しどの UseCase を使うか、と考える必要はありません。
Request を bus に対して引き渡すだけで Response を受け取ることができます(後述)。
使い方
ClArc.exe を実行すると以下のような画面になります。
列挙されているコマンドの頭文字をタイプするとコマンドを実行することができます。
プロジェクトの作成
それではプロジェクトを作成してみましょう。
※既存の WebProject でも上手く動くように作ったつもりですが DI の設定が必要になります。その際にはこのプロジェクトを参考にしてみてください。
‘g’ を入力して GenerateDefaultWebProject を選択します。
出力先として任意のディレクトリを指定します(D:\Test を入力しました)。
入力した Path が問題ない場合は WebProject 作成確認が行われます。問題ない場合はエンターを押下します。
WebProject が出力されて、コマンド選択に戻ります。q を入力して一旦コマンドを終了させましょう。
Web Project の確認
ClArc が出力した WebProject のソリューションを Visual studio で開いて確認してみます。
いくつかのプロジェクトが存在しています。
それぞれのプロジェクトに役割があるので一旦各々のプロジェクトの解説をします。
Domain
プロダクト用ロジックを記述するプロジェクトです。いわゆるビジネスロジックです。
ドメイン駆動設計を実践する場合はこのプロジェクト上で展開することになるでしょう。
もちろんドメイン駆動設計に従わずトランザクションスクリプトで記述しても問題ありません。
Application フォルダは UseCase の実装クラス(Interactor)が配置されます。
UseCase の実装クラスは Repository から集約を再構築し、モデルを取り扱います。
場合によっては API などを呼び出したりすることもあるでしょう。
それらのモジュールは必要に応じてコンストラクタで受け取ることになります(DependencyInjection を利用)。
Infrastructure
実際に DB に接続する Repository 等を配置するプロジェクトです。
不要であれば削除しても構いません。
MockUseCase
デバッグ時に利用される UseCase の実装である MockInteractor が記述されるプロジェクトです。
この MockInteractor の多くは付属の JsonsLoader というモジュールが利用されるようになっており、json 形式でテストデータを定義することになります(後述)。
UseCase
UseCase の interface を定義するプロジェクトです。
WebProject ということで、UseCase は Presenter を利用するのではなく、必ず Response を返却するようになっています。
好みの問題だと思うので、Presenter を利用するパターンも作ってみようと思っています。
WebApplication
ASP.net Core のプロジェクトです。
殆ど初期設定ですが、StartUp.cs にて DependencyInjection の設定がされています。
Startup.cs の ConfigureServices メソッドを見てみましょう。
DiResolver から取得する DILauncher を利用して、DependencyInjection の設定がされます。
DIResolver は返却する DILauncher というクラスを返却します。
このクラスは UseCase やそれのコンストラクタで引き渡すインスタンスなどの DependencyInjection を設定するスクリプトです。
DebugDiLauncher と ProductDiLauncher のどちらが選ばれるかは WebProject が Production か Development かによって適宜選択されます。
初期状態では DILauncher の内容はほとんど一緒です。DebugDILauncher を見ていきましょう。
デバッグ時に必要な設定がデフォルトでされています。
早速 Scaffolding する
それではいよいよ CleanArchitecture に従って UseCase を Scaffolding してみましょう。
まずはClArc を起動します。
‘u’ を入力し UseCase を作成するコマンドを起動します。
ソリューションファイルのパスを指定します。今回は D:\Test\Application\Application.sln です。
指定したソリューションファイルが正しければ次は ASP.net の WebProject ディレクトリを指定します。D:\Test\Application\WebApplication を指定します。
WebProject も受け入れられ、いよいよ UseCase の設定を始めます。まずは Controller 名を指定します。’Test’ としましょう。
次はアクション名です。’MyAction’ にします。
設定が終わり、Scaffolding の設定が確認として表示されます。そのままエンターキーを押して Scaffolding を実行しましょう。
以上で Scaffolding は完了です。
Scaffolding された UseCase を早速使ってみます。
手っ取り早く HomeController の Index で利用してみます。
コンストラクタで UseCaseBus というクラスを受け取るように記述します。
そして Index のアクションで bus に対して Scaffolding された TestMyActionRequest を Handle メソッドに引き渡します。戻り値は同じく Scaffolding された TestMyActionResponse です。
ちゃんと動作するかを確認するために、次の画像のようにブレークポイントを張ります。
F5 でデバッグ実行してみます。
response にカーソルを合わせてみると、TestMyActionResponse という Scaffolding されたクラスのインスタンスが戻ってきているのがわかります。
Response にデータを持たせる
Response にプロパティを追加して、データを返すようにしてみます。
UseCase/Test/MyAction/TestMyActionResponse.cs に TestData という int のプロパティを追加します。
次に WebApplication/Debug/JsonResponse/TestMyActionResponse.jsons に json 形式でデータを記述します。
F5 でデバッグ実行してみると json で記述したデータがプロパティに格納されているのがわかります。
この Response を作成しているのは MockUseCase/Test/MockTestMyActionInteractor.cs です。
JsonsLoader というクラスが最初から組み込まれていて、このクラスが UseCase 名に従った .jsons ファイルからデータを読み取り戻り値を生成しています。
プロダクション環境に変更
次にプロダクション環境も試してみましょう。
Production 環境では Domain/Application/MyAction/TestMyActionInteractor.cs が利用されます。
現在は未実装になっているので、もしもこれが実行されたら例外が発生するはずです。
プロダクション環境に変更するため、WebApplication のプロパティを開いて、環境変数 ASPNETCORE.ENVIRONMENT を Production に変更します。
F5 を押して実行してみましょう。
例外が発生し、プロダクション環境では Domain/Application/MyAction/TestMyActionInteractor.cs が利用されているのがわかります。
Interactor に Repository を DI する
Repository 等の永続化機構を利用する場合はコンストラクタで受け取るようにします。
サンプルとして ITestRepository という interface を TestMyActionInteractor に設定する場合は、まず以下のコードのように Domain プロジェクトに ITestRepository を定義し、対象の Interactor のコンストラクタで受け取るようにします。
次に Infrastructure プロジェクトで ITestRepository の実装を用意します。今回は適当に InMemoryTestRepository を用意します(本来では DB にアクセスし Model を再構築するような処理が書かれた Repository を用意することになるでしょう)。
最後に WebApplication/ClArc/DI/ProductDiLauncher の任意の場所で ITestRepository の DI を InMemoryTestRepository を設定します。
ブレークポイント等を設定しながら実行すると Repository が利用できることが確認できるかと思います。
テストの方法
フロントエンドのテスト
Development モードであれば json 形式で記述すれば好きなデータを受け取ることができます。
ビジネスロジック上再現が難しいデータについても、この機能を使えばテストが可能です。
また複数の UseCase が連携する動作のテスト時は、InMemory な DataBase を利用した Repository を利用するようにすれば、実際のデータベースを利用しないでテストが可能になるでしょう。
バックエンドのテスト
UseCase がバックエンドのロジックになります。
永続化装置の Repository や API のモジュールをコンストラクタで受け取るように記述されることになるので、スタブを引き渡してロジックをテストすることが可能になります。
ツールの機能解説
ツールが何を行っているかの解説です。
なお、実際に何が起きたかはツールを実行して git の diff を見た方が早かったりします。
Scaffolding 機能
UseCase を scaffolding する際に生成されるファイルをプロジェクトごとに説明します。
UseCase
- UseCase
- Request
- Response
UseCase プロジェクトは UseCase の定義元ですので、主に宣言にあたります。
UseCase は interface で定義されます。
これらのクラスはすべて紐づいています。
ですが、それを意識する必要はないでしょう。
Domain
- Interactor
こちらはプロダクション用の UseCase 実装が作成されます。
デフォルトでは処理は未実装になります。
MockUseCase
- MockInteractor
テスト用のスタブです。デフォルト実装は Json ファイルからデータを読み取るようにしています。
UseCase の DI 設定
ProductDiLauncher と DebugDiLauncher にそれぞれ UseCase と Interactor を適宜 DI するようにしています。
json データ読み取り用ファイル生成
Debugフォルダに {{コントローラー名}}{{アクション名}}Response.json という形式でファイルを作っています。
このデータに json 形式でデータを記述することで、MockInteractor はそのデータを読み取ります。
.jsons は複数のデータを記述することができ、一回目の処理は最初のデータ、二回目の処理は二つ目のデータというように準備しておくことも可能です。
Web サーバー起動中でもデータを書き換えることで、受け取るデータを変更することができます。
今後の展望
- nuget 化
- DiLauncher を任意に設定できるように
- DI 設定の XML などで行えるように
- チュートリアルが文字だとわかりづらいので動画にする
- 他フレームワーク(Play 等)対応
を予定。