NDDD

ドメイン駆動開発_フォルダー構成編_#07_WinFormのフォルダー構成

前回はInfrastructureのフォルダー構成を解説しました。今回はWinFormのフォルダー構成を解説していきます。今回はWindowsフォームを使用するため,WinFormプロジェクトにしていますが,WPFやUWPなどになる可能性があります。それらをまとめて,ユーザーインタフェース層と呼びます。

時代の変化と共に変化する部分

ユーザーインタフェースとは,簡単に言えば画面等のユーザーが実際に触れる部分です。この部分というのも,時代と共に変わっていきますよね。昔は真っ黒のコンソールでしたが,Windowsフォームが出てきて,WPFがあり,UWPがあります。あとはWEBサイトなどもユーザーインタフェースですね。こういった部分は時代とともに進化します。だから,いまWPFで作成していても,数年後にはもっとおしゃれなユーザーインタフェースに切り替えたくなる可能性があります。なので,そういった部分も切り離して実装することで,ユーザーインタフェース部分だけの変更で時代についていくことができます。

ビジネスロジックとの分離

ユーザーインタフェース部分を切り離すことで,ドメイン層には純粋なビジネスロジック,インフラストラクチャーには外部接触部分,ユーザーインタフェース層には画面関連のみを集中することで,今後WindowsフォームをWPFに変更させる場合は,Domain層とInfrastructure層はそのままで,WPFプロジェクトの追加し,Windowsフォームに実装していたものを,WPFプロジェクトに移行するという作業だけで,WPFの実装が可能になります。なので,ユーザーインタフェース層には,ビジネスロジックが入り込んではいけません。純粋な,画面表示などの,ユーザーインタフェースを制御するためのロジックのみを集中させます。ドメイン層やインフラストラクチャー層の機能を選ぶのが仕事です。

合言葉は「WinFormからWPFにするときに,変更しないといけない物だけを入れる!」です。

MVVMパターンの適応

テスト駆動開発を行う上で,WinFormだろうと,WPFだとうと,UWPだろうと,MVVMパターンを採用することがもっともいい選択です。MVVMパターンとは,View,ViewModel,Modelという3つに分けて実装するパターンです。このうちModelはDomain層とInfrastructureが担っているので,ここでは画面をViewと呼び,Viewのコントロールに連動してデータバインドさせる画面制御ロジッククラスをViewModelとします。昔は,Formプログラムにすべての実装をしていましたが,それでは,テストコードからテストができません。なので,Formには最低限の記述だけをして,画面と1対1でデータバインドさせるViewModelに,画面制御のロジック部分のみを移行させます。これにより,多くのユーザーインタフェースのコードをテストコードで検証できるようになります。

フォルダー構成

以上の事を踏まえて,ユーザーインタフェース層ではViewを入れるフォルダーとViewModelを入れるフォルダーの2つに分けます。フォルダー名はそれぞれ,「Views」と「ViewModels」とします。

タイマーイベントはどこに入れる?

ユーザーインタフェース層ではイベントが発生します。私の考えでは,イベントはユーザーインタフェース層でのみ発生させるべきという結論に至っています。例えば「ボタンを押したとき」や「クリックしたとき」などのイベントは当然ユーザーインタフェース層に入ることが理解できると思います。しかし,定期的に発行されるタイマーイベントのようなバックグラウンドイベントはどこに書くべきでしょうか?私の結論はユーザーインタフェース層です。理由は,保守性を高めるためです。保守性の高いコードとは,「修正時に追いやすいコード」です。インフラストラクチャー層からでも,ユーザーインタフェース層からでも,不具合が発生したときや,改造したいときに,簡単に影響範囲が理解できるのが良いコードであり,保守性の高いコードであるといえます。例えばドメイン層に「アプリ起動後に,1秒に1回計測データを作成するタイマー処理」が動作していた場合,数年後にプログラムコードを初めて見た人は,どのようにしてそれに気づくことができるでしょうか?プログラムコードをすべて読まないと,それに気づくことができません。だって,そういうコードがあるという事は,

ほかにも,「勝手に動いているもの」があるかもしれません。

そんなものがあると知らされたら,すべてひっくり返して読まないと,どう動いているかわからないアプリケーションになってしまいます。

だから,私は,「イベントは1か所にまとめるべきだ」という結論に至りました。

「ユーザーインタフェース以外からイベントは発動していない!」とルール付けをすることで,容易にコードは追えるようになります。だって,イベントは画面のクリック等と,バックグラウンドで動作するタイマー的なものだけをWinFormプロジェクトで理解しておけば,アプリケーションがどう動いているかが理解できます。

Domain層とInfrastructure層は,ユーザーインタフェース層で呼ばれない限り,決して動いてはいけないのです。

NDDD

■4700人以上が受講している動画コースはこちらからご確認ください

#01_プロジェクトの作成
#02_プロジェクトの追加
#03_依存関係
#04_ドメイン駆動開発でApplication層は必要?
#05_Domainのフォルダー構成
#06_Infrastructureのフォルダー構成
#07_WinFormのフォルダー構成
#08_Testsのフォルダー構成
#09_テスト駆動で実装するための事前準備
#10_テストコードとViewModelの追加
#11_テストコードを追加する
#12_ Repositoriesフォルダーの作成
#13_ Entitiesフォルダーの作成
#14_ Mockの作成
#15_フォーム画面の作成
#16_画面のコントロールデータバインドする
#17_Fakeを使ってタミーデータを画面に表示させる
#18_Fakeデータを画面に通知する
#19_PropertyChangedの方法を変更する
#20_Fakeとデータベースの値を切り替える方法
#21_Sharedクラスを作成する
#22_クラスを生成するファクトリークラスを作る
#23_#if DEBUGでFakeデータがリリースされないようにする
#24_DEBUGモードであることをわかりやすくしておく
#25_Factories以外から生成できないようにしておく
#26_Factoriesの呼び出しはViewModelで行う
#27_外部の設定ファイルの値で判断する
#28_Fakeデータを切り替える方法
#29_FakePathを設定ファイルとSharedに移す
#30_Fakeデータのバリエーション
#31_Shareクラスの活用方法
#32_ベースフォームを作る
#33_SharedにログインIDを記憶する
#34_BaseFormでログインユーザーを表示する
#35_ValueObject
#36_ValueObjectを作成する
#37_抽象クラスValueObjectを使用してイコールの問題の解消
#38_AreaIdにビジネスロジックを入れる
#39_AreaIdクラスをEntityに乗せる
#40_MeasureDateの作成
#41_MeasureValueの作成
#42_オブジェクト指向の自動化
#43_Repositoryの具象クラス
#44_例外処理
#45_例外の作成
#46_インナーエクセプション
#47_例外の欠点
#48_メッセージの区分
#49_エラー処理の共通化
#50_ログの出力
#51_タイマー処理はどこに置く?
#52_タイマークラスの作成
#53_StaticValues
#54_Logics
#55_Helpers
#56_Module
#57_トランザクションはどこでかける?
#58_特徴を見極める
#59_さいごに

■4700人以上が受講している動画コースはこちらからご確認ください