読者です 読者をやめる 読者になる 読者になる

はむはむエンジニアぶろぐ

このブログのコンセプトは"ハッキングの為なら愛する家族を傷つけることをいとわない" 自分にとってエンジニアリングは "手段ではなく生きる目的" である

Adapterパターンでドメインレイヤと技術レイヤを分離する

デザインパターン DDD Adapter リファクタリング

f:id:secret_hamuhamu:20150913014110j:plain
ドメインを理解するために、ソースコードを読んでいて読みにくさを感じる瞬間の一つにドメインレイヤと技術レイヤの話が混じっている場合です。
ドメインとして関心があるのは、どんなデータを扱うのか?どういう振る舞いをするか?です。

技術レイヤの話は、ドメインを理解する際に不要な情報で、コードを読みにくくする要因です。
ユーザを登録する際に、DBを使用しているのか?ファイルに書き込んでいるのか?外部APIを叩いているのか?というのはドメインを理解するために必要な情報ではありません。

もちろん、どのようにユーザを登録しているのか?という情報は大事なことです。
問題は、ドメインレイヤと技術レイヤが混じっていることで、それ分離する必要があります。

Adapterパターンを使うことで、ドメインレイヤと技術レイヤを分離する事ができます。

Adapterパターンとは?

Adapterパターンは、既存のクラスのインターフェース(published interface)を変更することなくインターフェースを変更するというものです。

どのようにインターフェースを変更するかというと、2通りあります。

1. 継承
2. 委譲

既存のクラスを継承か委譲を用いてラップします。

Adapterパターンを適用してみる

例えばとある会員サービスのユーザを登録する際に、以下のドメインの関心ごとがあるとする。

  1. ユーザを登録する
  2. チュートリアルに参加させる

これが一塊になっていて、かつドメインレイヤと技術レイヤが結合しているとコードが読みにくく、メンテナンスしづらいです。

<?php
class User
{
    public function register($params)
    {
        // パスワードを暗号化
        $hash = new Hash();
        $password = $hash->encrypt($params['password']);

        // ユーザを登録
        $binds = [
            'NAME' => $params['name'],
            'mail' => $params['mail'],
            'password' => $password,
        ];
        $userDao = new UserDao();
        $userDao->insert($binds);
        $userId = $userDao->lastInsertId();

        // チュートリアルに参加
        $binds = [
            'USER_ID' => $userId,
        ];
        $tutorialDao = new TutorialDao();
        $tutorialDao->insert($binds);
    }
}

ドメインを理解する際に、どのようにユーザを登録しているか?どのようにチュートリアルに参加させているか?ということは邪魔な情報である。
ドメインを表現するために、要約する必要がある。

委譲を使ったAdapterパターン

新たに UserRegisterTutorial クラスを作り処理を委譲する。
Adapterパターンが適用された。
既存のクラスである UserDaoTutorialDao のインターフェースを変更せずに Adapter がよしなにやりとりしている。

<?php
class User
{
    public function register($params)
    {
        $userRegister = new UserRegister();
        $userId = $userRegister->execute($params);

        $tutorial = new Tutorial();
        $tutorial->entry($userId);
    }
}

class UserRegister
{
    public function execute($params)
    {
        // パスワードを暗号化
        $hash = new Hash();
        $password = $hash->encrypt($params['password']);

        // ユーザを登録
        $binds = [
            'NAME' => $params['name'],
            'mail' => $params['mail'],
            'password' => $password,
        ];
        $dao = new UserDao();
        $dao->insert($binds);

        return $userDao->lastInsertId();
    }
}

class Tutorial
{
    public function entry($userId)
    {
        // チュートリアルに参加
        $binds = [
            'USER_ID' => $userId,
        ];
        $dao = new TutorialDao();
        $dao->insert($binds);
    }
}

ドメインレイヤと技術レイヤの間にアダプタレイヤを挟むことで分離する事ができた。

レイヤ構造
ドメインレイヤ User
アダプタレイヤ UserRegister, Tutorial
技術レイヤ UserDao, TutorialDao

Adapterパターンを適用することで、ドメインの表現が磨かれた。
ユーザの登録処理とチュートリアルの参加処理は、個別に安全にリファクタリングできる。

おすすめの本

エリック・エヴァンスのドメイン駆動設計

エリック・エヴァンスのドメイン駆動設計

実践ドメイン駆動設計

実践ドメイン駆動設計

実践テスト駆動開発 テストに導かれてオブジェクト指向ソフトウェアを育てる (Object Oriented SELECTION)

実践テスト駆動開発 テストに導かれてオブジェクト指向ソフトウェアを育てる (Object Oriented SELECTION)

テスト駆動開発入門

テスト駆動開発入門

  • 作者: ケントベック,Kent Beck,長瀬嘉秀,テクノロジックアート
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2003/09
  • メディア: 単行本
  • 購入: 45人 クリック: 1,058回
  • この商品を含むブログ (161件) を見る