コンピュータシステムの学習の一環として『コンピュータシステムの理論と実装』 (通称Nand to Tetris project) を進めているのだが、Nand to Tetrisの課題ではハードウェア記述言語を使ってハードウェアをコードとして表現し、あくまでエミュレータ上で回路を実行するので現実のハードウェアに関するイメージがリアルに湧かなかった。
Sedgewick先生が赤黒木の論文を書いたのが1979年、大学の講義で赤黒木を扱う中で2007年にさらに改良された実装を見つけたという話と、"there are simple algorithms still out there waiting to be discovered and this is one of them that we're going to talk about." という言葉はグッときた。
赤黒木の代償として実装が複雑という話が出てきており、これはSedgewick先生がCourseraの講座でも言っていたことを思い出した。特に2008年のLeft-Leaning Red Black Treeの発表以前、とあるデータベースプロバイダが赤黒木の削除の実装を誤ったために障害を起こしたという話。(木の高さを常に一定に保つことが保証されていないHibbard deletionを採用したので木の高さが高くなりすぎ、再構築のためにシステムダウンするほどだった)
committeeにはrequest validation, coercion, test assertion, stub機能などありますが同プロジェクトで使った機能はCommittee::Middleware::ResponseValidationのみです。これは名前の通りRack middlewareであり、アプリケーション(この場合は我々が提供するAPI server)のレスポンスを検証します。
test assertionをすべてのテストに都度書いていくのは面倒なため、API定義が書かれているすべてのエンドポイントについて自動的に検証を走らせるようにしています。OpenAPIによる定義が書かれていない場合は検証は行われません。
# config/environments/test.rbRails.application.configure do
config.middleware.use(Committee::Middleware::ResponseValidation, schema_path: Rails.root.join("openapi/index.yaml"), raise: true)
end
1) #GET /:language/api/users/:idFailure/Error: subject { get "/ja/api/users/#{user.id}" }
Committee::InvalidResponse:
trueclass is TrueClass but it's not valid integer in #/components/schemas/User/properties/is_teacher # ./spec/requests/api/users_spec.rb:160:in `block (3 levels) in <top (required)>'# ------------------# --- Caused by: ---# OpenAPIParser::ValidateError:# true class is TrueClass but it's not valid integer in #/components/schemas/User/properties/is_teacher# ./spec/requests/api/users_spec.rb:160:in `block (3 levels) in <top (required)>'
これでテスト実行時にOpen API specificationと実装の乖離に気づけるようになりました。
…本当でしょうか?
実はこの検証だけでは実装との乖離を完全に防ぐことはできません。用意されたテストデータに対してしかテストを行っていないためです。たとえば上記コードでは user というテストデータを生成してそのデータに基づいてレスポンスを返すAPIを検証していますが、もしこのデータが変わったとしてもAPIが定義通りに動くことは保証しません。開発者が想定した正常系ド真ん中のテストデータによってしか動かない可能性もあります。