ドメイン駆動設計(DDD)で PHP のコードを書くとき、コンストラクタを直接呼ばずに静的ファクトリメソッドを用意するのは定石になっています。その中でも make と of という二つの名前を見かけるたびに、「どちらをいつ使えばいいのか」と迷う開発者は少なくありません。本稿では、この二つの命名が担う役割と違いを整理し、チームでの実践方法まで掘り下げて解説します。
make と of を区別する背景
DDD が目指すのは、コードをドメインの言葉と一致させ、モデルを読みやすく保つことです。そのためにはインスタンス生成の意図をメソッド名で表現することが欠かせません。特にファクトリメソッドは「どのような前提で何を組み立てるか」を伝える看板に当たります。make と of を使い分けることで、呼び出し側は生成コストや副作用の有無を即座に判断でき、ドメインモデルの理解がスムーズになります。
make の意図と適用場面
make は「ゼロから組み立てる」というニュアンスを持ちます。典型的にはエンティティや集約ルートの生成で利用され、ID の発行、複数値の整合チェック、ドメインイベントの登録といった比較的重い処理を内包します。こうしたロジックをファクトリメソッド内部に閉じ込めることで、呼び出し側は詳細を知らずに安全なエンティティを受け取れます。ファクトリーを利用してビジネスルールを集中管理する手法は DDD の文脈で広く紹介されています。
of の意図と適用場面
一方の of は「既にある値を安全に包む、あるいは変換する」という軽量な意味合いです。主に値オブジェクトで使われ、プリミティブ値を検証してラップするだけという単純な生成に向いています。ビジネスロジックや外部依存を持たせたくない場面で使うことで、値オブジェクトを頻繁に生成してもパフォーマンスと可読性を損なわずに済みます。値オブジェクトとファクトリの関係を説明する資料でも、軽量な静的メソッドの重要性が強調されています。
実装例
以下に User エンティティと Email 値オブジェクトを対比させたコードを示します。User::make では ID の生成や値オブジェクトの組み立てといった複数の手続きを担当し、Email::of では文字列を検証して安全に包むだけで完結しています。
final class User
{
private function __construct(
private UserId $id,
private Email $email
) {}
public static function make(string $email): self
{
return new self(
UserId::generate(),
Email::of($email)
);
}
}
final class Email
{
private function __construct(private string $value) {}
public static function of(string $value): self
{
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
return new self($value);
}
}
このように命名だけで生成コストの大小が読み取れるため、コードベース全体で統一しておくと保守が楽になります。
チームで命名を統一するコツ
静的ファクトリメソッドの命名には from, create, valueOf なども候補になりますが、選択肢を増やしすぎると迷いの元になります。まずは「重い処理や副作用を含むなら make、単一値の変換なら of」という単純なルールを決め、ガイドラインとして共有するのがお勧めです。命名規則を揺るがさないことで、コードレビューの基準が明確になり、将来的なリファクタリングコストも抑えられます。静的ファクトリの命名を議論した記事でも、プロジェクト初期にルールを固める重要性が指摘されています。
まとめ
make は「構築プロセスを伴う新規生成」、of は「既存値の安全な包み直し」という役割を担います。二つのメソッド名を使い分けるだけで、モデルの意図がコードににじみ出て、読み手の認知負荷が下がります。DDD を実践する第一歩として、プロジェクトの命名ガイドラインにこの区別を取り入れてみてはいかがでしょうか。