$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

エリック・エヴァンズのドメイン駆動設計読んだ

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

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

読んだ。

エンティティ、値オブジェクト、集約など、自分の中でなんとなくの理解になっていたところを、より具体的に言語化出来たことが良かった。一方、用語が難解なため理解が難しく、既に経験則でなんとなく理解していることを言語化する役には立ったが、新しい知識を習得できたという実感はないことが残念だった。なぜDDD初心者はググり出してすぐに心がくじけてしまうのか - little hands' labの記事を読んだとき「分かる分かる」って感じだったので、「実践ドメイン駆動設計」をまた読んでみようと思う。

実践ドメイン駆動設計 (Object Oriented SELECTION)

実践ドメイン駆動設計 (Object Oriented SELECTION)

読書ノート

* 4つのレイヤ 1938
    * プレゼンテーション層
    * アプリケーション層
    * ドメイン層
    * インフラストラクチャ層
* エンティティ: 主に同一性によって定義されるオブジェクト 2314
* 値オブジェクト: ドメインにおける記述的な側面を表現し、概念的な同一性を持たない場合、そういうオブジェクトは値オブジェクトと呼ぶ 2459
* サービス: 2615
    * モデルにおいて独立したインターフェースとして提供される操作で、状態をカプセル化していない
    * クライアントに対して何が実行できるかという観点から定義
    * 名詞でなく動詞的
* 優れたサービスの特徴 2639
    * 操作がドメインの概念に関係しており、その概念がエンティティや値オブジェクトの自然な一部ではない
    * ドメインモデルの他の要素の観点からインターフェースが定義されている
    * 操作に状態がない
* 集約: 関連するオブジェクトの集まりであり、データを変更するための単位 3102
    * 集約のルートのエンティティを決め、内部へのオブジェクトのアクセスはそれ経由にして制御する
    * ルートエンティティは集約内での不変条件も管理する
* 意図の明白なインターフェース 5310
    * ユビキタス言語を使って、クラスと操作にはその効果と目的を記述する名前をつけることで、利用者に意図を表明する
* リファクタリングのタイミング 6715
    * 設計が、ドメインに関するチームの現在の理解を表現していない
    * 重要な概念が設計で暗黙的になっている(かつ、それを明示的にする方法が分かっている)
    * 設計において重要な部分を、よりしなやかにする好機がある

yarn workspaceを使っている時でもvscodeでeslintプラグインが動くようにする

例えばyarn workspaceを使って、

  • packages/hoge/
  • packages/fuga/

のようにワークスペースを二つに分けて開発したいときがある。この時、ワークスペースごとでeslintの設定やインストールするpackageが分かれてしまっているのでESLintプラグインがうまく動かない。

この場合でもうまく動かすにはeslint.workingDirectoriesを設定すると良い。そのプロジェクトの.vscode/settings.jsonに以下のように設定しておくと良いだろう。

{
  // TypeScriptでもeslintが動くように
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact"
  ],
  // yarnを使う
  "eslint.packageManager": "yarn",
  // workspaceを指定する。CWDも変えたい。
  "eslint.workingDirectories": [
    { "directory": "./packages/hoge", "changeProcessCWD": true },
    { "directory": "./packages/fuga", "changeProcessCWD": true },
  ]
}

Next.jsのpages/ディレクトリ以下にはページ用のファイル以外は置いてはならない

Next.jsではpages/ディレクトリ以下にページ用の実装ファイルを置く規約となっているが、それに追加して、このディレクトリ以下にはページ用以外のファイルは置いてはならないということが分かった。ページ用以外のファイルとは、例えばテストのファイルや共通ロジックのための実装などである。

ファイルを置くことで起こる問題と起こる理由

例えば日記サービスを考えたとして、pages/diaries.tsxのような日記一覧のページを実装するファイルがあったとする。この時、テストファイルはJestの流儀にしたがって、pages/tests/diaries.test.tsxもしくはpages/diaries.test.tsxに置きたくなる。

しかし、この時、次の問題が起こってしまう

  • Next.jsはテストファイルもページ用の実装とみなし、next build時に成果物に含めてしまう
    • .next/server/static/jfklanfkealknl/pages/diaries.test.js のようなファイルができる
  • ルーティングも機能してしまい、例えば/diaries.testのようなURLにアクセスできてしまう。ページの実装がないのでISEが返る

このようになる理由はNext.jsがpages/以下の全てのファイルをentrypointとしてwebpackでビルドしてしまうためである(このへんこのへんを参照)。webpackのentrypointとして指定されているので、next.config.jsのwebpackの設定でIgnorePluginなどを入れたとしても解決しない。

解決策

https://github.com/zeit/next.js/issues/3728 で色々と議論されている。少なくともpagesGlobPatternのような設定や、excludePatternのようなものは提供しない方向となっていそう。

解決策としては例えば以下のようなパターンがありえる。

いろいろ検討したけど、テストのために本番用のコード側を変えすぎるのは避けたい(本番用のロジックでsymlink作ったりしたくない)と考え、__pages_tests__ディレクトリを別で切ってテストを配置することにした。__pages_tests__というディレクトリ名にしたのは、pages/以下のテストしか置かないということを明示したかったためである。

最終形

pages/diaries.tsx
__pages_tests__/diaries.test.tsx