Open14

スキーマベース開発でインフラ間のバージョン差によるバグを抑制するアイディア

ハトすけハトすけ

悩み事。
互換性を保つ開発の複雑さ。

手元のPCであれば、フロントもバックもDBも同時に更新ができるので気づきにくいが、それぞれのインフラは残念ながら一気にリリースができないため、壊れないようにするためにもリリース順序が大事。

ある項目をDBから削除するとき。

  1. フロントエンドのその項目に関する依存を消す
  2. バックエンドのその項目に関する依存を消す
  3. DBのその項目を消す

ある項目をDBに追加するとき。

  1. DBにその項目を追加する
  2. バックエンドにその項目を追加する
  3. フロントエンドにその項目を追加する

ある判別ロジックをフロントエンドから渡してほしいとき

  1. フロントエンドに判別ロジックを実装しAPIに渡す
  2. バックエンドに判別ロジックを受け取り判別する実装をする

もしくは

  1. バックエンドに判別ロジックをnullableにしてフロントから渡してもらう実装を書く
  2. フロントエンドに判別ロジックを実装する
  3. nullableを削除する
ハトすけハトすけ

ビッグバンリリースとかで追加と削除を同時にやったら地獄。
一般的に削除はフロントエンドから、追加はDBからやる。ここでジレンマが生じる。
そこで、改善策としては、追加コードをnullableにしつつ、フロントからリリースし、最後にnullableを消す。

ハトすけハトすけ

ここらへんをうまく楽に管理してくれるツールはないのか。

ハトすけハトすけ

一般的な解決策としては、

セマンティックバージョニングを採用し、基本的に値の削除はしない。
削除する項目はdeprecatedにしておき、メジャーバージョンアップ時にフロント側から徐々に消していく。それで互換性を保持する。

ハトすけハトすけ

基本的にインフラをともにする奴ら同士は、一気にリリースすることができるから、究極1つのサーバーにフロントもバックエンドもDBもいれれば、こんな問題は起きないんだけど。

ハトすけハトすけ

スマホアプリケーションとか最悪だよね。

アプリのバージョンアップはユーザーに依存しているから。ユーザーが古いバージョンを使っている限り、常に古い互換性のことを考えておかないといけない。

ハトすけハトすけ

各インフラ単位ごとに、スキーマとスキーマバージョンをもたせるのはどうだろうか?
スキーマ自体は統一して扱えるようにJSONとかで表現する。

DBはDBスキーマを提供する
バックエンドは DBスキーマに依存しAPIスキーマを提供する
フロントはAPIスキーマに依存する

スキーマの項目を追加時はマイナーバージョンアップ
スキーマの項目を削除時はメジャーバージョンアップ
それ以外のリリース時はパッチバージョンアップ

それを統一した方法で扱うことができれば

ハトすけハトすけ

各インフラの起動時に自分のもっているスキーマのバージョンと依存サービスの現行バージョンを確認する。マイナーバージョンやパッチバージョンが異なっていてもよい。メジャーバージョンが異なっていれば....

いや、これだと、DBをメジャーバージョンアップでリリースしたあとに、バックエンドがうまくリリースできないな。。

いっそのこと、バージョンいらないんじゃない?スキーマの差分だけ比較する

ハトすけハトすけ

ほかによくある対応としては、インフラのすべてのバージョンを一致させること

フロント v1.2.1
バック v1.2.1
DB v1.2.1

みたいな

ハトすけハトすけ

インフラというかリリース単位といったほうがいいか

ハトすけハトすけ

メジャーバージョンアップデート時には、旧メジャーバージョンのリリース単位を物理的に残して、並行運用するのもありかもしれない。DBとかはムリだけど

ハトすけハトすけ

ここらへん、ビッグテックはどう解決してるんだ?

ハトすけハトすけ

メジャーバージョンのx.0.0では既存のdeprecatedを削除する警告の意味をもたせてもいいかもしれない。
x.1.0以上で実際に削除を行っても良い。

ハトすけハトすけ

フロント側は依存先のスキーマと自信が保持しているスキーマのメジャーバージョンが異なれば、強制的にアップデートされるような仕組みをもたせておく。

そしてフロント側のメジャーバージョンアップデートでは、deprecate依存を強制排除しないといけない。