コードを修正してプルリクエストを作成したが、テストが失敗したことを見て、私が見逃した部分を探して修正する経験をし、テストの価値を実感することができた。私たちのチームはKPIとしてカバレッジを設定する。業務時間の2割はテスト作成、ビルドタイム改善、モジュール化などの技術課題に割り当てる。テストコードを作成して維持する経験を通して感じたことがある。

より良いアーキテクチャを追求する

テストが難しいコードは悪い構造である可能性が非常に高い。テスト可能なコードは、依存性への工夫が反映されている。特に依存性逆転の原則を徹底的に守りながら、ソースコードの依存関係を整理して管理する必要があるが、これに関しては、ロバート・マーティンが依存性規則(dependency rule)を通じてよく説明している。

自分のコードのドッグフーディング(dogfooding)

テストを作成すると、自分が作成したコードをユーザーの立場で直接体験することができる。まるで家を建てる過程で、内部を飾る途中で外に出て、外部からはどのように見えるかを確認することと同じである。窓はどのように見えるか、ドアはどのように開くか、入り口はどこにあるのかなど。窓と入り口はpublic APIに該当する。家の内部はprivateの要素だ。テストでオブジェクトの動作を確認する時は、public APIを使う。オブジェクトを直接生成してみて、設定をしてpublicメソッドを呼び出したり、プロパティにアクセスしてみる。その中で自分が作ったコードの使いやすさを確認することができる。APIが適当になっていると、テストを作成するのも面倒で大変である。「こんなことまでテストする必要があるのか」または「このケースはなぜこんなにテストするのが難しいのか」など、様々な状況に直面する。したがって、APIの使い勝手に気を使うしかなく、気にしてみると、よりシンプルかつ直観的なAPIを作るようになる。もっとシンプルなことには様々な意味があるが、私の考えにはpublicメソッドやプロパティの個数が少ないのが何よりも重要だと思う。

シンプルで直観的なAPI設計

機能開発 → テスト作成 → 機能修正 → テスト修正の過程を繰り返すと、APIを作る際に設計段階であらかじめ大きな絵を描くことができる筋肉ができるようだ。例えば、少し機能を修正すると、既存のテストを全て廃棄して最初から書き直す時が発生する。この場合、設計が最初から良くなかった可能性が高い。簡単に変わらない政策的なものをpublicに公開し、詳細の実装部は隠すか外部に移さなければならない。設計が間違っているとテストを作成することが不可能だったり、どうにかなっても維持するのが難しい。このようなことが繰り返されると、オブジェクトの構造や役割、テスタビリティを考慮するしかない。何をこのオブジェクトの中に入れるべきか、何を除去すべきか、依存性をどのように調整すべきか悩ませる。どのようにコードを設計すべきかどうか、どのパターンがより良いものかを判断するのが難しい場合は、テストコードを基準にするのも良い選択だ。

意味のあるテストを作成して維持できるように、チームの能力を高める

残念ながら、ある日突然テストコードが作成できるようになるわけではない。テストを作成できるコード構造と環境が整っている必要がある。したがって、テストを作成できるアーキテクチャを導入し維持する必要がある。AppleのMVCはテストを作成するのが難しい。UIを作成しないとユーザーアクションイベントを発生させることができないという問題点がある。また、ビューコントローラはライフサイクル関連のメソッドが複雑で、個数が多いのでテストが難しい。そして依存性を注入することさえも簡単ではない。そのため、MVVM、VIPER、RIBsなどのアーキテクチャが生まれた。しかし、アーキテクチャを導入しても終わりではない。 アーキテクチャは銀の弾丸ではないため、導入してもチームが置かれた状況と直面した問題によって絶えず変形する。そのため、時間が経ってもテストが可能で、テストを作成するのが難しくなく面白い構造を維持する技術的なリーダーシップが重要だ。また、テストを作成するのが難しくならず生産性が低下しない環境を構築し、適切なツールを導入・作成するチームワークも重要だ。