はじめに
きっかけ
今更ながらドメイン駆動って何?
テスト駆動って何?
という長年のほったらかしにしてきた課題と、ちょっとだけ、ほんのちょっとだけ向き合おうと思ってUdemyで学習しました。
このタイトルに冠して個人的感想の発信、役に立つ情報になればと思います。
対象の方
ドメイン駆動開発やテスト駆動開発について深く知りたい方向けではありません。
ちょっと興味があるなーという人の動機付けです。
ドメイン駆動とテスト駆動
この両面については逆にこのQiita内にたくさん記事があります。
ぜひそちらや最後に紹介するUdemyの講座を参考にしてみてください。
ここでは簡単に概略だけ。
ドメイン駆動開発 とはユーザーの関心ごとであるプレーンな情報とそれを処理する知識に注目してアーキテクチャをデザインする開発手法。
テスト駆動開発 とは
- 開発→テスト
- テスト→開発
というテストありきのテスト主体の開発手法。
本題
BADコードに気づく
まずはBADコードに気づく。
-
共通関数
初学者がコードを書き始めるころ、よく利用する処理を 共通関数 にしてリファクタリングした気分になっていたと思います。
共通関数を詰め込んだ〇〇Utilityとかcommon〇〇とか見ませんでしたか?または作りませんでしたか?
肥大化した共通関数はもはや処理のごみ箱と化してしまいます。 -
定数べた書き
定数をリテラルでべた書きで埋め込む。しましたよね?
でもそれじゃあまずいってことでconst〇〇って作ってやっぱりそこに押し込んでおしまい、ってしましたよね? -
SQLべた書き
クエリを書いて何が悪いんだ?
細かい条件やテーブル結合はどうしてもあるし・・・
SQLインジェクション対策にパラメータ埋め込みを工夫したり
まだ問題はある
最初の関門を抜けたら、まだ何もしないよりはマシ。にはなりました。
でも相変わらずバグは発生し続けます。なぜでしょう?
新しく入った新人が悪いのでしょうか?
ベテランが手を抜いたのでしょうか?
もちろんどちらもあります。でもそれは事実ではあっても本質ではありません。
本質的には、新人が知らなくてもベテランが手を抜いても大丈夫なように最初から設計されていればいいわけです。
何が起こるか
a というデータがあってこれを a' と表示するという要件があったとして
これをこのままプログラムに落とし込むのは 最初は とても簡単です。
最初の画面を A とします。
1年後に少し見え方の違う画面 B、画面 C が追加要件であがってきます。
この時画面 A の設計と開発をした人はすでに退職しているか別のプロジェクトにアサインされてしまっています。
どうでしょうか、何が起こるか想像できると思います。
画面 B と画面 C には a' を表示することは忘れさられて a を表示すると思います。
これは誰が悪いんでしょうか?
画面 B と画面 C の開発者でしょうか?
多くの会社では文化的に大抵その扱いが多いでしょうが(苦笑)
これは仕組みが悪いです。
強いていうならプロジェクトスタート時のPJマネージャが悪いです。
PJマネージャも予算と時間がなくて労力見合いでその選択をしたのかもしれません。つまるところ会社が悪いです。
知識を必要としないソリューション
その答えの一つがドメイン駆動開発、なんだと思います。
a と a' には強い関係がありました。
というかこれはある時点での要件そのものです。
a を a' とするという要件そのものをそのまま閉じ込めちゃいましょう
これはいわいる カプセル化 ですね。
ドメイン層を定義して、ValueObjectを作って・・・という話はおいておきます。
要は関心ごと(=要件)を関心ごとの塊のまま扱って壊さないようにすることを心がけましょう、ということです。
テスト駆動開発はどうなった?
実は直接ドメイン駆動開発と関連があるというよりは、ドメイン駆動開発が実践されていればそれで次のステップにはいけているとは思うのですが、じゃあそれを担保できるようにするには?という次のステップの位置づけなのかなと思ってます。
テスト駆動開発はテスト先行型で、テストロジックを書いてユニットテストを積み重ねることで品質をある程度担保しよう、というアプローチです。
テストは実は要件そのものです。先ほどまでの例でいうと
a は a' と表示される。という要件そのものをテストに書きます。
public class AValueObject:ValueObject
{
public AValueObject(string _Value){
Value = _Value;
}
public string Value {get;set;}
public string DisplayValue {
get{
return $"{Value}様";
}
}
}
これが a を a' とするという要件そのものをカプセル化した例です。
そしてこれに対してテストユニットには
// 色々省略します
public test(){
var a = new AValueObject("Qiita");
Assert.AreEqual(a.DisplayValue, "Qiita様");
}
のように書きます。
これだけ見ても何が嬉しいの?と思う人はいるかもしれません。
実はこれすごい嬉しいんです。
テストユニットでは a が a' とする大切な要件を半永久的に担保してくれます。
この約束事を誰かが壊した時にテストはNGを出してくれるので出荷前に気づけます。
まとめ
ここまで言っておきながら、ドメイン駆動開発やテスト駆動開発を絶対にしましょう。ということを言うつもりはありません。私自身がまだこれらの初心者です。
ですが今回学んだことで気づいたのは、アプローチこそ違えど目指したものや改善点の方向性は私が長年思っていたことと同じだったことに気づきました。
それと同じ概念をもっておりその答えの一つがたまたまこのデザインパターンだったというだけです。
最後に・・・
最も大切なことは
SDGs (持続可能な開発目標)を心がけること
人がする作業は必ず、100%、絶対にミスる、なのでミスること前提で仕組みで対応すること
※「頑張る」なんて論外です、皆さんもうわかってますよね?
参考にさせてもらった講習
こちらを受けました。有料ですがその価値があると思います。
回し者ではありません。
C#でドメイン駆動開発パート1【C#でドメイン駆動開発とテスト駆動開発を使って保守性の高いプログラミングをする方法】
所感
最後の投稿から何年もたってしまいました。
この間に自分は成長できたのだろうか?
インフラもアプリもウェブもフォームも設計も開発もプロジェクトマネジメントも広くやってきて
おかげで比較的なんでも知っている、気になってるけどどれも浅くて中途半端、という気分がする。
でも、だからこそ勉強したいという気持ちになれる。