TL;DR
本記事は、「Winters, Titus, Tom Manshreck, and Hyrum Wright. Software engineering at google: Lessons learned from programming over time. O'Reilly Media, 2020.」の「Testing Overview」の内容を読んで特に重要だと感じた箇所を13個まとめました。
新卒の頃からこちらの内容を理解していれば、もっとテストや品質、生産性について考えられると感じたため記事にしました。
テストの品質を考える参考になれば幸いです。
1. 自信を持って変更を加えるためにテストがある
“catching bugs” is only part of the motivation. An equally important reason why you want to test your software is to support the ability to change. Whether you’re adding new features, doing a refactoring focused on code health, or undertaking a larger redesign, automated testing can quickly catch mistakes, and this makes it possible to change software with confidence.
テスト(特に自動化テスト)は、バグの早期発見をしてくれるのはもちろんですが、コードの変更を加える際にも重要だと記載があり、まさにその通りだと感じました。
自信を持って、問題ない変更を加えるためにテストがあるのです。
GWSの事例紹介に以下のような記載もされています。
Team members had little confidence when making changes to the service, and often found out something was wrong only when features stopped working in production.
2. 劣悪だと感じたテストを書くくらいなら書かない方がマシ
If testing becomes a productivity sink, constantly inducing toil and uncertainty, engineers will lose trust and begin to find workarounds. A bad test suite can be worse than no test suite at all.
テストが生産性を下げ、不確実性を増やすようなものであれば、エンジニアはテストを信頼しなくなり回避策を見つけ始めるという記載があります。
テストを書く際には、テストを書く覚悟が必要であり、劣悪なテストを書くくらいなら書かない方が良いと感じました。
3. 「後でテスト書くよ!」はありえない
At Google, we have determined that testing cannot be an afterthought. Focusing on quality and testing is part of how we do our jobs. We have learned, sometimes painfully, that failing to build quality into our products and services inevitably leads to bad outcomes. As a result, we have built testing into the heart of our engineering culture.
テストに注力するのは、クオリティ担保のためであり、利益につながることが記載されています。
私は機能開発をすることが楽しいと感じるときがありますが、その機能開発にテストを後回しにすることはできないと感じました。
4. どんなに優秀なエンジニアでもチームになればバグを起こす確率は無視できない
Even if each engineer writes only the occasional bug, after you have enough people working on the same project, you will be swamped by the ever-growing list of defects. Imagine a hypothetical 100-person team whose engineers are so good that they each write only a single bug a month. Collectively, this group of amazing engineers still produces five new bugs every workday. Worse yet, in a complex system, fixing one bug can often cause another, as engineers adapt to known bugs and code around them.
どんなにバグを引き起こす可能性が低いプログラマーを雇ったとしても、人数が増えればバグは起きやすくなると記載されています。
これはソフトウェアテストだけに関わらず、どんなに低い確率ても継続的なプロセスにおいてはその確率は大きくなることに注意したいと考えました。
5. テストをやる唯一の方法は自動化
When it comes to testing, there is one clear answer: automation.
上記の文言はGoogle検索について説明をされている箇所のため、到底手動でテストを行うことはできないと感じました。ただ、ある程度の規模である場合は自動化テストが必要であると感じました。
こちらは、Software Engineering at Googleには記載されている内容ではないですが、
[GS-1-2] 『質とスピード』特別編 〜 現代のソフトウェア開発にキャッチアップしていくヒント〜) | AWS Dev Day 2023 Tokyo #AWSDevDayの中で、自動化するか否かの損益分岐点についての話があり、4回という回数が挙げられていました。
Google検索のような規模であれば、それは自動化するしかないと感じました。
6. ソフトウェアのドキュメントは信じるな。テストを信じろ。
Software documentation is notoriously unreliable. From outdated requirements to missing edge cases, it is common for documentation to have a tenuous relationship to the code. Clear, focused tests that exercise one behavior at a time function as executable documentation.
ドキュメントが古いのはよくあることであり、テストが信頼できると記載があります。
個人的に他人のコードを読むのは少し苦手なため、公式ドキュメントやテストがあるのですが、今後は訓練も兼ねて他人が書いたテストコードを読んで仕様を理解することも重要だと感じました。
7. テストがしづらい?ならモジュラー化しろ
Writing tests for new code is a practical means of exercising the API design of the code itself. If new code is difficult to test, it is often because the code being tested has too many responsibilities or difficult-to-manage dependencies. Well-designed code should be modular, avoiding tight coupling and focusing on specific responsibilities.
ある新規機能を追加しようとする際にテストが難しい場合、そのコードが多くの責務を持っているか、管理が難しい依存関係を持っている可能性があると記載があります。
そのため、新規機能を追加するためにどういったモジュール化を行うかを考えることが重要だと感じました。
たまに、テストがしづらいと感じつつもリファクタをせずにそのまま進めてしまうことがあるため、今後はモジュール化を意識してコードを書いていきたいと感じました。
8. 確率によるバグを減らす努力をしろ
If test flakiness continues to grow, you will experience something much worse than lost productivity: a loss of confidence in the tests. It doesn’t take needing to investigate many flakes before a team loses trust in the test suite. After that happens, engineers will stop reacting to test failures, eliminating any value the test suite provided. Our experience suggests that as you approach 1% flakiness, the tests begin to lose value. At Google, our flaky rate hovers around 0.15%, which implies thousands of flakes every day. We fight hard to keep flakes in check, including actively investing engineering hours to fix them.
確率によって引き起こされるバグ(flake)が増えると、テストケースの価値が減少してきてしまい生産性が落ちる傾向にあるため、確率によるバグを減らす努力が必要だと記載があります。
具体的にどのように確率によるバグを減らすかについては、本書には記載がなかったため考えていきたいですが、確かに確率によって引き起こされるバグはテストケースの価値を減少させるため、その対策が必要だと感じました。
9. テストしたい対象について、最も重要な情報のみを含めろ
A test should contain only the information required to exercise the behavior in question. Keeping tests clear and simple aids reviewers in verifying that the code does what it says it does. Clear code also aids in diagnosing failure when they fail. We like to say that “a test should be obvious upon inspection.” Because there are no tests for the tests themselves, they require manual review as an important check on correctness. As a corollary to this, we also strongly discourage the use of control flow statements like conditionals and loops in a test. More complex test flows risk containing bugs themselves and make it more difficult to determine the cause of a test failure.
テスト対象に必要なものだけを書くことで、レビュワーがコードが期待通りに動作しているかを確認しやすくなると記載があります。
私自信、たまにあれもこれもと思いついたものを同じテストの中にに書いてしまうことがあるため、今後はテスト対象に必要なものだけを書くことを意識していきたいと感じました。
Code is read far more than it is written, so make sure you write the test you’d like to read!
10. 単体テストでカバーするべきか、統合テストでカバーするべきかを考えろ
Googleは、下の図のように迅速にテストを行うために、単体テストを多めに書くことを推奨していました。
一方で、以下のような記載があります。
Our recommended mix of tests is determined by our two primary goals: engineering productivity and product confidence.
When considering your own mix, you might want a different balance.
A good test suite contains a blend of different test sizes and scopes that are appropriate to the local architectural and organizational realities.
つまり、組織やアーキテクチャによって単体テストと統合テストのバランスが変わるため、それぞれが生産性を重視するのか、製品の信頼性を重視するのかを考えてテストを書くべきだと感じました。
11. テストを書くべきかどうか迷ったときには、テストをしろ
We are often asked, when coaching new hires, which behaviors or properties actually need to be tested? The straightforward answer is: test everything that you don’t want to break.
We have a name for this general philosophy: we call it the Beyoncé Rule. Succinctly, it can be stated as follows: “If you liked it, then you shoulda put a test on it.”
テストを書くべきかどうか迷ったときには、壊したくないかどうかを考えると良いと記載があり、哲学的に「好きならテストをすればいいじゃないか」という記載があります。
そのため、気になった箇所はくまなくテストを書くことが重要だと感じました。
12. コードカバレッジは表面的だから気をつけな
That’s because code coverage only measures that a line was invoked, not what happened as a result. (We recommend only measuring coverage from small tests to avoid coverage inflation that occurs when executing larger tests.)
An even more insidious problem with code coverage is that, like other metrics, it quickly becomes a goal unto itself.
A better way to approach the quality of your test suite is to think about the behaviors that are tested. Do you have confidence that everything your customers expect to work will work? Do you feel confident you can catch breaking changes in your dependencies? Are your tests stable and reliable? Questions like these are a more holistic way to think about a test suite.
コードカバレッジは、油断ならないことに定量化しやすいので気をつける必要があり、よりよいテストケースの作成方法として、根本的な問いを立てながらテストケースを考えることが重要と記載がありました。
そのため、単にテストの品質を定量化をするのではなく、テスト設計を頭を使って考えることが重要だと感じました。また、それは後の開発メンバーからも追従可能な形で残しておき、どれだけ考えられているテストかわかるとより良いとも感じました。
13. Googleはモノリポ
most of Google’s code is kept in a single, monolithic repository (monorepo). Almost every line of code for every product and service we operate is all stored in one place. We have more than two billion lines of code in the repository today.
Google’s codebase experiences close to 25 million lines of change every week.
えっと、、、すごいですね。モノリポであるGoogleのコードベースは、週に約2500万行の変更があると記載があります。
また、モノリポであることによるメリットとして、以下のような記載があります。
The openness of our codebase encourages a level of co-ownership that lets everyone take responsibility for the codebase. One benefit of such openness is the ability to directly fix bugs in a product or service you use (subject to approval, of course) instead of complaining about it.
コードに対して文句を言う前に、自分で修正することができるため、コードベースの共有ができることがモノリポのメリットだとも記載があります。
この規模のリポジトリを私は見たことが無いため、想像できないのですが、知らない世界があるなと度肝を抜かれました。
感想
Googleのソフトウェアエンジニアリングにおけるテストの考え方について学ぶことができ、非常に勉強になりました。
心の何処かで、テストを書くのが面倒だと感じることが多かったのですが、テストを書くことの重要性を再認識することができ、テストを書くモチベーションを上げることができました。