EmotionTechテックブログ

株式会社Emotion Techのプロダクト開発部のメンバーが、日々の取り組みや技術的なことを発信していくブログです。

フロントエンドから語るテストの意義と向き合い方

f:id:emotion-tech:20210310132321p:plain

はじめに

こんにちは、エンジニアのねだです。 主にフロントエンドの開発を行わせていただいてます。
弊社では顧客体験や従業員体験を改善するためのソリューションを提供するクラウドサービスEmotionTech CX・EmotionTech EXを提供しています。 機能追加を行いながらおかげさまで様々なお客様に使っていただけるようになっています。

弊社のフロントエンド環境はURLによって配信するアンケート画面と、ダッシュボードと呼ばれるアンケートを配信したり、収集したアンケートを解析する画面によって構成されます。そして、そのどちらもフレームワークとしてAngularを使用しています。

現状、フロントエンド側の動作を保証しているものは正常系を保証するE2E(End to End)Testテストだけになってしまっています。
そのためユニットテストや不足するテストの拡充など、不足していたフロントエンドのテストの設定について取り掛かっており、改めて考えてみたテストの意義について書きたいと思います。
テストというものについて日和見的な立場の方や、つい荒めのテストを書いてしまうような方に有益な内容になればと思います。

EmotionTechのテスト事情

私がプロダクトにjoinした時、どうやら過去の経緯から、EmotionTechのプロダクトはv1と呼ばれる不十分な機能で構成されるプロダクトから必要な要件はとりあえず満たしているv2への移行が行われ、半年程が経過した後でした。
会社で使用しているesaという情報共有サービスには当時のポエムや断片的なテキストが一部残されており、そこからは仕様面の混迷により、実装が後ろ倒しになり、色々と混迷を極めたことが推察されました。
後に耳に入ってきた状況から推察するに、仕様の詰めが不十分な状態で開始し、仕様をエスパーしながらの実装が行われ、修正を行いながら開発が進められていたようです。
話を聞くに、実装者の方々はかなりの推察力を有しておられていたようです。
ただし、あまり推察ベースで開発を行うと、エンジニアの能力だったり、現実的な実装可能性だったり、人の能力の限界を超えてきます。そこには代償が伴います。

具体的に言うと開発者の精神力とテストが犠牲になります。

そして初期開発が短納期で仕様が混迷している際、開発促進のためスポットでエース人員が投入されることが多く、運用フェーズに入ったのちまでその人達が居付くことは少ないように思います。今回もそのケースでした。
一度テストの追加が行われなかったプロジェクトでは、機能追加や修正に追われ、テストの追加がなかなか与えらない状況が発生する、というのも常だと思います。そしてそれは少しずつですが、確実に負債として積み上がっていきます。
諸々の事情で前任者からの引き継ぎが不十分であったこともあり、結果として半端な状態のE2ETestが最低限未満のサービスの動作だけを保証し、unit テストがまともにないままに時間が過ぎていきました。

私がjoinする以前から、記述に実装者によるブレがあったり、特定のコンポーネントが極端に肥大化したり、安易なDRYによってコンポーネントの再利用が一部破綻したり、といった記述があるにもかかわらず、場当たり的な記述の修正も混在し、修正の手をつけにくい状態が続いてきました。
その状況が放置されてきたことの責任の一端は私にもあります。

いよいよバグの対応コストも少しずつ増加傾向にあり、テストやリファクタリングなどの、既存リソースの整備に対する機運が高まってきました。(人員の都合もあり、サーバーサイドのテストの充実化や整備は少しずつですが進みつつあったこともありますが)フロントエンド側でもその機運が高まりつつありました。

テストが無いことの何が問題なのか?

もともと私自身、テストがあると言うことが心理的安全性を担保することは理解できていましたが、テストの重要性をなんとなくでしか理解できていない気がしていました。

最近のマイブームに物事の定義を明確にする、と言うのがあり、以前に読んだものも含め、何冊か本を読みながら考えてみました。
特にClean Coderでは筆者はテストのカバレッジは必ず100%にしろ!と口を酸っぱくして書いていたのが印象的でした。

テストが無い、と言うのは何が問題なのでしょうか?

現在の理解としては以下になります。

  • コードの理解が十分できないと正しい修正を行えない
  • 修正箇所の衝突の際の心理的安全性
  • リファクタリングの際に都度動作を確認する必要があり、効率的ではない
  • 実装者が動作を保証する方法に関する問題
  • 動作の保証がQA任せになる

当たり前だろ!と思った方も多いと思います。それがもたらすものは小さくないと思います。以下に記載します。

  • コードの理解が十分できないと正しい修正を行えない

コードを追うのにはある程度以上の時間が必要ですが、基本的に現場にjoinした直後から軽い修正をすることになりがちです。実装は単一責任の原則が保持されているべきですが、それでもコードの規模によって配慮しなければいけない要素は増加します。
時間を空けて見た自分のコードは他人が書いたコードのようなものだ、と言うのはよく言われる話ですが、コード作成時の意図や考えなどはコードやコメントを振り返る必要があります。
十分なテストがあれば確認時のスコープがテストシナリオによって保障された状態で、最低限のコード確認でjoinして間もない人も対応でき、何年も前のコードも安心して修正を行うことができます。

  • 修正箇所の衝突の際の心理的安全性

複数の人々が近い箇所の修正を行う場合でも、テストが整備されていればテストの動作が保障する限りにおいて、直接の記述自体が衝突しない限りは一定の動作が保障されますし、直接的に被害が出る記述の衝突箇所にすぐ辿り着くことができます。

リファクタリングは「コンピュータプログラミングにおいて、プログラムの外部から見た動作を変えずにソースコードの内部構造を整理することである。」と言われます。リファクタリングを行う際にもテストは一定の動作を保障し続けてくれます。そのことは心理的安全の向上に大きく向上します。非効率的な記述や不味い構造と思われるものが見つかった際に、記述を修正してもテストが正しい振る舞いを保証するのであれば、安心して修正することができます。テストが無い状態でのリファクタリング作業は、テストがある状況では不要な覚悟をどこかで実装者に強いてきます。

  • 実装者が動作を保証する方法に関する問題

テストの無い状態で、プロダクトの振る舞いを別のエンジニアに伝えるにはドキュメントやコメントに頼ることになります。ですが、ドキュメントやコメントはコードの修正と同時に更新されるわけではないため、差分を生みやすい面があります。(自動ドキュメントツール等はありますが、それは実装者が内容を保証するわけではないため、ある程度の頻度で確認しておかないと、想定を外れた振る舞いをするケースがあります。その意味においてこれらの自動化ツールも差分を生む、と言えると思います。)
テストを利用する場合、開発ルールとして自動テストが通ったことをリリースの前提として決めれば差分を生みませんし、適切に記述されたテストは動くドキュメントとしてプロダクトの機能を保証してくれます。

  • 動作の保証がQA任せになる

テストの無い状態は、QAへの確認依頼を行う前に画面などで動作を十分に確認するようにしていたとしても、確認の粒度は対応の緊急性や割り込みタスクの状況によってムラが生じてしまいがちです。そうなるとQAに負担が行き、発見するバグの粒度が荒くなり、単純なバグの確認対応により、細部のバグが見落とされるリスクが存在します。テストがあれば、実装者側の動作保証が最低限担保されるので、QAの確認の質にもつながります。

テストの意義

テストに対する意見は、両極を見ると「カバレッジ100%であるべき」「そんなものにかまけている時間はない」などといった意見をはじめ、様々な意見を見かけます。
私個人の考えとしては、どちらも間違ってはいないのだと思います。

ですが、そこには前提が必要だと思います。「製品として機能を保証するものがテストである」ということです。
ソフトウェアにおいては製品であることと、問題を解決することはイコールではないことがしばしばあります。問題を解決することが製品たりうることよりも重要な初期の段階においてはとにかく動くコードを書かないと費用対効果が得られず、計画自体が消失してしまうことがあり得ます。
実装開始時点での仕様の検討が不十分で何を作るべきか不明なまま実装が行われている場合にも、変更が頻発するので都度テストを変更していると工数が肥大化するわりに得られるメリットが少ないので、優先度がかなり下がります。 書いて捨てるコードや、一生アップデートしないコードについてもテストを記述するほどではない、という状況はあり得ると思います。
これらの状況では顕著に時間>製品の品質となり、テストが軽視される状況が許容されうると思います。

ですが、それは言い方を変えれば、未来の工数の前借りです。
テストが無くても良い、と言う話ではなく、テストが無いコードで動作するものは本当の意味では製品とは言えないのだと思います。

プロダクト規模とテストの関係

以上の前提を考えると製品である、ということとテストの粒度は、プロダクト規模と価値を生んでいる期間、関わっている人が多くなればなるほど意味合いが大きくなるのではないか?という仮定ができると思います。
Angularのテスト手法のインプットを兼ねて、github上でスター数の多いプロジェクトを確認して見ましたが、テストがあまりしっかりと書かれていないプロダクトも少なくはありませんでしたが、仮定通りにプロダクト規模と価値を生んでいる期間、関わっている人が大きく、バージョンが進んだプロジェクトに関してはしっかりとテストが記述されたものが多かったです。

現在動いてるテストのないプロジェクトとの向き合い方

テストがあまり揃っていないプロジェクトにテストを追加していく作業は、昏い洞窟の中に灯りを灯していく作業に似ています。
コード読み解くことから実装者の考えを推察することは可能ですが、結論が本当に実装者の思考とイコールであるのかはわかりません。
実装者がテストを追加していく作業は、どのように振る舞うかを実装者の目線で残し、後に続く人にもその意図を伝達することができます。
灯りに灯された世界は一定の心理的安全性が確保され、リファクタリングや修正も比較的容易に行うことができます。

この結論に至った時、私の意識には「UNIXという考え方」という書籍で紹介されていた、第3のプロジェクトという概念が頭に浮かびました。
この概念はある種の経験則であり、第1のプロジェクトは、最低限の機能が作られ、それが人々の想像力を刺激し、やがて第2のプロジェクトが作られるが、それは多くの場合贅肉がついて効率的なものではなく、そこで火傷をした人々が作った第3のプロジェクトが本当の価値を提供できるものであり、できるだけ早く第3のプロジェクトを目指すべきだ、という考え方です。
現実的には第3のプロジェクトに至った後にも、機能の追加や改善は求められますし、必要な提供価値も少しずつ変わってきます。

そのため、プロジェクト全体で見た場合にも、単体の機能で見た場合にも、より早い第3のプロジェクトへの移行が、ビジネス的にも成功の可能性を高めてくれるのでは無いでしょうか?コードのテストが十分にあることは、エンジニア側にとってもその変化を望む気持ちを後押ししてくれます。

さいごに

さて、ところどころで話が脱線気味だった気もしますが、あなたはあなたの書いたコードを永続的に保守・運用できるわけではありませんし、そのコードに対して責任を持って向かい合うことができる期間は限られています。あなたが書いているコードの責任を取れる間にテストを書きましょう。それは未来のあなたのステークホルダーの価値やあなた自身の価値を高めるのに資する行為だと思います。
テストを書きましょう。

私も書きます。

λ.....

Emotion Techでは顧客体験、従業員体験の改善をサポートし、世の中の体験を変えるプロダクトを開発しています。新しい価値の提供に興味がある方ばかりでなく、既存のコードや環境の改善について関心の深い方も歓迎します。イキイキと働けるチームでプロダクトをより良くしていきたい方がいらっしゃいましたら、ぜひ採用ページからご応募をお願いいたします。

www.wantedly.com

名前を出した書籍など

  • CleanCoder
    Clean Architectureに比べると人を選ぶ内容であるし、やや筆者の自分語りが過ぎる部分があるようにも思いましたが、テストを重視した開発について考えている時に手に取る本としては役に立つ部分があるかもしれません。(web開発の実運用でここまで行うことができるところはそれほど多くは無さそうだとは思いましたが……)
  • UNIXという考え方
    20年以上前に出版され改訂も無いまま20版以上印刷された書籍です。流石に古さを感じる部分もあるものの、考え方という意味では今にも通じる部分も多いと思われます。150ページも無い割には人によっては有益に感じられる書籍だと思います。

ちゅうど本文記述時に開発者向けのテストについてまとめている方がいたのでリンク