(Photo by:Shintaro Kakutani)
はじめに
いつもどんなソフトウェア設計手法を使っていますか?独自の設計手法を使っている方が多いのではないでしょうか?ソフトウェア設計は複雑なもので、100人のエンジニアからは100の設計が生まれることでしょう。たしかに独自の設計手法を編み出すのもよいのですが、業界の賢人に学ぶことも大切です。そこで今回は、エリック・エヴァンス氏が提唱する「ドメイン駆動設計(Domain Driven Design)」を紹介します。
この記事では、新しいソフトウェア設計手法を取り入れたい方のために、ドメイン駆動設計の主要な概念をお伝えしていきます。設計はソフトウェアの根幹をなす重要な部分です。後から設計を変更するには多大なコストが発生するため、最善を尽くしておくべきでしょう。もちろんドメイン駆動設計によってすべてが解決するわけではありませんが、きっとあなたの設計の助けになってくれることでしょう。
ドメイン駆動設計の概要
ドメイン駆動設計(Domain Driven Design)とは、エリック・エヴァンス氏が自身の経験からノウハウやベストプラクティスをまとめた設計手法の集大成です。とはいってもドメイン駆動設計はまったく新しい手法というわけではなく、一部既存の手法やパターンを組み合わせたようなものになっています。そのため、ドメイン駆動設計の中にはどこかで聞いたことがあるような手法も含まれています。多数のパターンを含んでいますが、単なる寄せ集めではありません。各パターンは関連を持っていて、設計手法としてしっかりとしたまとまりがあります。それでは、次項からドメイン駆動設計の主要な概念をみていきましょう。
ドメインってなに?
”ドメイン”駆動設計という名前にあるように、「ドメイン」が中心的な存在になっています。ドメインとは、ソフトウェアが対象としている業務領域のことです。たとえば、顧客管理ソフトの場合は”顧客管理業務”が対象のドメインということになります。そして、ドメインに精通した専門家を「ドメインエキスパート」と呼びます。ドメイン駆動設計では、ドメインエキスパートと協力して設計を進めていくことになります。
ユビキタス言語を使う
専門用語が相手に伝わらなかった経験は誰にでもあるでしょう。これは「エンジニア」と「ドメインエキスパート」の間でも起こります。エンジニアは技術的な専門用語を使い、ドメインエキスパートは業務内の専門用語を使うといった具合です。そのため、相手に伝えるためには専門用語を”翻訳”する必要がでてきます。しかし、翻訳をすると重要な情報が欠落してしまったり、微妙なニュアンスが伝わらなかったりすることがあります。また、コード内に現れる用語もドメインエキスパートが使う用語ではないため、いちいちなにと対応しているのか考えなくてはなりません。
こういった問題を解決するため、ドメイン駆動設計では「ユビキタス言語」を使います。ユビキタス言語とは、開発者とドメインエキスパート双方が理解できる共通語です。ユビキタス言語を使いドメインモデルを作成することで、ドメインエキスパートとスムーズに設計を進めていくことができます。ドメインモデルについては次に説明します。
ドメインモデルを設計する
UML(統一モデリング言語)のクラス図などを使ってドメインモデルを設計します。ドメインモデルとは、各要素の属性(プロパティ)や振る舞い(メソッド)、関連(参照)などを表現した図です。この作業にはユビキタス言語を使用して、ドメインエキスパートと協力しながら段階的に設計をしていきます。そして、このドメインモデルがソースコードと一対一に対応するようにします。これにより設計とソースコードが同期されることになり、ドメインエキスパートとの協調も容易になります。次にドメインモデルを構成する要素を説明します。
ドメインモデルを構成する要素
エンティティ
エンティティは、属性や振る舞いなどを持ったオブジェクトです。たとえば、顧客や注文、銀行口座などにあたります。ほとんどのエンティティにはIDを持たせて同一性を確保することになるでしょう。エンティティ同士を協調(関連)させることでシステムを構築します。
値オブジェクト
値オブジェクトは、エンティティの持つ属性のひとつです。単純なフィールドとして値をもたせるのではなく、専用のクラスを用意して値を表現します。たとえば、氏名やメールアドレス、電話番号などです。複数のエンティティから参照されることもあるため、値オブジェクトは「不変(イミュータブル)」である必要があります。そうしなければ、参照により無関係なエンティティの値まで変更されてしまいバグの元になってしまいます。
サービス
サービスは、エンティティや値オブジェクトのどちらにも該当しないような状態を持たないオブジェクトです。たとえば、口座間の資金の振替をするメソッドは口座エンティティに持たせるのは不自然なので、振替サービスとして独立させます。無理にエンティティや値オブジェクトにメソッドを持たせるのではなく、適切にサービスに分離しましょう。
リポジトリ
リポジトリは、エンティティや値オブジェクトの永続化処理を担当します。エンティティや値オブジェクトはどこからともなく生まれてくるわけではありません。多くの場合、データベースなどのストレージから値を読みだしてエンティティを構築(インスタンス化)する必要があるでしょう。こういった作業をその都度行っていてはコードが冗長になってしまいます。また、逆にストレージに値を保存する場合も同様です。そのため、ストレージと関わる処理をリポジトリにまとめて再利用できるようにしましょう。
ファクトリー
ファクトリーは、新しいエンティティと値オブジェクトの生成を担当します。単純なエンティティなら問題ありませんが、複雑なエンティティになると単純なインスタンス化だけでは済まない場合もあります。コードの冗長化を避けるために、初期化処理はファクトリーに任せましょう。ほとんどのファクトリーは状態を持たないため、シングルトンとして実装されることが多いです。
モジュール
モジュールは、ドメインモデルの要素が属するグループです。Javaでいうパッケージに該当するものですね。大規模なソフトウェアでは、関連するオブジェクトをパッケージにまとめてパッケージ間を疎結合にしましょう。ただし、バッケージ間のクラスの移動には手間がかかるため慎重に分類してください。
集約
集約は、関連する複数のエンティティや値オブジェクトをひとつの「ルートエンティティ」にまとめることです。たとえば、注文エンティティに商品エンティティと小計値オブジェクトをまとめるといった具合です。この場合、注文エンティティの外部からは商品エンティティや小計値オブジェクトに直接アクセスすることはできず、注文エンティティを介してやり取りします。これにより、関連はルートエンティティに集約され、ルートエンティティ配下のオブジェクトの一貫性を保つことができます。
まとめ
ここまでドメイン駆動設計の主要な概念を紹介してきました。ドメイン駆動設計はかなり広範囲な設計パターンを含んでいるため、これ以外にも多数の概念があります。そのため、すべてを理解して実践しようと思うとかなりの労力を要します。基礎的な部分から少しずつ実践して設計に取り込んでいくほうがよいでしょう。エリック・エヴァンス氏本人による著書も含め何冊か参考書籍が出版されています。体系的な情報がないと理解するのは困難ですので、書籍で学習することをおすすめします。さあ、あなたも今日からドメイン駆動設計をはじめてみましょう!
本ブログは、Git / Subversion のクラウド型ホスティングサービス「tracpath(トラックパス)」を提供している株式会社オープングルーヴが運営しています。
開発の効率化をしたい!もっと便利なツールを使いたい!そんなお悩みをtracpathで解決!
「tracpath(トラックパス)」は、企業内の情報システム部門や、ソフトウェア開発・アプリケーション開発チームに対して、開発の効率化を支援し、品質向上を実現します。
さらに、システム運用の効率化・自動化支援サービスも提供しています。
”つくる情熱を支えるサービス”を提供し、まるで専属のインフラエンジニアのように、あなたのチームを支えていきます。
No Comments