DDDとは一体何か
ここ数年、DDDに関する話題をよく耳にするようになりました。
この記事では、そもそもDDDとはなんなの?という定義や基本的な事ついて書いていこうかと思います。
この記事の目的
- 初心者の方がDDD関連の知識を理解しやすくするための下準備
- DDDとは「コードの書き方」ではない、ことを伝える
ですので、専門用語は極力使用しないか、解説をしてから使用するようにしました。
また、この記事はDDDの本質を理解することが目的ではないため、
難解と思われる内容には触れておりません。
その辺りは、他の記事や書籍などを参考にして頂ければと思います。
むしろ、この記事は他の記事や書籍などを理解しやすくするための手助けのものです。
また、記事内の例に文房具生産システムなどを使用していますが、
筆者は文房具生産の知識がある訳ではなく、実際のシステムにこのようなものがあるとは限らないので悪しからず。
結論
DDDとは以下のような設計思想であると、自分は考えています。
ソフトウェアが扱う領域の専門家と共に、知識の抽象化を継続的に行い続け、 それによって得られたモデルをコードに落とし込もう、という設計思想である。
DDD=Domain-Driven Designを和訳すると「ドメイン駆動設計」になります。
ソフトウェアが扱う領域(ドメイン)を第一に考える(駆動される)、
という意味合いになるかと思います。
ネット上の記事を見たりするとコードの書き方に目が向きがちですが、
DDDとはコードの書き方のことではない、という事に注目して頂ければと思います。
以下で詳しく考えていきます。
ドメインとは何か
そもそも、なぜ開発者達はソフトウェアを開発するのでしょうか?
それは、そのソフトウェアにより解決したい問題や実現したい事があるからですね。
そして、そのソフトウェアが対象として扱う領域のことを ドメイン
と呼びます。
例:文房具の工場で使用するシステムの場合は、
材料の管理、機材の稼動状態、生産工程や生産量などがドメインとなり得る。
なぜソフトウェア開発は難しいのか
近年、大変優秀なフレームワークやライブラリが多く登場しています。
ですが未だにソフトウェアの開発はとても難しいことだと思います。
それは何故でしょうか?
ソフトウェア開発が難しいのは、ドメインの知識が複雑だからだ、とDDDでは考えます。
例えばブログのシステムを作ることを考えましょう。
入力のルールがなく、タイトルとテキストのみのブログを作るだけなら、
単一テーブルのCRUDでバリデーションもしなくて良いので一瞬でコードを書き上げることができると思います。
ですが「タイトルは必須でX文字まで」というルールをつけると少しコードは複雑になります。
更に、下書き状態があるとしたらどうでしょう?関連記事は?有料プランのアカウントと無料アカウントで文字数制限が異なっていたら?
このようにドメインのルール、知識が複雑になっていくと、書かれるコードも複雑になっていきます。
DDDではドメインの複雑さにどうやって立ち向かっていくか
そこで、DDDではドメインの複雑さに焦点をあて、立ち向かっていこうとします。
ですが、一般的に開発者はドメインに関する詳しい知識を持っていません。
そこで開発者だけではなく、そのドメインの専門家=ドメインエキスパートと共に進む事になります。
ここで、ドメインエキスパートと開発者が共通認識を作り上げることが大切です。
そこで、ドメインの用語をドメインエキスパートと開発者間で共有することが重要です。
このような用語のことをDDDでは、 ユビキタス言語
と呼びます。
例:その工場がその日に必要な製品の生産量のことを「日次必要生産量」と呼ぶ。など
モデルとは何か
ソフトウェア開発において、「モデル」という言葉は良く耳にします。
ですが、そもそもモデルとは何でしょうか?
それは、ドメインを抽象化する事です。
例えば、ボールペンに関するモデリングしてみましょう。
生産工場が使用する生産管理システム、卸売業者が使用する卸売管理システム、
オフィスで使用する社内備品管理システム、それぞれでモデリングを考えてみたいと思います。
ドメイン | ボールペン関連のモデル |
---|---|
文房具生産管理 | 製造番号、材料、生産工程、その日に必要な生産量など |
卸売管理 | 製造番号、商品番号、値段、在庫数、購入単位(ダース売りか?)など |
社内備品管理 | 商品番号、値段、備蓄数、備蓄数がいくつ以下で追加発注するか?など |
文房具を生産する上で材料や生産工程は重要です。
ですが、卸売や社内の備品管理ではそれらの情報は必要ありません。
このように重要でない情報を削ることをDDDでは 蒸留
と呼びます。
モデリングとは、このようにして現実の概念を抽象化することを言います。
また、一度モデルを作ったら終わりではなく、
ドメインエキスパートと共により良いモデルを探求し続ける必要があります。
最初に作ったモデルでシステムを構築してみても、
「そのモデルだとここがうまくいかない!」という事はよくありますし、
ビジネスは常に変化し続けるからです。
モデルができあがったら
モデルができたら、いよいよそれをコードに落とし込んでいきます。
ですが、せっかく良いモデルがあってもそれを表現できておらず、
リレーショナルデータベースやHTTPなどソフトウェアの関心ばかりに気を取られたコードになっては意味がありません。
そこで、ドメインのモデルを綺麗にコードに落とし込み、表現するための 戦術
として、
エンティティや値オブジェクト、レイヤー化アーキテクチャやクリーンアーキテクチャ、リポジトリやファクトリなどを使用します。
戦術的DDD
世の中では、ドメインエキスパート共にモデリングをすることをせず、
エンティティなどコードの書き方の戦術部分のみを採用して開発することがあります。
これは、戦術的DDDや軽量DDDと呼ばれたりします。
戦術的DDDが良いか悪いかの議論はここではしませんが、個人的には一定の効果はある、と思っています。
まとめ
以上をまとめると、DDDとは以下のようなものだと言えると思います。
ここから専門用語を除去すると冒頭の、
ソフトウェアが扱う領域の専門家と共に、知識の抽象化を継続的に行い続け、 それによって得られたモデルをコードに落とし込もう、という設計思想である。
になります。
境界づけられたコンテキストなど、説明していない内容がありますが、
まずはこの記事がDDDを理解するための助けになればと願います。
C#でnullチェックを省略-Collection編
当然ですが、以下のソースは例外で落ちます。
public static void Main(string[] args) { List<string> nullList = null; foreach (string str in nullList) // ここで落ちる { Console.WriteLine(str); } }
ifでnullチェックとか、nullの場合は空リストで初期化するとか方法はありますが、
以下のような拡張メソッドを定義して、
nullチェックを省略してしまうとシンプルでよさげです。
拡張メソッド
public static IEnumerable<T> CollectionOrEmpty<T>(this IEnumerable<T> collection) { return collection ?? Enumerable.Empty<T>(); }
使い方
public static void Main(string[] args) { List<string> nullList = null; foreach (string str in nullList.CollectionOrEmpty()) { Console.WriteLine(str); } }
C#で異なるクラス間のプロパティ値コピー
Entityframeworkを使っていると、
ViewModelとDomainModel間で同名のプロパティをコピーしたい!
なんてことよくありますよね。
というわけで、作ってみました。
今回は拡張メソッドにしてみます。
public static class Extention { public static void CopyProperty(this object toObject, object fromObject) { // コピー元、コピー先のプロパティ情報を取得 PropertyInfo[] fromProperties = fromObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); PropertyInfo[] toProperties = toObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var fromProperty in fromProperties) { // 名前と型が同じプロパティを取得 PropertyInfo target = Array.Find(toProperties, to => to.Name.Equals(fromProperty.Name) && to.PropertyType.Equals(fromProperty.PropertyType)); // プロパティ値コピー if (target != null) target.SetValue(toObject, fromProperty.GetValue(fromObject)); } } }
使い方は以下の通り
コピー元クラス
public class FromObject { public int Id { get; set; } public string Name { get; set; } public bool? Nullable { get; set; } public string OnlyFrom { get; set; } public int SameName { get; set; } }
コピー先クラス
public class ToObject { public int Id { get; set; } public string Name { get; set; } public bool Nullable { get; set; } public string OnlyTo { get; set; } public string SameName { get; set; } }
class MainClass { public static void Main(string[] args) { FromObject from = new FromObject() { Id = 1, Name = "hoge", Nullable = true, OnlyFrom = "foo", SameName = 10 }; ToObject to = new ToObject(); to.CopyProperty(from); Console.WriteLine("ID:" + to.Id); Console.WriteLine("Name:" + to.Name); string sameName = to.SameName ?? "null"; Console.WriteLine("SameName:" + sameName); Console.WriteLine("Nullable:" + to.Nullable); string onlyTo = to.OnlyTo ?? "null"; Console.WriteLine("OnlyTo:" + onlyTo); } }
実行結果
ID:1 Name:hoge SameName:null Nullable:False OnlyTo:null
名前と型が同じプロパティのみコピーされます。
null許容型は違う型とみなしコピーはしません。
atomの背景画像を設定してみる
atomの背景画像を設定してみる
editor-backgroundを使うと、atomの背景画像をとても簡単に設定できます。
おおまかな手順は以下の2つだけ。
- editor-backgroundのインストール
- 背景画像の設定
1.editor-backgroundのインストール
コマンド一発でOK
$ apm install editor-background
2.背景画像の設定
atomのメニューから
パッケージ -> editor-background -> Toggle
を表示
最低限、以下の2つを設定すればOK
- Background Sizeをcoverに変更
- image URLに表示させたい画像のパスを設定
※パスの設定は「atom://」がatomのインストールフォルダになります。
(だいたいユーザフォルダの直下の.atomフォルダ)
完成
やったぜ