nato243 weblog.n-jitter brand iconweblog.n-jitter
テクノロジー

下書きと完成品と検索と。  Re:「下書き」「一時保存」という要件を甘く見積もってはいけない

2024.11.06
ポエム
下書きと完成品と検索と。  Re:「下書き」「一時保存」という要件を甘く見積もってはいけない アイキャッチ

なんかこんなZennのポストが流れてきた。
タイトルの通り「下書き実装」に関しての DB設計とかの話です。


この記事では要件見えない(ぼかしてる)せいもあるのか、はてなだと記事CMSの下書きテキスト程度の設計感覚で「それだけJSONでいいんじゃね?」みたいな意見が多かった。

でもまあほんとに要件によるかな...。
いろいろ似たような実装したこと思い出して、「多分それで済む話じゃなかったんだろうな」みたいなピンときた感覚があった。

今もバッチリした答えがないので整理がてら書いてみます。


「完成品」と「下書き」はおなじコンテンツの別モデル?

本稿では今回のテーマを、
「下書き」
「完成品」

という状態変化の話として定義する。

ここでいう「下書き」は、中途半端な状態でいくらでも永続化でき、かつUX要求によって頻繁に変更がはいり、柔軟さが求められるもの。

一方で「完成品」は、所与のバリデーションが通ったうえで、RDBの一般的な正規化作法に則った”きれいな”状態で永続化されたものとする。

「完成品」と「下書き」は別モデル



UX/UIモデル変更というのはDB/ドメインモデリングどれだけ頑張ってようがある程度は発生する。
特にここでいう「下書き」はユーザー主体の書き込み処理が頻繁に発生する箇所ではあるかと思うので、まさにどれだけわかりやすくするかがサービスの肝になったりするポイントだろう。当然、UX変更も多くなる。
一方で「完成品」はそこまでの変更要求はなく、DB上の治安のほうが優先される。

このようにライフサイクルが大きく違うものは、別モデルとして定義すると筋がいい場合が多い
「完成品」と「下書き」は、別物では?という感覚は悪くない気はする。

「下書き」にスキーマレスな柔軟な永続化領域を利用するというのは、途中保存の治安の悪いデータなり、頻繁なUX変更要求などを扱ったりすることにおいて、それなりに効力を発揮する。
スキーマレス運用も永続化もオレオレスキーマ維持の作法とか多少の論点はあるけど、ある程度整っていればまあJSONでもいいかというのはその通りで、皆一回は考えるっしょという感じではある。

(関係ないけど、今、本記事をいじってるmicroCMSも同じ記事の公開状態と下書きプレビューは別で扱えるわけで、それはそれでいろいろテクニックがあるのだろうと想像)

「完成品」と「下書き」は検索上は一緒に出してほしい

だが、それで済まないこともある。

自分のお仕事のケースだと、「下書き」に書き込まれたデータと「完成品」って結局等価で検索要件があった。結局同じリストUIに出るとか同じクエリで検索しなきゃいけない、ということ。
DB上がどうであれUI上のモデルとしては同じってわけで、OOUI的な事情とDBのモデルとはまた粒度のレイヤが違うわけだ。

そのとき、はじめは「下書き」実装はJSONで考えていたが、「JSONとそうでないものを同クエリ条件にいれつつ検索すんのか?まじで?」みたいな感想が先に立ち、結局下書きを別モデルにするアイディアは捨てて、記事のようにテーブル設計をし、下書きも防御的なリビジョン実装をいれた。


つまり、「下書き」も「完成品」も同じテーブルを使えるようけっこう真面目なRDB設計をしたわけだ。
DEFAULT NULLとかは最小にして、正規化して、リビジョン実装を切って...、みたいな。

こういう経験があったので記事の人も似たような別の事情だったのかなとか想像した。

「横断リスト検索」も、もはやそれ結局別のREADモデルなのでは? (今)

当時は、「下書き」実装をDB上別モデル/スキーマレスにするアイディアは捨てて、

  • MySQLとCRUDで済んだ
  • RDB設計の定石としてはやるべきことをやった

...のではあるが、結局今の時代だと自分はどうするだろうか?



おそらく、検索要件のほうこそむしろ別テーブル、別要件として非正規化するかもしれない。

検索テーブルへの反映が限りなくリアルタイムであれば、下書きどころか完成品もsingle truthはJSONとかで構わないわけだ。イベント駆動とかCQRSの話題とかで同様の考え方は近年はよく取り沙汰されるようには思う。

ただ、ここで別途必要になるのは

  • Postgresならマテビューを焼く
  • MySQLトリガーやプロシージャを駆使してViewを焼く
  • イベントストア基盤で焼く
    • RDB
    • DynamoDB/Kinesis Stream やEventBridge Pipe,SQS
  • 結果整合性の許容度の設計
  • 上記までを維持するパフォーマンス確保
  • システムの複雑化

等、別の知識になる。当時はこのへんのノウハウがなかったが、今はある程度ある。

結局それらしいRDB設計やってても、サービスの成長とともに検索クエリの複雑化やパフォーマンスの都合上、どこかのタイミングでは検索Viewらしきもの非正規/非同期で焼くことになる。
プロダクトがある程度複雑化し、一度イベント駆動基盤作っちゃった後ならこっちのほうが建設的な展開が望めそう、というのが最近の感覚だ。

どこかでやってみようか...。