TT Lab
はじめる
学ぶ 学習パス コース

統合とデプロイ

フィールド名が変わり、合計だけが静かに狂った

TT Labで続きを見る

目標

パートナーの注文APIの1.3と1.4を並べて、何がこちらを壊すのかをフィールド単位で見分けたあと、こちらが読むものだけを書いたコンシューマー契約と、その契約を毎回確認する契約テストを作ります。旧バージョンと新バージョンを同時に受け入れる読み取り層まで付けます。

なぜ重要なのか

接続が切れる事故は、アラートが鳴ります。フィールドの名前が変わる事故は、鳴りません。rec.get("region")は例外の代わりにNoneを返し、増えた列挙値はこちらの分岐のどこにも入らず、整数が十進文字列になると合計が黙って変わります。 そのため、統合の安全装置は「ドキュメントをよく読むこと」ではなく、機械が毎回照合する契約です。契約には、パートナーの全体のスキーマではなく、こちらが実際に読むフィールドだけを書きます。全部書くと、こちらが使わないフィールドの変更にも赤信号が点き、ノイズが増えると、人はテストを切ります。 バージョンアップは、一度で終わることもありません。旧バージョンと新バージョンが数か月一緒に動く間、読む側が両方を受け入れる必要があるので、名前が変わった箇所は別名表で、型が変わった箇所は正規化関数で、1か所にまとめます。 採点ツールは、作成した文章を信じません。作成したパートナーサーバーを、採点ツールが選んだポートで直接起動して応答を受け取り、作成した判定器と照合器を、採点ツールが作った入力で再度実行して、答えを合わせます。

ステップ

  1. /root/contract/partner.pyを作成してポート8011で起動し、2つのバージョンの応答を、/root/contract/v13.json、/root/contract/v14.jsonの順に保存してください。
  2. 2つの応答のフィールドの差を、/root/contract/diff.jsonに、added・removed・type_changed・enum_addedの4つの欄で書いてください。
  3. /root/contract/breaking.pyを作成して、変更1件を受け取って、こちらを壊すかどうかを判定するようにしてください。
  4. こちらが読むフィールドだけを書いたコンシューマー契約を、/root/contract/order.contract.jsonに書いてください。
  5. /root/contract/validate.pyを作成して、契約とレコードを照合し、違反をmissing・type・enumに分けて書くようにしてください。
  6. /root/contract/read_order.pyを作成して、1.3と1.4の応答を、どちらも同じ内部の形に移してください。
  7. /root/contract/contract_test.shを作成して、パートナーの現在の応答を契約と照合し、ずれていたら0以外のコードで終了するようにしてください。
  8. /root/contract/contract_report.mdに、4つの節で報告してください。

参考

2つのバージョンを一緒に提供するパートナーを起動する

/root/contract/partner.pyを作成してポート8011で起動し、/v1.3/ordersと/v1.4/ordersの応答を、順に、/root/contract/v13.json、/root/contract/v14.jsonに保存してください。注文は2つのバージョンとも24件です。

flaskで3つのパスを作ります。/healthは準備ができたことを知らせる場所で、2つのバージョンの一覧のパスは、同じ注文24件を、それぞれのフィールド名と型で出力します。--portと--driftをargparseで受け取ってください。フォアグラウンドで起動するとターミナルが塞がるので、バックグラウンドで起動して、/healthが200になるまで待ちます。

2つのバージョンの差を機械が読める形で取り出す

/root/contract/diff.jsonに、added、removed、type_changed、enum_addedの4つの欄を書いてください。addedとremovedはフィールド名のソートされたリスト、type_changedは{"field": ..., "from": ..., "to": ...}のリスト(型名はinteger・string)、enum_addedは{"field": ..., "values": [...]}のリストです。列挙と見なすフィールドは、新バージョンで異なる値が6個以下のフィールドに限定します。

2つの応答ファイルの最初のレコードだけを見れば、フィールド名の集合が得られますが、列挙値は全件を調べて初めて見えます。型名は、integerとstringの2つで十分です。statusのように値が数種類しかないフィールドは、両側の値の集合を引いてみてください。

何がこちらを壊すのかを見分ける

/root/contract/breaking.pyを作成して、--change <파일>(プレースホルダーはファイルです)で受け取った変更1件を判定し、{"breaking": true|false, "reason": "..."}を出力するようにしてください。応答側とリクエスト側のルールが違います。

応答はこちらが読む側なので、追加されることだけが安全です。リクエストはこちらが送る側なので、方向が逆です。任意フィールドが増える、または必須が任意に緩和されることは、こちらにとって何でもありません。(where, kind)の組をキーにした表1つで十分で、知らない組は、安全な側ではなく、壊れると答えてください。

こちらが読むものだけを書いた契約

/root/contract/order.contract.jsonにコンシューマー契約を書いてください。versionは1.4、unknown_fieldsはignore、fieldsには、こちらが実際に読む5つのフィールド(order_id・amount・currency・status・market)だけを、それぞれtypeとrequiredで書きます。currency・status・marketには、enumも付けます。

パートナーが出力するフィールドをすべて書きたくなりますが、こちらが読まないフィールド(channel・updated_at)を書くと、相手がそのフィールドを変えるたびに、こちらのテストが赤信号を出します。型名はstring・integer・decimal_stringの3つで、1.4の金額は十進文字列です。statusの列挙値は、1.4の応答を全件調べて得てください。

契約と実際の応答を照合する

/root/contract/validate.pyを作成して、--contractと--recordsを受け取り、{"records": n, "ok": n, "violations": [...]}を出力するようにしてください。違反はmissing、type、enumの3つに分け、各違反にindexとfieldを付けます。

レコード1件に違反が2つあることもあるので、violationsはレコードごとに複数行になりえます。一方、okは違反が1つもないレコードの数なので、違反の行数を引く方式では出ません。必須でないフィールドがないことは違反ではなく、型がすでに間違っている値に、列挙をさらに照合しないでください。

旧バージョンと新バージョンを一緒に受け入れる

/root/contract/read_order.pyを作成して、--in <응답 파일>(プレースホルダーは応答ファイルです)で1.3と1.4の応答をどちらも読み、同じ内部の形に移してください。各レコードは、order_id、amount_krw(整数)、currency、status、marketの5つの欄で、知らないフィールドは捨てます。

名前が変わった箇所は別名表1つで、型が変わった箇所は正規化関数1つでまとめます。あちこちにifをばらまくと、旧バージョンを切るときに、どこを消せばよいかわからなくなります。金額はfloatを経由しないでください。"12300.00"は、ドットを基準に切って整数に移せば、丸めが生じません。

通知なしにまた動いたパートナーを検出する

/root/contract/contract_test.shを作成して、bash contract_test.sh <BASE_URL>で、パートナーの現在の/v1.4/ordersを契約と照合するようにしてください。違反がなければ0、あれば1で終了する必要があり、違反があるときは、何件かが画面に残る必要があります。

前に作ったvalidate.pyとorder.contract.jsonを、そのまま使います。新しく作るのは、応答を取得する部分と終了コードだけです。--driftで起動したパートナーに対して実行して1が出るか、通常のパートナーに対して実行して0が出るかを、両方確認してください。

バージョンアップ点検の報告書

/root/contract/contract_report.mdに、## 무엇이 바뀌었나、## 무엇이 우리를 깨뜨리나、## 우리가 지킬 계약、## 다음부터 어떻게 잡나(韓国語の見出しで、順に何が変わったか、何がこちらを壊すか、こちらが守る契約、次からどう検出するか、を意味します)の4つの節で書いてください。前のステップで得たフィールド名と違反件数が、本文に入っている必要があります。

読む人は、こちらのチーム長ではなく、パートナー企業の担当者かもしれません。「壊れた」ではなく、「どのフィールドがどう変わって、こちら側の何がずれたか」で書いてください。4つの節のタイトルはそのままにして、数字は、自分が得た値で埋めます。