前回までは、開発組織や採用の話をしていたので、今回は気分をかえて少し技術よりの話をしてみようかと思います。
今回のお話
AITravelはビジネスに影響が大きい機能については、E2Eテストを真面目に書いています。その結果、CircleCI 上で7コンテナを利用しても、テストが完了するまでに、30分もかかるようになってしまいました。 今回はそれに我々が立ち向かっていくお話をしようかと思います。
ちなみにまだ問題は解決はしていませんが、ステップを引いて取り組んでいるのでそれのご紹介をします。
AITravelの機能開発後からリリースまでのフロー
AITravel はざっくりいうと開発者の開発完了からリリースまでに下記のフローをとっています。 ざっくりなので、厳密には違います。ただ、イメージは伝わるはず。
- プルリクエストをレビュアがレビューする。
- レビュアがアクセプトしたら、masterの差分を開発者のブランチに取り込み、ステージ環境にデプロイする。(ここでCI上で自動テストが走る)
- QAが受け入れテストをする。
- masterにマージ→リリース
大きな機能追加をたまに行うときはこのフローで十分なのですが、小さな機能改善を細かくリリースしたいときに、テストの待ち時間が多く、とてもストレスフルな状態になってしまいました。 せっかく自動なのに、毎回リリース作業で、30分ほど無為な時間があるのはちょっとつらいです。
また、WIPのプルリクエストをpushした際も自動テストがCircleCI上で実行されます。開発者による普段の開発という観点から見ても、テストの結果がわかるまでに時間がかかるために、落ちるなら早く教えてくれよ!って感じになってしまい、その観点からも精神衛生上あまりよろしくない状態になってしまいました。
初めは素晴らしい仕組みだった
我々のサービスの大きな価値の一つに、ユーザが出張の手配作業を簡単にできるようにするという点がありますが、それを担保するために様々な条件のテストが書かれています。 ユーザの環境を可能な限り再現したいため、E2Eでのテストが主流になっています。ユーザに近いレイヤでテストができるのは安心感もあり、初めはそれで良かったのです。
サービスが成長するにつれて暗雲がただよってきた
開発あるあるですが、初めは片道・往復だけであった出張の予約パターンも、複数の拠点を任意の個数追加できるような仕様の追加であったり、旅行のパッケージサービスの追加など、どんどん要件が追加され、機能が増えていきました。
そしてテストコンディションは膨れ上がっていったのです。
さてどうする
3つのステップでテスト時間を短縮化する構想を立てました
- ロジックのテスト、特にモデル層周りのテストを増やす。
- 必要最低限のE2Eテストを作り、リリースフローに入れる。
- 既存のE2Eテストは開発、リリースフロー上では実行させず、非同期で実行させる。
ロジックのテスト、特にモデル周りのテストを増やす
そもそもなんで、そんなにE2Eのテストケースが多いかというと、ロジックをほとんどすべてE2Eでテストしていたからでした。そのため、可能な限りロジックやモデル周りのテストでケースの爆発を抑え、E2Eは本当に最低限の掛け合わせだけ行うようにするという意思決定をしました。
そして、油断するとテストは誰しも書かなくなるので、コードを書き足してpushした際に、CI上でテストコードがカバーしていない部分のモデル周りにコードの差分が発生した場合は、テストが失敗するような仕組みを入れました。
もちろんどうしてもテストがしにくい部分というものはあるので、そこについては、指定したコメントを挟むとテストが書かれていなくてもテストが通る仕組みをつくりました。 ただし、レビューアがOKを出さない限りは、原則許容しないという運用でカバーすることにすることで乱発を抑える努力をすることにしました。
運用して2ヶ月ちょっと経つのですが、今までモデルのテストはあまり書かれなかったのですが、急に書かれるようになって効果を実感しています笑 一方、テストのチェックをスルーするためのコメントが増えてきており、おやおや?というところもあります。
まだまだな部分も多くあるのでこれからも引き続き打ち手を考えていきたいです。
必要最低限のE2Eテストを作り、リリースフローに入れる
ロジック、モデル周りのテストが増えてきたら、さじ加減が難しいですが、ざっと主要業務の機能テストするという目的でE2Eテストを薄く書いていく予定です。 必要最低限ってなんやねんという話はありますが、一旦「2条件の掛け合わせ以上のテストケースは行わない」という決めでいこうと考えています。
より具体的には、スプレッドシートで直行表を作って自動でテストコンディションを作れるようにしているので、それを使うだけな感じになります。 3条件以上の掛け合わせだと使うのが厳しいのですが、今回の上記の決めにより運良く使えそうです笑
これで、並列7コンテナで30分にはならないであろう。
既存のE2Eテストは開発、リリースフロー上では実行させず、非同期で実行させる
既存のテストを捨てるのはやはりもったいないのと、この防御壁があったため大きな事故なく今まで開発出来てきたのは紛れもない事実なので、うまく資産として使っていこうと思いました。
そのためただただ捨てるという手は取らずに有効活用していくことにしようと考えています。具体的には、本番環境に新しい機能がリリースされたことを検知し、別の環境でマスタのブランチをもとにサービスを自動でデプロイ→既存のE2Eテストを実行するという仕組みを構築します。
もちろんこのテストが実行されるまでに機能のリリースは完了してしまうので、ここでバグが見つかると辛いのですが、検知できるという意味では非常に意味があると考えています。
リリースまでの時間の短縮化とのバランスをとる形の対応と捉えています。
最後に
論理的に漏れダブりのないテストを行っていくのも大事と思いながらも、現実世界で限られた時間ですばやくユーザに価値を提供するためには、ラインを見極めながら今回みたいな対応を進めていくことが大切だなと考えています。これで開発スピードがより上がって欲しい。。!
ちなみに、実際のモデルのカバレッジチェックを用いたテストの仕組みはyokomotodさんに作っていただきました。ざっくりとした構想を伝えただけでサクッと作ってくださったので、大変助かりました。
この場を借りてお礼をお伝えしたいと思います!ありがとうございます。