あけましておめでとうございます。
去年の暮からエリック・エヴァンスのドメイン駆動設計という5200円、500ページもする本を購入して読み始めた自分です。
エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)
- 作者: エリック・エヴァンス,今関剛,和智右桂,牧野祐子
- 出版社/メーカー: 翔泳社
- 発売日: 2011/04/09
- メディア: 大型本
- 購入: 19人 クリック: 1,360回
- この商品を含むブログ (129件) を見る
実際に作られたサイトは、
http://www.soichiro.org/sf
こんな感じです。
- id: [email protected]
- pass: test1
でログインできます。(ユーザー作るだけならadmin/adminpassでもOK)
画面イメージは
こんな感じです。UIにはtwitterのbootstrapを使っています。
ソースコードは、
https://github.com/sifue/UserManagement
からチェックアウトできます。無論MITライセンスです。サンプルとして使えそうな所があったら好きなように改変してご自由にご利用ください。
ドメイン駆動設計はすごく簡単に言うと、システムを作る時って業務モデル(実際のビジネスを抽象化した概念、例えばUMLのクラス図で書いたようなもの)の共有ってすごく重要だよねって話から始まって、そのモデルとシステムをいかに近づけるかって話と、実際のシステムを実装するときには、
- ユーザーインターフェース層 : WebでいうView
- アプリケーション層: WebでいうController
- ドメイン層: すべてのビジネスロジックを集約した実装
- インフラストラクチャ層: Webで言うModel
に分けて実装すれば良いよっていうところから、更に深く実際のいろいろなプラクティスが書かれています。
かなりじっくり読まなきゃいけないタイプの本で、読めば読むほど考えさせられる所もあって読み進まないタイプの本でした。オブジェクト指向大規模アプリ設計の教科書と言っても過言ではないのでしょうか。
読み進んでビックリしたのは、ここに出てくる概念がほとんどSymfony2で実装されているというところでした。たぶんこの本に相当影響を受けてるんだと思います。例えで言うと、
サービス : Symfony2ではサービスコンテナというDIコンテナ- エンティティ: Symfony2ではエンティティというデータクラス
- ファクトリ: Symfony2ではサービスにインスタンスを作るファクトリを登録したり、サービスを作るファクトリを設定できる
- リポジトリ: Symfony2ではリポジトリというORMとの接続処理実装集約クラス
- モジュール: Symfony2ではバンドル、OSGiのバンドルのように拡張ポイントもある
とかがありました。
残念ながらなかった概念は、値オブジェクト。Javaのenumのように不変でstaticなインスタンスを作る仕組みがPHPにはないのでやむなしというところなのかもしれません。
実際にアプリ作るにあたってエリック・エヴァンスのドメイン駆動設計によるとドメイン層はできるだけ集約して一つにして高い凝集にしたほうがよいということだったので、実際に作ったこのユーザー管理システムのバンドル設計、クラス図はこんな風になりました。
Symfony2の思想としては、ドメイン層とアプリ層とUI層を一つのバンドル内で作ってしまうように作られていたのですが、よりドメイン層に全てのビジネスロジックを集約する意図を持たせるために、DomainBundleというものを作りました。
赤がインフラ層、オレンジがドメイン層、緑がアプリ層、青がUI層をあらわしています。UI層のテンプレートファイルやルーティング設定ファイル類は割愛しています。
確かにこの設計で作ってみると非常にアプリの作りがいいように感じます。あと、クラスそれぞれが単一責務になっている。
以下に実際にUserFactoryの実装を書きますが、ここではUserのインスタンスができる際に守らせなければならない、インスタンス作成時は有効になっていることや、ランダムなハッシュ用のsaltの設定などを守らせることができます。
<?php namespace Sifue\Bundle\DomainBundle\Factory; use Sifue\Bundle\DomainBundle\Entity\User; /** * Userインスタンスの作成とインスタンスが守らなければいけない整合性を保つ責務を持つクラス */ class UserFactory { /** * ユーザーのインスタンスを取得する * @return Sifue\Bundle\DomainBundle\Entity\User */ public function get() { $user = new User(); $user->setIsActive(true); $user->setSalt(base_convert(sha1(uniqid(mt_rand(), true)), 16, 36)); return $user; } }
いい具合に責務が分離されています。
これなら大規模開発で拡張、リファクタリングを続けていっても耐えられる構成なのではないかなという確信を得ることができました。
とは言えまだドメイン駆動設計、ぶっちゃけ業務でいろいろやってみないとわからないことも多そうなので、いろいろなテクニックを取り入れながら少しずつ試して行けたらななんて考えています。まだ初心者な所もあるので、ご指摘などあればコメント下さい。
ちなみにこのアプリ。Symfony2のインストールのためのPHP環境、MySQL環境を揃えた後、
$ git clone [email protected]:sifue/UserManagement.git $ vim app/config/parameters.yml
parameters: database_driver: pdo_mysql database_host: 127.0.0.1 database_port: ~ database_name: symfony database_user: root database_password: password mailer_transport: smtp mailer_host: 127.0.0.1 mailer_user: ~ mailer_password: ~ locale: ja secret: ThisTokenIsNotSoSecretChangeIt
$ php app/console doctrine:database:create
$ php app/console doctrine:schema:update --force
とするだけで、UserManagement/webをウェブサーバーに公開すれば動かすことができるようになっています。
テストもひと通り実装してあり、PHPUnitがインストールしてあれば、
$ phpunit -c app
で全てのテストが実施可能です。
Symfony2はPHPUnitをいい具合に拡張してあって、WebのUIをエミュレーションするテストやサービスコンテナのテストができるところが便利です。
ぜひ試してみて下さい。
追伸
ちなみに自分はPHPなんてオブジェクト指向言語の風上にも置けない言語だと思っていたのですが、Symfony2に触れて全然そんなことはないな、普通に戦えるフレームワークだなと思いました。PHPはひどい言語だけど、捨てたもんじゃない!きっとw