新規プロダクトならではの悩み

福岡憲治氏(以下、福岡):それでは『新規プロダクトの開発速度と品質の両立を支える自動テスト』というタイトルで福岡が発表いたします。お願いします。

ではいきなりですが、まずはじめに、新規プロダクトとタイトルに入っているとおり、新規プロダクトならではの悩みについて、簡単にお話しできればと思います。

まず1つ目、ドメインに対する理解が不十分だったり、アジャイルに機能開発していくので、作り直しが発生します。あるいは、新規プロダクトである程度できあがってくると、チームメンバーを増員することになりますが、新メンバーに今の設計を浸透させるのはなかなか難しいですよね。あるいは、ユニットテストだけでは結合レベルの品質が不安なので、手動テストが減らないということもあるでしょう。

そういう悩みを抱えつつ、新規プロダクトにスピードはとても重要です。その中で品質を保ちつつ、開発速度を両立するためには、自動テストが不可欠であると考えています。

本日お話しする内容といたしましては、自動テストって何しているんですか? だったり、自動テストはどういうとき実際うれしいんですか? という2点をお伝えできればなと考えています。

本日の話の流れはこちらです。私は、楽楽労務という商材を担当していまして、それに対してプロダクトの概要、技術スタックを簡単にお話しします。

そのあとに、自動テストは何をやっているのかということと、それを行うことによってどういう恩恵、うれしいことがあるのか。そして最後にテストコードを書くというチーム文化がそもそもどうやってできあがったについて、4本立てでお話しできればと思っています。

楽楽労務の技術スタック

では1つ目、楽楽労務のプロダクト概要についてです。楽楽労務は、人事労務の方々の業務を効率化するサービスになっています。

技術スタックはどういうものを使っているかというお話です。フロントエンド、バックエンド、バッチですね。3つ書いています。

フロントエンドに関しては、Vue.js とVuetify.js、バックエンドに関してはDockerの上にSpring Boot、Doma、OpenJDKが動いている状態です。そしてバッチに関しても、Dockerの上にPythonが起動している構成をとっています。

またこちらは、開発のフロー図を示した図になっています。開発者がGitLab上にリポジトリにコミットすると、CIが動いて、AWS上でtestだったりbuildが走る構成を現在構築しています。開発者がGitLabにコミットするたびに、テストが裏で動く仕組みになっています。

開発フローの中に、自動テストを先ほどの図に示したように組み込んでいますが、実際にどういうテストを実施しているかという話に移りたいと思います。

ユニットテストの実施

3本柱でユニットテスト、アーキテクチャテスト、E2Eテストという3つを実施しています。それぞれ使用しているフレームワーク、ライブラリの名前を載せています。今回時間も限られているので、JUnit、ArchUnit、Puppeteerの3つに絞ってお話ししたいと思っています。

まずユニットテストですね。こちらはご存知の方が多いかなと思いますが、自分たちのチームではJUnitを使っていまして、Javaプログラムのメソッドレベルの入出力が期待通り動作しているかを確認しています。

こちら現状テストカバレッジが90パーセントを超え……超えていないかな。89.いくつだったかと思います。なので、ほぼほぼ実装コードに対してテストコードが存在している状況です。

それの何がうれしいんですか? というお話ですが。先ほど開発フローの中に、コミットするたびにテストが走るということを説明しましたが、マージリクエストを送った際に、レビューイ、レビューアともにGitLsb上で既存機能にデグレがないことを一目で確認できます。

デグレがないことで「今の機能に影響はないんだ。ちゃんと動いているね」という安心感をもてる。また既存機能は本当に壊れてないのかなって、「デグレの粗探し」という表現が正しいのかわからないですが、デグレを探す時間を削減できるといううれしさもあります。

最近、私が一番うれしいなと思ったのが、依存ライブラリを更新する際に、アプリケーションが壊れていないことを確認したときですね。例えばJavaの場合、JDK、Spring Bootに脆弱性が見つかって、アップデートしないといけないとなったときに、アップデートして本当に今のアプリケーションを維持できるのかは、なかなか不安なところもあります。

自分たちのチームでは、テストが通っていることで、ある一定の担保をしています。

アーキテクチャテストの実施

続きまして3つのうちの2つ目、アーキテクチャテストに移ります。アーキテクチャテストという表現自体、聞いたことがある方は少ないかと思うのですが。

ArchUnitというライブラリを使いまして、Javaアプリケーションのパッケージやクラスが設計方針に沿っているかを確認できます。どういうことかというと、具体的にこんな悩みが解決できます。

設計者の目線に立つと、当初作成した設計方針が納期優先だったり、メンバー増加によって、設計方針が浸透できずに、どんどん泥団子状態になります。開発者目線で言いますと、どのパッケージに今回作るクラスは置いたらいいんですか?って迷います。2つ挙げましたが、例えばこういう悩みを解決できます。

もう少し具体的な例でお話しします。右の図にインフラストラクチャ層、UI層、アプリケーション層、ドメイン層、それぞれパッケージが4つあると認識してもらえればいいと思います。

今回、ドメイン層のクラスはほかの層のクラスに依存しない。ドメイン層にあるクラスはほかのインフラストラクチャ層、UI、アプリケーションからは参照はできますが、逆にドメイン層からそれぞれの層には参照しませんというルールを設けていた場合、これをコードで縛ることができる。

これのなにがうれしいかと言いますと、パッケージやクラスの設計方針のレビューが自動化できます。こちらは設計者目線で言うと、ドキュメント作らなくていい、レビューで指摘をしなくていい、そういう時間を削減できる。

そして開発メンバーからすれば、テストが落ちたからこのクラスに置いたらダメだなと気づくことができます。

詳しく知りたい方については、同じチームの川並が別資料をSpeaker Deckにあげていますので、そちらを参照いただければと思います。

E2Eテストの実施

では3つ目、E2Eテストに移りたいと思います。まずこちらの用語、E2Eとは、について簡単に説明します。

フロントエンド、バックエンドを結合したエンドツーエンドの動作を、ブラウザ操作で確認する、人がブラウザ操作して確認していることを自動化するイメージですね。

自分たちのチームではPuppeteerというライブラリを使用して、自動化を行っています。

ハッピーパス、正常系についてはブラウザを経由した自動テストが動いていて、ユニットレベルではなく、バックエンド、フロントエンド、結合しても大丈夫なんだという安心感を得られるのが大きな特徴になります。

自動テストの恩恵

それぞれのテストの説明とうれしいことについてお話ししましたが、改めて、じゃあ恩恵って何ですか? という話に移ります。こちらは、最初に述べた新規プロダクトならではの悩みを再度表示しています。

そしてそれぞれについて見ていきますと、例えばドメインに対する理解だったり、アジャイルの機能開発で作り直しが発生するという悩みに関しては、今回自動テストを入れることによって既存機能のデグレをいち早く……こちらがすごく大きいキーワードで。いち早く検知して、メインブランチへのマージを防げる。これが大きいかなと思います。

またチーム増員の際、新メンバーにも設計指針を浸透させるのが難しい。2つ目の悩みについては、ArchUnitを使ったテストで、一定の強制力をもってアーキテクチャの設計品質も担保できる。

最後に3つ目、ユニットテストだけだと不安、結合レベルの品質が不安、手動テスト減らせないという悩みに関しても、E2Eテストを活用することで、エンドツーエンドでもアプリケーションが壊れていないことに、一定の安心感をもてます。

ここまでは感想というか、定性的な情報が多かったかと思いますが、数字でも見てみたいと思います。リリーススプリントの結果を分析しました。リリースプリントと書いていますが、リリース直前のテストやリリース準備の期間だと思ってもらえれば問題ないです。

そのリリーススプリントで実施している回帰テストですね。こちらの結果について載せています。言葉で表現しますと、回帰テストでバグが多く発見できました。ただ修正しなくてもリリースできる、主にUI面の軽微なバグがほとんどで。時間効率が悪いことが、分析して見れました。

自分たちのチームでは、リリーススプリントに、これまで1ヶ月半という期間を置いていたんですが。何回かな? 4回、5回ほどリリースを行った結果として、自動担保で一定の品質担保はできているという気づきを得ました。現在は、テストの実施方法を見直して1ヶ月にして、3分の2に短縮することをチャレンジしています。

テストコードを書く文化をどう形成していったか

では続きまして、今まではテストコードの話をしましたが、ではチームとしてテストコードを書こうという文化が、どういうふうにできあがったかという話に移りたいと思います。

書いているとおり読みます。プロジェクト立ち上げ時から、テストコードを書くことを前提として始めていたことがとても大きいです。現状としては、プロダクトの開発ガイドラインを定めていますが、そちらのほうでテストコードを書くのは当たり前。書かないとダメだというふうに縛っています。

いやいや、なんでそういうモチベーションになったんですか? という話になるかと思うんですが。モチベーションは何かというふうに改めて今回振り返ってみると、前身のチームのときからポジティブな印象が強かったというのがあります。一度やってみてよかった、なので続けようという意識が強かったということですね。

今の楽楽労務チームは、楽楽精算の開発に携わったものが多くその時代からテストコードを書いていました。結果としてデグレをテストフェーズに入るまでに、開発の上流の工程で早く検知できて、デグレがないことを即座に確認ができました。

その結果、単体・結合テストの前にバグが潰せます。またアプリが壊れてないという安心感が持てて、じゃあもっとテストコードを書こうよといういい循環になって。新しいプロダクトを立ち上げる際にも、テストコードは書く前提で進みましょうというふうに決意できたと経緯があります。

以上です。今回短い時間ですが、新規プロダクトの開発速度と品質の両立を支える自動テストについてお話しました。今振り返ると、自動テストがなかったと考えると、テストフェーズ、リリース前のテストで結合とかでバグ発生。

そのフェーズでバグが発生すると手戻りってけっこう発生するかと思うんですね。やったテストをもう1回やり直し、またバグが見つかった、もう1回テストやり直し。ってなると、リリースまでのスピードが結果的に落ちていたかもと思うことがあります。

できるところから始めるでも、ぜんぜん効果というのは大きいのかなと思っています。みなさんも自動テストを書いていきませんか? という投げかけで、福岡の発表を終わらせていただきます。ご清聴ありがとうございます。

質疑応答

司会者:ありがとうございます。新規プロダクトならではの自動テストがもりもりという感じでしたね。1つご質問が来ていますね。「私も職場でE2Eテストを作っていますが、不安定になってしまうのが悩ましいです。このへんの対策ってなにかされていますか?」とのことです。不安定というのは、テストが壊れるとかでしょうか。

福岡:壊れるというか、私たちは時間がタイムアウトになることがあってですね。待つ時間も一応コードとかで制限していて、いつまで待ってもレスポンス返ってこなかったら、E2Eのテストシナリオ自体落とします、みたいな。今うちのチームとして、思い当たるのはそれですね。

司会者:もともとご質問いただいた方の不安定というのは、実行が不安定という文脈でしょうか。Puppeteerって、時間を待つみたいな感じの指定になるんですか?

福岡:そうですね。この画面が表示されたら、次のボタンを探してクリックしにいくみたいな。

司会者:あーなるほど。そこのへんの挙動がけっこう、そのときのコンディションによって左右されたりすると、不安定になるんですね。

福岡:はい。

司会者:あ、今追加で「不安定というのは、手動で確認したらまったく問題ないのに自動テストだと失敗になったりする場合」と。

福岡:逆にそれは、Puppeteer側のコードを追って、どこで落ちているかを探していけそうですけどね。

司会者:福岡さんのプロダクトでは、あんまりそういうことは起きていない?

福岡:そうですね。タイムアウトが多いぐらいですね。どちらかと言うと。

司会者:なるほど。わかりました。ありがとうございました。