このブログは、株式会社Penmarkの社内ブログを転送した物です
Firestoreにデータを保存する時のルールをいくつか。
IDを定義し、それをdocのフィールドに保存する
Firestoreには、docの追加時に自動でUUIDを生成する方法があるが、これには頼らずに、
ドメインEntityを一意に識別するIDを定義し、それをFirestoreのdocのIDにも流用する。
例えば、授業Entityなら、「授業名、開講学期、キャンパス、年度、担当教員、時限」で授業を一意に定めることができる。これは人間にとって識別しやすいIDになる他、後から簡単にデータを上書きできるようにもなる。(DDD本 P92を参照)
ID生成についての知識を持つべきかどうかはコンテクストによって異なる。
授業データをスクレイピングし、それをFirestoreに保存するpenmark-timetable
アプリのコンテクストには、当然ID生成の知識が必要となる。
class Lecture{
constructor(
readonly title: string,
readonly campus: Campus,
...
penmark-timetable
のコードでは、上のようにコンストラクタではIDを受け取らず、インスタンス初期化時にID生成を行っている。
しかし、penmark-app
のコンテクストではID生成の知識はあってはならない。クライアント側から授業データを追加することはできないからである。
class Lecture{
Lecture(
LectureId id,
String title,
...
penmark-app
のコードでは、上のようにコンストラクタで直接IDを受け取っている。
このように、コンテクストによってID生成の知識の有無の判断が必要になる。また、IDに限らず、Aggregateの関係等もコンテクストによって変わる。
例えばpenmark-app
ではLecture Aggregateの一部として Modify Entityがあるが、
penmark-timetable
ではLectureはAggregateではない。これは直接コードを見て確かめること。
データ型を厳格にする
例えば、日付(Date)オブジェクトをFirestoreで表現する際、
{"date": "2000-1-1"}
や、
{
"date": {
"year": "2000",
"month": "1",
"day": "1"
}
}
ではなく、
{
"date": {
"year": 2000,
"month": 1,
"day": 1
}
}
が望ましい。
データ構造を適切に表現すること。
永続化機関(ここではFirestore)に保存するのは、ドメインEntityの永続化機関での表現となる。ここからわかるように、ドメインEntityの表現はPresentation, Domain, Infrastractureで異なる物となる。
永続化機関での表現が、Presentation層での表現やDomain層での表現に依存しないようにする事。
このために必要になってくるのが、DTO(Data Transfer Object)である。 参考
penmark-timetable
ではシラバスからのデータ構造体をドメインEntityに変換するDTOや、
Firestoreでの構造とドメインEntityの間での双方向の変換に対応したDTOがある。
penmark-app
ではドメインEntityを文字列として表現する為のDTOがある。
ドメインモデルの適切な表現は各層毎に変わるので、DTOで変換する事により結合度が下げられる。この変換は一方向の場合もあれば、双方向の場合もある。
不変性、変性の見極め
penmark-app
では、授業データをユーザーデータの中にコピーする事によって、オフライン時での時間割確認や、時間割の読み込みのパフォーマンス向上を図っている。
授業データのタイトルや、キャンパス、時限など、未来永劫不変である部分をコピーしているので、元データの更新に伴うコピーデータの更新の必要も無い。
データ構造での 変性 / 不変性 を分析し、docの別々の部分に保存する事。また、必要に応じて不変なデータのコピーを行うこと。