tag:crieit.net,2005:https://crieit.net/tags/DDD/feed
「DDD」の記事 - Crieit
Crieitでタグ「DDD」に投稿された最近の記事
2020-10-30T19:46:03+09:00
https://crieit.net/tags/DDD/feed
tag:crieit.net,2005:PublicArticle/16181
2020-10-28T00:50:39+09:00
2020-10-30T19:46:03+09:00
https://crieit.net/posts/C-DateTime-ValueObject-5f9841cf877d6
C# の DateTime で説明する ValueObject
<h2 id="ValueObject イズ 何?"><a href="#ValueObject+%E3%82%A4%E3%82%BA+%E4%BD%95%EF%BC%9F">ValueObject イズ 何?</a></h2>
<p>ValueObject とは「何らかの概念についての状態と振る舞いを持ち、その概念の責務を果たすオブジェクト」です。<br />
ValueObject はそれが定義される上で満たすべきいくつかの要件があります。<br />
IDDD 本で示されている ValueObject が満たすべき要件を確認してみたいと思います。</p>
<div class="table-responsive"><table>
<thead>
<tr>
<th>No.</th>
<th>要件</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>計測・定量化・説明</td>
<td>そのドメイン内の何かを計測したり定量化したり、あるいは説明したりする。</td>
</tr>
<tr>
<td>2</td>
<td>不変</td>
<td>状態を不変に保つことができる。</td>
</tr>
<tr>
<td>3</td>
<td>概念的な統一体</td>
<td>関連する属性を不可欠な単位として組み合わせることで、概念的な統一体を形成する。</td>
</tr>
<tr>
<td>4</td>
<td>交換可能性</td>
<td>計測値や説明が変わったときには、全体を完全に置き換えられる。</td>
</tr>
<tr>
<td>5</td>
<td>値の等価性</td>
<td>値が等しいかどうかを、他と比較できる。</td>
</tr>
<tr>
<td>6</td>
<td>副作用のない振る舞い</td>
<td>協力関係にあるその他の概念に、副作用のない振る舞いを提供する。</td>
</tr>
</tbody>
</table></div>
<p>引用 : <a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/dp/B00UX9VJGW/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1">ヴァーン・ヴァーノン. 実践ドメイン駆動設計</a></p>
<p>どうでしょう、初見で理解出来ましたか?<br />
「全然わからん」となったそこのあなた。もしあなたが C#er なら ValueObject は怖くありません。<br />
あなたは既に ValueObject を知っているからです。</p>
<p>人間誰しも自分の理解していない事柄に対しては拒絶感を抱きやすいものですが「既に知っている」となればどうでしょうか。<br />
この記事は「まだ ValueObject をあまり知らない方」に向けた「ValueObject に対する拒絶感を和らげる」ために書かれた記事です。</p>
<h2 id="DateTime で説明する ValueObject"><a href="#DateTime+%E3%81%A7%E8%AA%AC%E6%98%8E%E3%81%99%E3%82%8B+ValueObject">DateTime で説明する ValueObject</a></h2>
<p>C# には日時を取り扱うための構造体として DateTime があります。C#に触れたことがある人ならば一度は見たことがあるのではないでしょうか。<br />
この DateTime ですが実はある種の ValueObject です。<br />
嘘ではありません。<br />
それでは DateTime で ValueObject の要件を説明していきましょう。</p>
<h3 id="計測・定量化・説明"><a href="#%E8%A8%88%E6%B8%AC%E3%83%BB%E5%AE%9A%E9%87%8F%E5%8C%96%E3%83%BB%E8%AA%AC%E6%98%8E">計測・定量化・説明</a></h3>
<p>言わずもがな DateTime は日時を示す為の構造体です。<br />
日時に関しておおよそ一般的な定義や振る舞いを提供してくれます。</p>
<h3 id="不変"><a href="#%E4%B8%8D%E5%A4%89">不変</a></h3>
<p>DateTime は読み取り専用構造体として定義されておりインスタンス生成後に状態を変更することは出来ません。<br />
「状態を不変に保つことができる」と言うより「状態が不変であることを強制されている」と言う方が正しいかもしれません。</p>
<pre><code class="csharp"> public readonly partial struct DateTime : IComparable, IFormattable, IConvertible, IComparable<DateTime>, IEquatable<DateTime>, ISerializable, ISpanFormattable
</code></pre>
<p>引用 : <a target="_blank" rel="nofollow noopener" href="https://source.dot.net/#System.Private.CoreLib/DateTime.cs,df6b1eba7461813b">.NET Core Source Browser DateTime.cs</a></p>
<p>既に存在する DateTime インスタンスとは別の日時が欲しい場合は常に新しいインスタンスとして生成されます。<br />
一例として AddDays メソッドの定義を見てみます。</p>
<pre><code class="csharp"> public DateTime AddDays (double value);
</code></pre>
<p>引用 : <a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/dotnet/api/system.datetime.adddays?view=netcore-3.1">DateTime.AddDays(Double) メソッド | Microsoft Docs</a></p>
<p>戻り値が DateTime になっていますが、この戻り値について MS Docs の説明にはこう書いてあります。</p>
<pre><code>このインスタンスの値に、指定された日数を加算した新しい DateTime を返します。
</code></pre>
<p>引用 : <a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/dotnet/api/system.datetime.adddays?view=netcore-3.1">DateTime.AddDays(Double) メソッド | Microsoft Docs</a></p>
<p>上記の通り新しいインスタンスを返却します。自身の状態を変更して自身の参照を返す訳ではありません。<br />
AddMonths メソッドや AddYears メソッドも同様です。</p>
<h3 id="概念的な統一体"><a href="#%E6%A6%82%E5%BF%B5%E7%9A%84%E3%81%AA%E7%B5%B1%E4%B8%80%E4%BD%93">概念的な統一体</a></h3>
<p>ここに「2000」という数字があるとします。この数字は、これだけでは殆ど価値のある意味を持ちません。<br />
ですが「年」という言葉と組み合わせると「2000 年」になり、只の「2000」よりも具体的な意味を示すようになります。</p>
<p>DateTime には「年」以外にも構成要素があります。<br />
月、日、時刻、現地時間なのか UTC なのか、などです。<br />
これらの属性が組み合わせることで「現地時間 2000 年 4 月 1 日 12:00」の様な日時として更に意味のある概念を示せるようになります。</p>
<p>この様に複数の属性で何かを説明したり意味のある概念を示すものが「概念的な統一体」です。</p>
<h3 id="交換可能性"><a href="#%E4%BA%A4%E6%8F%9B%E5%8F%AF%E8%83%BD%E6%80%A7">交換可能性</a></h3>
<p>DateTime は「不変」であるため、交換が不可能であると値を変更することが出来なくなってしまいます。<br />
その為 DateTime は交換可能でなければなりません。</p>
<pre><code class="csharp"> // dateA に「2000 年 1 月 1 日」のインスタンスをセットしたあと 「2000 年 1 月 2 日」のインスタンスに「交換」する。
var dateA = new DateTime(2000, 1, 1);
dateA = new DateTime(2000, 1, 2);
</code></pre>
<p>C# 的には当たり前のことかもしれませんが ValueObject として必要な要件です。</p>
<h3 id="値の等価性"><a href="#%E5%80%A4%E3%81%AE%E7%AD%89%E4%BE%A1%E6%80%A7">値の等価性</a></h3>
<p>C# において等価性について何も考慮されていないクラス/構造体では、内部で保持している値が同じだとしても異なるインスタンス同士は等価と判断されません。</p>
<pre><code class="csharp"> // 参照型のクラス
public sealed class User
{
public User(string id)
{
this.Id = id;
}
public string Id { get; }
}
public void Main()
{
var userA001 = new User("1234");
var userA002 = new User("1234");
// 同じ ID なので等価として判断して欲しい。
if(userA001 == userA002)
{
Console.WriteLine("同一ユーザー"); // しかし出力されない。
return;
}
Console.WriteLine("別ユーザー"); // 出力される。
}
</code></pre>
<p>ですが同じ値を保持しているのであればそれらのインスタンス同士を等価として判断して欲しい場面があります。<br />
C# にはそんな時の為に異なるインスタンス同士の等価性判断を提供する IEquatable インターフェースや == 演算子が用意されており、DateTime でもこれらが実装されています。</p>
<pre><code class="csharp"> public static bool operator ==(DateTime d1, DateTime d2) => d1.InternalTicks == d2.InternalTicks;
</code></pre>
<p>引用 : <a target="_blank" rel="nofollow noopener" href="https://source.dot.net/#System.Private.CoreLib/DateTime.cs,df6b1eba7461813b">.NET Core Source Browser DateTime.cs</a></p>
<p>これにより DateTime では異なるインスタンス同士を違和感なく等価かどうか判断出来るようになっています。</p>
<pre><code class="csharp"> var dateA = new DateTime(2000, 1, 1);
var dateB = new DateTime(2000, 1, 1);
Assert.IsTrue(dateA == dateB);
</code></pre>
<p>この様に等価かどうかを判断出来ることが「値の等価性」です。</p>
<h3 id="副作用のない振る舞い"><a href="#%E5%89%AF%E4%BD%9C%E7%94%A8%E3%81%AE%E3%81%AA%E3%81%84%E6%8C%AF%E3%82%8B%E8%88%9E%E3%81%84">副作用のない振る舞い</a></h3>
<p>「副作用のない振る舞い」とは<code>何かを出力するけれども自身の状態は変更しないもの</code>です。<br />
引用 : <a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/dp/B00UX9VJGW/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1">ヴァーン・ヴァーノン. 実践ドメイン駆動設計</a></p>
<p>「不変」の要件と異なるのは「何かを出力するけれども」という点です。<br />
DateTime がただ「不変」であるだけで良いのであれば AddDays メソッドや AddMonths メソッドは不要な筈です。<br />
異なる日時のインスタンスは全てコンストラクタで生成すれば済むからです。</p>
<p>しかし新しいインスタンスが欲しくなる度にコンストラクタを呼び出していてはコードが冗長になる上にバグを埋め込む可能性も高くなります。</p>
<pre><code class="csharp"> var dateA = new DateTime(2000, 1, 31);
// dateA の翌日が欲しかったが 31 日であることに気付かず日付に 1 を足してしまった。
var dateB = new DateTime(dateA.Year, dateA.Month, dateA.Day + 1);
</code></pre>
<p>こういったことを防ぐ為に DateTime では AddDays などのメソッドを提供しています。<br />
この様に『その概念に関する振る舞いをカプセル化して「不変」であることを保ちつつ何らかの値を返却する』ことが「副作用のない振る舞い」です。</p>
<h2 id="DateTime は ValueObject"><a href="#DateTime+%E3%81%AF+ValueObject">DateTime は ValueObject</a></h2>
<p>無事に DateTime で ValueObject の要件を全て説明することが出来ました。<br />
同時に DateTime は ValueObject としての要件を満たしていることが分かりました。<br />
「ValueObject 全然わからん」という方でも「つまり DateTime みたいなヤツだな」という理解が出来るようになったのではないでしょうか。</p>
<h3 id="おまけ : ValueObject のポイント"><a href="#%E3%81%8A%E3%81%BE%E3%81%91+%3A+ValueObject+%E3%81%AE%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88">おまけ : ValueObject のポイント</a></h3>
<p>ValueObject 6 個の要件は以下の様に 3 つのグループに分けることが出来ます。</p>
<ul>
<li>概念
<ul>
<li>計測・定量化・説明</li>
<li>概念的な統一体</li>
</ul></li>
<li>不変
<ul>
<li>不変</li>
<li>交換可能性</li>
<li>副作用のない振る舞い</li>
</ul></li>
<li>等価性
<ul>
<li>値の等価性</li>
</ul></li>
</ul>
<p>概念グループの 2 つの要件は両方とも ValueObject で何らかの概念を定義する為の要件なので同じグループです。</p>
<p>不変グループは ValueObject が「不変」であることが前提にあり、残りの 2 つは「不変」であるが故に生じる要件なので同じグループです。<br />
「不変」であろうとすると自然に「交換可能性」と「副作用のない振る舞い」を満たす実装になります。</p>
<p>等価性グループは「値の等価性」だけのグループです。</p>
<p>自分で ValueObject を定義する際は「概念(のカプセル化)」、「不変」、「等価性」の 3 点を意識しておけば良いと思います。</p>
kono 16
tag:crieit.net,2005:PublicArticle/15353
2019-08-26T12:34:25+09:00
2019-09-30T10:42:42+09:00
https://crieit.net/posts/DDD-5d635341271f5
やはり俺のDDDの理解は間違いだらけ
<p>「ポエム」タグをつければ何を書いてもいいと許されると思ってるし、書きかけでも許されると思ってる。</p>
<h1 id="なんでDDDやることになったのか"><a href="#%E3%81%AA%E3%82%93%E3%81%A7DDD%E3%82%84%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B">なんでDDDやることになったのか</a></h1>
<p>なんでだっけ?</p>
<p>なんか前に居た会社でも「クリーンアーキテクチャで作られているプログラムだから、ソースコードを改変せずにAPIから上手にビジネスロジックを剥がしてドメインを叩ける」<br />
というどちゃクソ理論押し付けられていい経験はしていないのだが。</p>
<p>とはいえ、最近CSharpでアプリを作ると、テンプレートがそんな感じの作りをしているからだったかもしれない。</p>
<h1 id="ASP.net MVC5だと"><a href="#ASP.net+MVC5%E3%81%A0%E3%81%A8">ASP.net MVC5だと</a></h1>
<p>データアノテーションを付け加えることができるから、値オブジェクトとかエンティティを作る必要がない可能性がと思ったが、完全に勘違いだと思った。説明はうまくできない。</p>
<pre><code class="csharp">using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Ultra.Hyper.Models
{
[Table("m_users")]
public class User
{
/* アノテーションをつけると入力されるデータの制限とかができるだろうけど */
[Key]
[Column("id")]
[StringLength(5)]
public string ID { get; set; }
/* こういう実装の方が丁寧に思うぞ */
[Key]
[Column("id")]
{StringLenth(5)]
public IDentityNumber { get; set; }
// :
// :
[Column("name")]
[StringLength(128)]
public string Name { get; set; }
/* 性別が特にそんな気がする。
これより:*/
[Column("sex")]
[StringLength(2)]
public string Sex { get; set; }
/* こっちの方がいい気がする(Sexクラスの実際の実装は省く) */
[Column("sex")]
[StringLength(2)]
public Sex Sex { get; set; }
}
}
</code></pre>
<p>と、思いつきコードを書いたが、データアノテーションってあくまで「入力されたデータに対して」だと思ったので、リポジトリ群に書くものではないのではと思った。</p>
<p>だから、データベースの設計とプログラムの設計はまた別の話になるだろうし、ましてや自分が自由にやって許されているのはプログラムの設計までなので、データベースのテーブル構造とリポジトリのクラスが一対のものになるかというと、別問題じゃないかなと。</p>
<p>それに、レイヤードアーキテクチャの依存関係を考えた際に、外から内側への依存は良いとして、内側から外側への依存しちゃうとダメだと言う記憶。</p>
<p>なので、データの永続化に関しても、ドメイン部分にSQLを書いてDBへの書き込み処理を書くのは完全に間違ってる。と思う。</p>
<p>ということで、データアノテーションを書くべきは、フォームなどのビューからデータを受けるモデルに対して行うべきであり、データ永続化処理(リポジトリとか)に書くのは違う気がしてる。</p>
<p>ヤマもないしオチもない。続きが合ったら加筆するかなあ?</p>
<h1 id="参考資料"><a href="#%E5%8F%82%E8%80%83%E8%B3%87%E6%96%99">参考資料</a></h1>
<p>多すぎるのでまた後で加筆すると思うぞ。</p>
<h2 id="書籍"><a href="#%E6%9B%B8%E7%B1%8D">書籍</a></h2>
<ul>
<li>実践ドメイン駆動設計</li>
<li>Clean Architecture</li>
</ul>
<h1 id="2019-08-27 追記"><a href="#2019-08-27+%E8%BF%BD%E8%A8%98">2019-08-27 追記</a></h1>
<p>プロジェクトリーダーさんから頂いてるDBレイアウトを元に、どんなデータが必要かを何となくモデリング(?)したが、未だにエンティティとサービスと集約をどの辺りで切り分けるべきなのかよくわからない。</p>
<p>業務ロジックが見えたら、多分この辺の切り分けができるのだが。</p>
<p>PlantUMLで書いたクラス図を、何となくオニオンアーキテクチャにはめてみるとそれっぽい感じにはなるが、ドメインモデル層の中で、エンティティが複数の値オブジェクトに絡んでいたり、更にエンティティが他のエンティティを参照していたりして、正しいのか全く自信が持てない。</p>
<h1 id="2019-09-30 追記"><a href="#2019-09-30+%E8%BF%BD%E8%A8%98">2019-09-30 追記</a></h1>
<p>先日たまたまCoderDojoのメンター仲間さんとコワーキングスペースで出会って、話の流れでDDDの事を話したが、結局、<br />
「ゑ、それってオブジェクト指向で実装すれば自然とそうなるものじゃないの?」<br />
という返答をいただいて、自分はやっぱりDDDの事を理解していないのだなと改めて感じた。</p>
<p>その時のDDDの説明:</p>
<blockquote>
<p>例えば個人情報に持たせたいデータは、性別・住所・連絡先などとありますが、それらを一つのクラスにまとめて実装するのではなくて、ちゃんと「性別クラス」「住所クラス」「連絡先クラス」と分けて実装するんです。そうすると、個人情報の性別に関する編集だけなのに、編集するコードの量が必要以上に多くなることがない、つまり、編集者は編集する事柄に集中できる設計方法なんです。</p>
</blockquote>
<p>改めて書き出したが、やはりこの説明では、そりゃあ、<br />
「オブジェクト指向で組めばしぜんとそうなるじゃん」<br />
と言われるわ。</p>
まんじゅ(´ん`)
tag:crieit.net,2005:PublicArticle/14556
2018-09-29T18:37:56+09:00
2018-10-30T07:43:25+09:00
https://crieit.net/posts/DDD
ボトムアップDDDを写経した
<h2 id="まえがき"><a href="#%E3%81%BE%E3%81%88%E3%81%8C%E3%81%8D">まえがき</a></h2>
<p>最近、通勤の合間などにIDDDを読んで少しづつDDDの知識を取り入れている。ユビキタス言語や境界づけられたコンテキストなど、概念的な定義が個人的に難しくて読むのに時間がかかっている。</p>
<p>そんな時に<a target="_blank" rel="nofollow noopener" href="https://twitter.com/nrslib">nrsさん</a>のブログに書かれている、<a target="_blank" rel="nofollow noopener" href="https://nrslib.com/bottomup-ddd/">ボトムアップドメイン駆動設計</a>を読んだ。理解や実践が難しい箇所はひとまず置いておき、理解しやすく実践しやすい箇所からまず始めてみようという内容だ。</p>
<p>自分にぴったりだと思って一通り読んだ後、せっかくなのでPHPとLaravelを使って写経をしてみた。一通り書いてみた感想としては、OOPの特性を活かしたコーディングとはこういうことなんだなとふんわり掴め、責務の所在が明確だとファイルが増えても処理が追いやすいなと感じた。</p>
<p>参考にした記事で扱われているものは次の5つ。どれも技術的な要素なので、普段コードを書いている人にとっては読みやすいと思う。</p>
<ul>
<li>値オブジェクト</li>
<li>エンティティ</li>
<li>ドメインサービス</li>
<li>リポジトリ</li>
<li>アプリケーションサービス</li>
</ul>
<p>また、サンプルとは異なる実装をしている箇所を以下で補足する。</p>
<h2 id="変更点"><a href="#%E5%A4%89%E6%9B%B4%E7%82%B9">変更点</a></h2>
<h3 id="コンストラクタ"><a href="#%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF">コンストラクタ</a></h3>
<p>PHPは<code>__construct()</code>を複数定義出来ない。そのため、今回はデフォルト引数を用いて実装を行った。</p>
<pre><code class="php"><?php
namespace BottomUpDDD\Domain\Users;
use InvalidArgumentException;
use BottomUpDDD\Common\Util;
use BottomUpDDD\Domain\EquatableInterface;
final class User implements EquatableInterface
{
/** @var UserId */
private $id;
/** @var UserName */
private $userName;
/** @var FullName */
private $fullName;
public function __construct(
UserName $userName,
FullName $fullName,
UserId $id = null
) {
$this->id = $id === null ? new UserId(Util::guid()) : $id;
$this->userName = $userName;
$this->fullName = $fullName;
}
// 以下の処理は省略...
}
</code></pre>
<p>ただ、必ず引数で受け取る<code>$userName</code>と<code>$fullName</code>を引数としたコンストラクタを定義し、2つの引数に合わせて<code>$id</code>と3つを引数に受け取る静的メソッドを定義すれば擬似的に複数定義することも出来なくはない。</p>
<pre><code class="php"><?php
namespace BottomUpDDD\Domain\Users;
use InvalidArgumentException;
use BottomUpDDD\Common\Util;
use BottomUpDDD\Domain\EquatableInterface;
final class User implements EquatableInterface
{
/** @var UserId */
private $id;
/** @var UserName */
private $userName;
/** @var FullName */
private $fullName;
public function __construct(
UserName $userName,
FullName $fullName
) {
$this->id = new UserId(Util::guid());
$this->userName = $userName;
$this->fullName = $fullName;
}
public static function ctorWithId(
UserName $userName,
FullName $fullName,
UserId $id
) {
$instance = new self($userName, $fullName);
$instance->id = $id;
return $instance;
}
// 以下の処理は省略...
}
</code></pre>
<p>個人的な意見としては、生成処理のパターンが増えたり、複雑であればファクトリを用意すれば良いのかなという解釈でいる。</p>
<h3 id="等価性の判定"><a href="#%E7%AD%89%E4%BE%A1%E6%80%A7%E3%81%AE%E5%88%A4%E5%AE%9A">等価性の判定</a></h3>
<p>C#やJavaのObjectクラスには<code>equals()</code>というメソッドが定義されており、等価の判別が出来る。これもPHPには用意されていないので、汎用的なメソッドとして用意し、インターフェースを実装した。</p>
<pre><code class="php"><?php
namespace BottomUpDDD\Common;
final class Util
{
/**
* @param object $objA
* @param object $objB
* @return boolean
*/
public static function classEquals($objA, $objB): bool
{
return get_class($objA) === get_class($objB);
}
// 以下の処理は省略...
}
</code></pre>
<pre><code class="php"><?php
namespace BottomUpDDD\Domain;
interface EquatableInterface
{
public function equals(EquatableInterface $obj): bool;
}
</code></pre>
<h3 id="リポジトリ"><a href="#%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA">リポジトリ</a></h3>
<p>Laravelを使用したということもあり、学習も兼ねてEloquentを用いて実装した。</p>
<pre><code class="php"><?php
namespace BottomUpDDD\ProductionInfrastructure;
use BottomUpDDD\Domain\Users\UserRepositoryInterface;
use BottomUpDDD\Domain\Users\User;
use BottomUpDDD\Domain\Users\UserId;
use BottomUpDDD\Domain\Users\UserName;
use BottomUpDDD\ProductionInfrastructure\Eloquents\UserEloquent;
use BottomUpDDD\Domain\Users\FullName;
final class UserRepository implements UserRepositoryInterface
{
/** @var UserEloquent */
private $userEloquent;
public function __construct(UserEloquent $userEloquent)
{
$this->userEloquent = $userEloquent;
}
/**
* @param UserId $userId
* @return User|null
*/
public function findByUserId(UserId $userId)
{
$target = $this->userEloquent->find($userId->value());
if ($target === null) {
return null;
}
return new User(
new UserName($target->user_name),
new FullName($target->first_name, $target->family_name),
$userId
);
}
/**
* @param UserName $userName
* @return User|null
*/
public function findByUserName(UserName $userName)
{
$target = $this->userEloquent->findByUserName($userName);
return $target;
}
/**
* @return User[]
*/
public function findAll()
{
$users = $this->userEloquent
->all()
->map(function (UserEloquent $userEloquent) {
return new User(
new UserName($userEloquent->user_name),
new FullName(
$userEloquent->first_name,
$userEloquent->family_name
),
new UserId($userEloquent->id)
);
})->toArray();
return $users;
}
public function save(User $user)
{
$this->userEloquent->persist($user);
}
public function delete(UserId $userId)
{
$this->userEloquent->deleteByUserId($userId);
}
}
</code></pre>
<h2 id="あとがき"><a href="#%E3%81%82%E3%81%A8%E3%81%8C%E3%81%8D">あとがき</a></h2>
<p>正直なところ、読む前はリポジトリやエンティティを用いてDDDしてみたというような記事をみかけては、「それって〇〇アーキテクチャを適用しただけでは…?」と思っていた。でも実際書いてみると、かなり歯ごたえがあって実装したときの達成感のようなものがあったので、書きたくなるのもわかるなぁという感じ。こうして自分も記事にしているので。</p>
<p>ただ参考記事や書籍にも書かれているように、ユビキタス言語や境界づけられたコンテキストなどの概念がより重要であり、技術的な側面だけを注力するといわゆる軽量DDDに陥ってしまうので、戦略的設計に関わる知識もインプットしていく。</p>
<blockquote>
<p>軽量DDDとは、DDDの戦術的パターンの一部だけをつまみ食いする方法で、ユビキタス言語を見つけ出して育てていこうなどという気は毛頭ない。おまけにこの手法は、境界づけられたコンテキストやコンテキストマッピングも使わずに済ませることが多い。技術面だけに注目して、技術的な問題だけを解決したがっているのだ。この方法にはメリットもあるが、戦略的モデリングを併用したときのような大きな見返りは得られない。(実践ドメイン駆動設計より)</p>
</blockquote>
<p>最後に写経したものはGitHubに置いているので、参考になれば。</p>
<p>[https://github.com/chocol4t/bottom-up-ddd-php:embed]</p>
<p>nrsさんのサンプルコードはこちら。(C#)</p>
<p>[https://github.com/nrslib/BottomUpDDD:embed]</p>
<h2 id="参考URL"><a href="#%E5%8F%82%E8%80%83URL">参考URL</a></h2>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://github.com/ytake/valueobjects">ytake/valueobjects</a>
<ul>
<li>Utilクラスを参考にしました。</li>
</ul></li>
</ul>
choco