パフォーマンスと変更容易性はトレードオフ

sukechannnn
·

パフォーマンスを高めようとすると変更を加えるのが難しくなる、というトレードオフの話をこの前友人としたので、メモっておく。

例となるアプリ

例えば、以下のような新聞のレイアウトと入稿を管理するアプリを作っていたとする。以下の説明は、あくまでユーザーから見た時の振る舞いである。

  • 新聞デザイナー: 新聞(Newspaper)のレイアウトを Page / Block で設定できる

    • Page: 新聞のページ

    • Block: 1ページ内の表示区画で、配置場所の情報を持っている

  • 記者: 予めレイアウトされた各ブロックに、記事の内容(Article)を書き込める

このアプリは、以下のような流れで利用される。

  1. 新聞デザイナー: 新聞のレイアウトを作成する

    • Newspaper に対して Page と Block を設定する

  2. 記者: 予めレイアウトされた各ブロックに記事を書き込む

    • 設定されている Block に対して Article を執筆する

  3. エンドユーザー: 公開された新聞を読む

こんなアプリを実装する時に、パフォーマンスを高めようとすると変更容易性が下がる例を見てみる。

初めの実装...変更はしやすい

最初は愚直にRDBのテーブル構造をモデルとして実装してみる。その場合のテーブル構造は以下のような形が想像できる。

Newspaper が Page を、Page が Block を複数持っていて、各Block は1つの Article を持つ(記事のレイアウトは毎日変わるので、Newspaper ~ Block をテンプレートにはしない)。

この場合、Newspaper に対して Page / Block / Article という概念ごとにテーブルを分けていて、エンドユーザーが記事を表示しようとする度に Newspaper から芋づる式に join が発生する。Block と Article は1対1なのでまとめてしまっても良いかもしれないが、それでも減らせる join は1つだけだ。

これがパフォーマンス的に問題かどうかは、そのアプリケーションによるだろう。新聞のように非常に多くのエンドユーザーが見る場合は、問題となる可能性が高い。

ただし、変更は加えやすい。APIのスキーマはバージョン管理が必要だろうが、そのスキーマにデータをマッピングするのはコードの修正だけで済む。

パフォーマンスを高める...変更容易性が下がる

上記の実装は実直で分かりやすいが、パフォーマンスに問題が出るかもしれない。では、パフォーマンスを高めるにはどうしたら良いか。

例えば仕様として「Article は記者が書いて Publish したら、後から訂正できるが反映されるまでは数分かかっても良い」とする場合、配信用のデータを生成して返す形が想像できる。記事を更新したら再生成してCacheを更新する。

速度を取るなら、クライアント用に最適化したデータを予めビルドしておいてまるっと返すのが一番速い(以下 Data for Client)。

ただし、これは複雑度が増している。Data for Client の生成自体は難しいことではないだろうが、リリース後に構造に変更を加えるのが大変だ。

例えば、記事の構造を変えたい(Block に複数の Article を追加できるようにしたい)場合には、Data for Client のマイグレーションが必要となる。でも配信済みのデータに直接手を加えると後方互換性が取れない(もちろんダウンタイムは発生させたくないし、モバイルアプリも提供している)。

そのため、Data for Client のバージョン管理が必要になり、複数バージョンの Data for Client を配信し続けないといけない。また、リリースの順番も気をつけないといけない(予め新しいバージョンの Data for Client ver.2 を生成して配信しておかないと、新しいアプリは記事を表示できない)。

まとめ...プロダクトのフェーズに応じて判断しよう

プロダクトを作り始めたばかりで、エンドユーザーの数がまだそこまで多くないなら「初めの実装」で十分だろう。その間にもユーザーからFBがたくさん来て、たくさん機能を開発したくさん修正を加えないといけない。このフェーズでデプロイに気を遣うのは致命的だ。main ブランチにプルリクをマージしたら勝手にデプロイされるくらいでないといけない。

ユーザーの獲得に大成功して、とんでもない数のユーザーが入ってくることが目に見えているなら、パフォーマンスを高める最適化を施そう。その後の運用が大変になるけど、きっとその時には優秀なSREメンバーがいるはずだから、デプロイフローの整備や配信データのバージョン管理システムなんかも作ってくれるはずだ。