この記事について
クリーンアーキテクチャについて本(Clean Architecture 達人に学ぶソフトウェアの構造と設計)を読んだのですが、本を読むだけだと実感が湧かない部分がありました。
そういうときは実践してみるに限る!ということで自分でサンプルを実装してみました。
私は組み込み系の開発者なので、デバイス制御するWindowsアプリケーション(C#)を作ってみました。
実装の対象
サンプルとして、外部(テストツール)からTCP/IPでコマンドを受け取って、仮想デバイスを制御するようなWindowsアプリケーションを作成しました。
持っている機能としてはこんな感じです。
- モーター移動コマンドを受け取ったら指定された分だけモーターを動かし、これまでの合計移動距離を画面に表示する
- センサー読み取りコマンドを受け取ったらセンサーの値を拾って画面に表示する
※実デバイス制御は行いません。デバイスを繋いでデバイスドライバを書けば実デバイス動作できるだろう、程度の粒度まで実装をしています。
このサンプルを、クリーンアーキテクチャで実装したバージョンとそうでないバージョンを、それぞれ実装しました。
単純に実装した場合
ソースコードは https://github.com/nendo-code/DeviceCommandApp です。
このバージョンは、実装は非常にシンプルです。小規模なツールをサクッと作るならこれもありだと思います。
しかし各クラスが密結合なので単体テストの書くのがしんどいです。Singletonで直接呼び出したりしています。
今回の例は特に通信プログラムなので、単体テスト時は通信部分やデバイスドライバ部分をスタブ化したいところですが、それができないのが痛いです。
テストする場合は結合しての手動テストがメインになるでしょう。
クリーンアーキテクチャ的な実装の場合
ソースコードは https://github.com/nendo-code/DeviceCommandApp_CA です。
クラス構成としては下記のような感じです。
※データベースは今回使用していないのでDBDriverは実装していません。
何かの冗談かと思うくらい複雑になりましたね。
フォルダ名などは超有名な↓の図に合わせて構成しました。ソースコードと対比をとると理解しやすいかと思います。
この構成のポイントとしては下位のレイヤのクラスは上位レイヤの実装に依存していないという点です。
上位レイヤを使う時は必ずInterfaceを使っています。
こうすることでテスト用のMockに差し替えるのが容易になり、単体テストがしやすくなります。
構成はかなり複雑ですが、各クラス内の実装内容自体はシンプルです。
また、各クラスが疎結合になっているので単体テストは非常にやりやすくなっています。
最初のバージョンを構築するまでには時間がかかりますが、一度できてしまえばその後の拡張はしやすそうだな、というのが感想です。
システムの規模が大きくなっても修正による影響範囲が少なくてすみそうなのが大きいです。
実際のプロジェクトで実装するときは、プロジェクトの都合に合わせてフォルダの名前や構成は変えるのがよいかと思います。
(私が実際のプロジェクトで実装しているときはもっと簡略化しています。)
理解したこと
本を読み、また実際に実装してみて思ったのは、
クリーンアーキテクチャは新しくもなければ特別な技術でもないということです。
本質としては、
・システムをレイヤーに分割し、レイヤーごとに何を関心事にするかを決める
・下位レイヤーは上位レイヤーの「実装」に依存しない。インターフェースにのみ依存する。(境界を設ける)
を守りましょうね、という事に集約できます。
これは設計の基本であり、昔から行われているソフトウェア設計と大きく変わりはありません。
その基本に従い、整理したアーキテクチャの一例として提示されたのがクリーンアーキテクチャなのだと思います。
「Clean Architecture 達人に学ぶソフトウェアの構造と設計」はこうしたソフトウェア設計の基本やオブジェクト指向の原理原則についてまとめて理解できる良書なので、
まだの方はぜひ読むことをお勧めします!