DeNA Testing Blog (original) (raw)
こんにちは、SWETの伊藤(@akito0107)です。
SWETが所属する品質管理部では開発プロセスや検証プロセスなどの業務をProcess Flow Diagram(PFD)を使って可視化し、 チーム全体の認識合わせや業務効率化に活用しています。
この記事ではPFDそのものやPFDを用いた業務可視化の実例を紹介します。 その後、SWETで開発しているPFDを記述するためのツール、PFD Draw Toolを紹介します。
PFD(Process Flow Diagram)とは
PFDとは清水吉男氏がDFD(Data Flow Diagram)を基にして、人が行う作業に使えるようにアレンジしたものです[1]。
PFDでは開発プロセスや検証プロセスなどの業務プロセスを、成果物とプロセス(1つ以上の成果物を受け取って異なる成果物へ変換する操作)に注目して可視化します。
ここでは具体例を用いつつ、PFDの書き方と構成要素について説明をします。
注:ここからの説明は、DeNAの品質管理部で用いているPFDの説明になります。オリジナルのものとは一部表現が異なっています。
下にソフトウェア開発のプロセスの例をPFDで記述しました[2]。 このPFDでは、初期成果物の要求(=ソフトウェアで実現したいこと)から始まり、仕様策定、設計、実装を経て最終成果物のソフトウェアまで至る様子が表現されています。
図1: 開発プロセスのPFDの例
図1: 開発プロセスのPFDの例
PFDの構成要素の説明をします。 図1を見て分かるとおり、PFDには次の4つの構成要素があります。
要素 | 画像 | 説明 |
---|---|---|
成果物 | 成果物 | プロセスの入力または出力となる具体的なものを表し、四角で示します。成果物ごとに一意のIDが付与されます。 |
プロセス | プロセス | 入力を出力に変換する作業または操作を表し、丸で示します。作業は手動で行われることもあるし、自動で実行されることもあります。プロセスごとに一意のIDが付与されます。入出力がないプロセスは存在しません。 |
矢印 | 矢印 | 成果物とプロセスの依存関係を表現します。 |
点線矢印 | 点線矢印 | 初回の実行では入力がないことを示し、成果物からプロセスに向けて使用されます。 |
PFDでは成果物やプロセスの依存関係を矢印で表現します。 たとえば、図1のP3はA2、A3に依存していますし、A3はP2に依存しています。これはP3を開始するためにはA2、A3の成果物が揃っていることが前提条件となることを表しています。
また、品質管理部では、メインとなる図に加え、成果物・プロセスそれぞれに要素表を用意しています[3]。 要素表とはPFDに書き切れない詳細な説明を記載する表で、 たとえば図1のPFDに対応する成果物の要素表は下のようになります。
ID | 名前 | 概要 |
---|---|---|
A1 | 要求 | PRDとして企画側から提供されるもの |
A2 | 仕様 | 画面の動作イメージおよび制約事項などが記載されているドキュメント |
A3 | 設計ドキュメント | API定義、シーケンス図、状態遷移図、DB設計を含んだドキュメント |
A4 | ソフトウェア | ビルド済みで実行可能な状態のソフトウェア。スモークテストを完了させておく。 |
A5 | 実装中に見つかった設計のミス | 実装の過程で見つかった設計のミスもしくは改善点。ドキュメントに反映させ、その後実装を修正する。 |
成果物の定義を詳細に書き下すことにより、成果物についての認識のずれが発生していないかを確かめることができます。 たとえば、A3はAPI定義、シーケンス図、状態遷移図、DB設計を含んだドキュメント
と定義しています。 今回は例示のため簡単に書いていますが、 定義や成果物の完了条件などをあらかじめ明確にして作業者間で認識をそろえておくことにより、いざ実際に開発を進めた際にドキュメントの作成漏れや作業の漏れを防ぐことができます (なお、プロセスについても同様に要素表を作成します)。
より詳細なPFDの記述方法に興味がある方は[1]等を参照してください。
PFDのメリット
さて、PFDの大まかなルールと記法がわかったところで、PFDのメリットを考えてみましょう。
業務プロセスを可視化すること自体の有用性はさまざまな場所で語られていますが、改めて整理します。 特に次の2つが挙げられます。
- 業務の流れを誰でも把握できるようにする。
- 業務改善の土台になる。
たとえば、1については新任者がチームに入ってきたときの立ち上がりや、チーム内で認識を揃えるのに必要な要素です。 2について、それぞれの作業がどう繋がってるのかを観察することにより、業務の冗長性を排除したり、品質に問題がある作業をあぶり出して改善作業を行うことができます。
業務プロセスの可視化は、PFD以外にフローチャートやバリューストリームマッピングなど、さまざまな手法が存在しています。 それらに比べると、PFDは成果物に注目する、という特徴があります。
たとえばフローチャートでは業務の手続きに注目し、それらのアウトプットである「成果物」は省略して記述されます。 上の図1をフローチャートで書くと次のようになります。
フローチャートの例
PFDで書く場合に比べ、簡潔に記述できてはいますが、作業の順番は理解できてもそれらの関連性についての情報は希薄になっています。
いざ実行してみると、作業のゴールイメージがずれていたり、成果物不足で作業同士がつながらなかったりといったことがよくあります。 プログラマーの方でしたらプロセスの『型』を明記する、といった方が伝わりやすいかもしれませんが、 PFDではプロセスだけではなく成果物に注目することにより作業の目的とそれらの関係をより明確にでき、 プロセスの実行時の不確実性の排除やチーム内外との認識齟齬を防ぐのに役立ちます。
PFDのSWETでの活用方法
PFDの一般的な説明をしたところで、SWETで活用しているPFDの具体例をいくつか紹介しようと思います。
例1: レビュープロセス
SWETの業務として、プロダクトコードのレビューがあります。 ここでのコードレビューの目的は、不具合の可能性を早期に発見するということももちろんあるのですが、 SWETメンバーのテストや対象のプログラミング言語についてのノウハウをレビューを通じて、実装者(レビュイー)に対して伝達することにあります。
SWETで行われるレビューのプロセスは次のようになります。
図2: レビュープロセスのPFD
図2: レビュープロセスのPFD
ここで注目するのは、成果物としてA4, A5のノウハウといった不定形のものや人間の脳内にしかないものを扱っているという点です。 「成果物」と書くとドキュメントやソースコードなど、具体的なものをイメージしがちですが、PFDではこのような抽象的な対象についても扱うことを許容しています。
例2: 外部勉強会の運営プロセス
それではさらに複雑な例を見てみましょう。 SWETではTest Nightなど、外部の方々を招いた勉強会を主催しています。 その際の開催や運営のプロセスを可視化したものになります。 実際のものからはかなり省略・簡略化したものになりますが、関係各所との調整や、 何をどの順番で実行しなければいけないかが明確になっています。
図3: 外部勉強会の運営プロセスのPFD
図3: 外部勉強会の運営プロセスのPFD
このような複雑な業務プロセスでもPFDを活用することでプロセスを明確に表現でき、特にチームで作業する際には共通の理解を促進するのに役立ちます。
PFDについてその概要・メリット・具体的な事例を紹介してきました。 ですが、PFDの弱点として、その記述やメンテナンスが難しいという問題点があります。
成果物・プロセスそれぞれにつける一意なIDの付与や要素表の作成がその代表的なもので、 成果物やプロセスを生成するたびにIDを編集したり、表と図の対応をそろえたりと、 とにかく人力でPFDを整合性が保たれている状態に維持するのはかなりの労力を費やします。
そこでSWETではPFDの記述をサポートするツールを作成しました。 ツールはWebベースのアプリとして実装されていて、社内の人であれば誰でもアクセスできるようにしています。
ちなみに、この記事に掲載してあるPFD(図1 ~ 3)はすべてこのツールで記述しています。
いくつか機能があるのですが、ここでは主要な機能を3つ紹介します。
ID自動採番
成果物、プロセス生成時に自動で連番のIDを付与します。 また、ここで付与されたIDは後で自然な順序(PFDのグラフ構造の始端が若く、終端に向かうにつれ番号が増えていく)に自動で振り直すこともできます。
ID自動採番機能
要素表自動作成
成果物、プロセスを作成時に自動で要素表にも追加します。 図の方で値を修正すると、要素表に自動反映します。またその逆も自動で行います。
要素表自動作成機能
PFDのルールのチェック
PFDには、記述上のルールがいくつか存在します。 たとえば成果物と成果物は矢印で繋げない(プロセス同士についても同様)、成果物はひとつのプロセスからしか生成されない、などです。 それらのルールに反したPFDをそもそも書けないようにする仕組みが実装されています。
PFDのルールチェック機能
簡単に実装に用いた技術スタックを紹介します。
実装にはReactをベースに状態管理ライブラリとしてRedux、Canvas上のコンポーネントライブラリとしてKonvaを使っています。
Reduxを用いることにより、この手のエディターの基本機能であるUndo / Redoや、ファイルへの書き出しの実装を簡易に実装できています。
まとめ
この記事ではPFDの紹介とSWETでの活用事例、SWETで開発したPFD Draw Toolについて紹介しました。 PFDは成果物にも注目して業務プロセスを可視化することにより、それぞれのプロセスの関係を明確にし、 実行時の不確実性を抑制し、作業者間での認識齟齬を防ぐのに役に立ちます。
SWETではこのPFDを用いて各種業務の可視化や効率化に活用し、さらにPFDの記述やメンテナンスを簡易にするツールを実装しました。
今回はPFDを用いた業務の改善・効率化については触れませんでしたが、また機会がありましたら紹介させていただこうと思います。
注釈
- [1]: 梶本 和博、派生開発推進協議会T21研究会 著 『プロセスを自在に設計するーPFDを使いこなそうー』 八木 将計、八木 香織(編集)、NextPublishing Authors Press、2021年5月29日
- [2]: ここではPFDの説明のために簡略化した開発プロセスを記述しています。実際の開発はここに検証の工程が追加されたり、「仕様を決める」というプロセスの中にも何工程も含まれたり、かなり複雑なものとなります。
- [3]: オリジナルのPFDでは要素表ではなく、それぞれの成果物・プロセスに定義書を記述します。
こんにちは、SWETの秦野です。
2024/6/7(金)に Lint Night #3 を開催しました。
本記事では、当日の発表スライドを紹介していきます。
参加者の反応
当日の様子はTogetterにまとめています。 こちら からご覧ください。
当日の動画
YouTubeにて当日のアーカイブ動画を公開しています。www.youtube.com
発表紹介
@szkdash「lintnet - General purpose linter powered by Jsonnet」
最初の発表は @szkdash さんによる「lintnet - General purpose linter powered by Jsonnet」でした。speakerdeck.com
ご自身が先月リリースされたlintnetについて紹介していただきました。 lintnetはJSONやYAMLなどの様々なフォーマットに対応している汎用的なLinterです。 ユーザーはLinterのルールを Jsonnet で定義し、そのJsonnetを公開すれば様々なプロジェクトで同じルールを共有できます。 ルールの共有が簡単という点が非常に魅力に感じます。
本イベント後にszkdashさんが lintnetの紹介記事 を公開されています。こちらもご覧ください。
@Linda_pp「actionlint の Linter 設計」
次の発表は @Linda_pp さんによる「actionlint の Linter 設計」でした。speakerdeck.com
actionlintはSWETグループでも使わせてもらっていて、お世話になっているツールです。 発表ではactionlintの設計思想について解説していただきました。 CIのワークフローファイルに対するLinterであるという特徴に合わせて、気軽に使えて高速なツールを目指すという方針はとても興味深く参考になる内容でした。
@haya14busa「reviewdog を飼ったコードレビュー支援体験とその汎用的な実現方法」
続いての発表は @haya14busa さんによる「reviewdog を飼ったコードレビュー支援体験とその汎用的な実現方法」でした。docs.google.com
reviewdogもSWETグループで使わせてもらっています。ありがとうございます! 発表ではreviewdogについて紹介していただきながら、世の中のLinterの出力形式がバラバラであるという問題についても解説していただきました。 この問題に対して、haya14busaさんが提案するフォーマットであるRDFormatが紹介されています。 Linterの出力形式にお悩みの方は必見です!
@tomoyamachi「パーサを使わないLintツール dockle」
最後の発表は @tomoyamachi さんによる「パーサを使わないLintツール dockle」でした。paper.dropbox.com
Linterは構文解析をするものだと思いがちですが、dockleはシンプルな文字列操作でコンテナイメージの問題を検知しています。 Linterを作ってみたいけど難しそうと感じている人を後押ししてくれる内容で、Lint Nightのテーマにピッタリだったと思います。
終わりに
お忙しい中登壇していただいた発表者の皆様に感謝いたします。 また、オフライン/オンラインで参加していただいた皆様、ありがとうございました。 皆様のおかげで無事Lint Night #3を開催できました。 今後もLint Nightをよろしくお願いします!
こんにちは、SWETのCI/CDチームに所属している幸田(@ponkio_o)です。
2024/03/26(火)に弊社オフィス(渋谷スクランブルスクア)とオンラインのハイブリッドで CI/CD Test Night #7 を開催しました。
本記事では、当日の発表スライドを紹介していきます。
参加者の反応
当日の様子はTogetterにまとめを作成しているので こちら からご覧いただけます!
当日の動画
YouTubeにて当日のアーカイブ動画を公開しています。www.youtube.com
発表紹介
@ponkio_o「業務で役立つ…かもしれない?!GitHub Actions Tips 集」
最初の発表は私の「業務で役立つ…かもしれない?!GitHub Actions Tips集」でした。speakerdeck.com
GitHubとの相性がよく、便利なGitHub Actionsですが、凝ったことをしようと思うとハマるポイントがいくつかあると思っています。今回の発表では実際の業務で遭遇した様々なTipsを紹介しました。
特に動的なJobの実行とBranchProtectionの話は「役に立った」との反応をいくつかいただけたので、お役に立ててよかったです!
@szkdash「CI/CD のセキュリティや Developer Experience を改善するツールやプラクティス」
続いての発表は @szkdash さんによる「CI/CDのセキュリティやDeveloper Experienceを改善するツールやプラクティス」でした。
スライドはGoogle Slideにて公開されています。docs.google.com
ご自身で開発されている aqua や tfcmt などの紹介に加え、さまざまなセキュリティのプラクティスを紹介していただきました。発表中に紹介のあった ghalint や pinact は直近でも業務で使わせてもらっていたのでタイムリーな内容でした。
szkdashさんのOSSは仕事でもプライベートでも数え切れないくらい使わせてもらっていますが、どのプロダクトもDXだけでなくセキュリティまで意識されている点がすごいな〜と思っています。
@k1LoW「CI/CD があたりまえの今の時代に API テスティングツールに求められていること」
続いての発表は @k1LoW さんによる「CI/CDがあたりまえの今の時代にAPIテスティングツールに求められていること」でした。
APIシナリオテストツールである runn の開発を通じて得たさまざまな気づきを紹介していただきました。
私も前職でrunnを利用していたのですが、今回の発表を通じて新しい情報も知ることできたので、機会があれば使ってみたいと思いました。
また今回の登壇に関するブログを執筆されているのでこちらもご覧ください!
今回の発表とはまったく関係ないですが、個人的に k1LoW/gh-do には大変お世話になっています!ありがとうございます。
@katzchum「リリース戦略を支える CI/CD パイプライン」
続いての発表は @katzchum さんによる「リリース戦略を支えるCI/CDパイプライン」でした。
runnの開発にも積極的に参加されているkatzchumさんからは、複数チームにまたがるリリースの悩みを Semantic Versioning と Songmu/tagpr を使ってうまく解決された事例をデモを交えて紹介していただきました。
tagprは私も仕事とプライベートの両方で活用しており、Semantic Versioningを用いたリリース戦略は弊チームでも採用している部分があるため、とても共感できる内容でした。
終わりに
お忙しい中登壇して頂いた発表者の皆様、そして足元の悪い中、弊社オフィスまで足を運んでくださった皆様に感謝します。皆様のお陰で無事にイベントを終えることができました。
引き続きCI/CD Test Nightをよろしくお願いします。
こんにちは、SWETでCI/CDチームの前田( @mad_p )です。
SWETでは、CI/CDに関する知識を共有することを目的として、「CI/CD Test Night」を開催しています。 約1年ぶりに、CI/CD Test Night #7をハイブリッド開催します!
今回のテーマは「CI/CDのプラクティス」についてです。 CI/CDサービスを利用してパイプラインを作成している中で、ふとしたときに「もっと効率の良い方法があるのではないか?」と考えたことはないでしょうか。断言します、私はあります! そこで今回は、 CI/CDに関するプラクティスや関連するツールの活用方法などをメインテーマとし、弊社メンバーに加え、CI/CDやツールに関する情報を多く発信しておられる以下の方々をお招きして開催いたします。
CI/CDのワークフロー作成時に手助けとなるツールや、どのようにパイプラインを構築しているのかなど、それぞれの現場での知見が多く知れる機会かと思います。 CI/CDのパイプラインを作成して運用しているが課題を持たれている方、これからCI/CDサービスを活用してパイプラインを構築しようと考えている方、すでに色々と知見を持ち課題などを解決している方この会を通して皆さんと多くの意見交換をしませんか。 皆様のご参加をお待ちしております!
オフライン限定になりますが、懇親会も予定しています。 3/26のCI/CD Test Night #7でみなさんにお会いできるのを楽しみにしています!
SWETグループ、23新卒の若松です。
今回、2024/1/31(水)にAndroid Test Night #9をオンライン開催しました!
本記事では、今回の発表のスライドを紹介していきます。あわせて発表内容の動画も公開していますのでご確認いただければ幸いです。
参加者の反応
Android Test Night #9 で盛り上がっている様子に投稿をまとめました。
当日の登壇動画
発表スライド紹介
Kento Wakamatsu:「Roomのマイグレーションをテストする方法」
トップバッターは私で「Roomのマイグレーションをテストする方法」の発表でした。
Roomのマイグレーションをテストする方法と注意すべきことについて、業務で行った例を示しながら説明しています。マイグレーションのテストを書く際は是非参考にしてみてください。speakerdeck.com
@sumio_tym:「Roborazzi + Jetpack Composeでスクリーンショットを撮るときに役立つTips集」
続いては、弊社SWETグループの@sumio_tymによる「Roborazzi + Jetpack Composeでスクリーンショットを撮るときに役立つTips集」の発表でした。
Robolectric(+Roborazzi)でJetpack Composeのスクリーンショットテストを書くにあたり、役立つTipsについて紹介しています。speakerdeck.com
@saikiiiji:「ViewModelのUnitTest難しすぎ問題」
3番目は、株式会社U-NEXTの@saikiiiji様による「ViewModelのUnitTest難しすぎ問題」の発表でした。
Android開発におけるViewModelで、ユニットテストを効率よく書くための役にたつテクニックについて紹介していただきました。ViewModelでテストしたいロジックを別クラスに書き出すだけでテストしやすくなるというのは驚きでした。www.slideshare.net
また、他にもTDDに関する発表を行なったり、RaMviを使ったテーブル駆動開発についてのブログを書かれたりしていらっしゃるので、要チェックです!t.co t.co
@hkusu_:「SARIFファイルを利用したAndroidの静的解析」
最後に、株式会社ゆめみの@hkusu_様による「Androidの静的解析におけるSARIFファイルの活用」の発表でした。
SARIFファイルをGitHub ActionsとGitHub Code scanningを用いてAndroidアプリの静的解析ツールを実行する方法について紹介していただきました。GitHub Actionsで各種静的解析ツールとGitHub Code scanningの連携方法についてかなり詳しく説明されているので、導入する際は是非参考にしたいと思いました。speakerdeck.com
終わりに
今回登壇していただいた皆様、参加していただいた皆様のおかげで、無事Android Test Night #9を終えることができました。大変感謝しております。 Android Test Nightは、今後も定期的にイベントを開催する予定ですので、今回参加していただいた方々、参加できなかった方々も次回お会いしましょう!
SWETグループ、23新卒の若松です。
今回、2024/1/31(水)にAndroid Test Night #9をオンライン開催します。2024年最初のAndroid Test Nightになります!
9回目の開催となる今回は、次の方々に登壇していただき、Androidのテスト・CI/CD・静的解析についての知見を共有していただきます。
- Kento Wakamatsuさん:Roomのマイグレーションをテストする方法
- Sumio Toyamaさん:Roborazzi + Jetpack Composeでスクリーンショットを撮るときに役立つTips集
- Saikiさん:ViewModelのUnitTest難しすぎ問題(仮)
- 久須 裕之さん:SARIFファイルを利用したAndroidの静的解析
Androidのテスト・CI/CD・静的解析について興味がある方であれば、どなたでも参加いただけます。 日々触れている方、気にはなっているけど触ったことない方、他の会社の話を聞いてみたい方など、ぜひ奮ってご参加ください!
2024/1/31のAndroid Test Night #9でみなさんにお会いできるのを楽しみにしています!
こんにちは、SWETグループの田熊です。
現在SWETグループでは書籍「単体テストの使い方/考え方」の輪読会を実施しています。
輪読会ではメンバー同士で活発に意見が交わされていますが、著者の主張に疑問を感じる箇所もあり、一度グループ外の方とも意見を交換したいと考えていました。 そこで、t_wadaさんをお招きし「単体テストの使い方/考え方」についてディスカッションする機会を設けました。
本記事では、SWETメンバーとt_wadaさんとのやりとりを紹介したいと思います。
ディスカッションの流れ
ディスカッションは事前にSWETグループのメンバーが書籍を読んで疑問に感じたテーマを挙げてもらい、t_wadaさんの意見を聞くという流れで行いました。
今回は次のテーマについて話をしました。
- 「退行に対する保護」があるテストとはなにか
- 「リファクタリングへの耐性」のトレードオフはあるのか
- 統合テストの比重を高くする考えについて
- テストダブルの使い方と開発文化
- 関数型アーキテクチャの考えを採用した際の結合バグへの対応
- ユーティリティに対するテストの価値
- 協力者オブジェクトが多いコードのテストでテストダブルの利用
- 単体テストが単体の正しさを保証している度合い
- 著者の主張と意見が異なる点について
- 振る舞いとはなにか
- 「退行に対する保護」と「リファクタリングへの耐性」の表現
- 再現テストをどのサイズとスコープで書くとお得か
※ SWETグループ内での輪読会が第7章までしか進んでいないため、7章以前の内容が中心になっています。
「退行に対する保護」があるテストとはなにか
SWETメンバー質問:
どのようなテストに「退行に対する保護」があると考えているか?
t_wadaさん回答要約:
- バグを入れたときにみつけてくれるテスト
- プロダクションコードの変更に対してテストコードの変更が0に近いと退行に対する保護がある。テストコードの修正が必要だと、そこに対してミスが入る可能性がある
- プロダクションコードにあわせてテストコードの修正の頻度が高くなるのは、実装に対してテストコードの距離が近いから。たとえば、実装の中身が漏れ出しているようなテストや、期待値の計算方法が実装と同じになっているテスト
- 実装とテストが別のやり方でクロスチェックをしている構造になっていると、退行に対する保護の度合いが高くなる。期待値をベタ書きにすることや、テスト対象へのアクセスのやり方を変えるのは、同じ誤りをプロダクションコードとテストに入れないための備え
- 実践 JUnitの「6.4 Cross-check(別の方法でチェックする)」
SWETメンバー質問:
アサーションは緩くもできる。たとえば、例外が発生しないことだけを確認したり、オブジェクトの一部のフィールドのみアサーションの対象にしたりできる。
アサーションの性質からも、バグをよく発見してくれるテストを説明できるのではないか?どのようなアサーションであれば偽陰性を減らせるか?
t_wadaさん回答要約:
- 大きいオブジェクトに対してピンポイントでアサーションをすると、偽陽性のリスクは減るが偽陰性のリスクが高まるトレードオフの関係になっている
- 完全一致で検査する大きいテストとピンポイントで検査するテストを使い分ける
- ユニットテストはピンポイントのテスト寄り。大きいテストとして、フロントエンド領域でのビジュアルリグレッションテストや、バックエンド領域でのレスポンス全体を見るテスト等
- テストスイートの信頼性はテスト全体で測るもので、あるレイヤーのテストの弱点を別のレイヤーのテストで補えればよい
SWETメンバーコメント:
ビジュアルリグレッションテストは画面が同一かを見たいのではなく、本当に担保したいのは使いやすさが壊れていないか。ちょっとしたズレはしきい値で調整して許容できる。
もともと使いやすさを考慮してデザインされた上で画面が作られているため、大きく変わっていなければ使いやすさも壊れていないと考える。
「リファクタリングへの耐性」のトレードオフはあるのか
SWETメンバー質問:
「リファクタリングへの耐性」を下げる原因になる偽陽性について。 偽陽性が出るテストは技術で解決できることが多い。偽陽性で一番多いのはシグネチャ変更によるコンパイルエラー。この本で出てくる偽陽性が原因ですごく出て困った話は出てこなくて、出てもすぐに解決可能だった。
偽陽性をテスト技術でカバーできるのであれば、他の要素とのトレードオフ関係とはいえないのではないか?
t_wadaさん回答要約:
- 本書では偽陽性の原因としてシグネチャ変更、テストダブルの多用について書かれているが、Flaky Testの記述が少ない
- 偽陽性は次の2種類がある
- Fragile Test。コードの変更に対してテストをたくさん直さないといけない問題。これはテストの書き方やテストで使う道具の問題
- Flaky Test。テストの安定性の問題
- 偽陽性の本当の戦いはFlaky Test。著者はE2EテストがFlaky Testのメインファクターだと思っていない
- この本はおおむねよいことを書いていて読んでもらいたいが、この点については鵜呑みにしてはいけない
統合テストの比重を高くする考えについて
SWETメンバー質問:
最近はTesting Trophyのような、単体テストを厚くするよりも統合テストに比重を置く考えも出てきている。ここについてどう考えているか?
t_wadaさん回答要約:
- テスト範囲(スコープ)は人によってブレるので、テストサイズというテスト実行時の動的な側面で分類するのがよいと考えている
- テストスコープで分類するとトロフィーになるものが、テストサイズで分類するとピラミッドになる
- スコープとサイズを3 x 3で分類してコスパのよい領域を整理した。サイズを上げずにスコープを広げられるのが理想
SWETメンバー質問:
テスタビリティを高めるためにデータベースなどの外部アクセスをDIできるようにしているが、これが本当に正しいのか悩んでいる。DIはテスタビリティにのためにプロダクションコードの本来あるべきソフトウェアの設計を変えてしまっているのではないか。
現在はDockerやAWSのFake(LocalStackやMoto)のような道具があって、テスト実行時に環境変数を変更するだけでテスト用インスタンスに繋げられる。DIのための特別なコンストラクタがなくても、テストは書けるし安定させられるのではないか。
t_wadaさん回答要約:
- DIできるようにするのがよいと思っている
- Dockerは安定しているが(オンメモリのテストよりは)速くはない。Dockerを使うとテストサイズがsmallからmediumにあがってしまう。テストの数が増えると実行時間が掛け算になって増えていく。自動テストは信頼できる成功または失敗までに最短時間で到達するゲーム
- 一番終端のプロセス外にアクセスしているところをテストダブルにする戦略がとれるとよい。たとえば(いわゆる三層アーキテクチャの)データアクセスの入り口にRepositoryを置く構成になっている場合に、Repositoryのコンストラクタでテストダブルを注入する。あるいはRepositoryを偽物にする
- Repositoryのテストはデータベースにアクセスしないとできないものもあるので、medium x 単体になる。ドメインレイヤのテストはsmall x 単体が一番よい。それ以外のControllerやServiceはsmall x 統合。そうするとテストの大部分をsmallにでき、テストのパイプラインのスループットが向上する
SWETメンバー質問:
これまでの話はテストから見たときの観点だが、「テストしやすいように設計」することで設計が悪くなっている場合があるのかもしれない。
良い設計とテスタビリティの高い設計が相容れないことはあるのか?
t_wadaさん回答要約:
- 「テスタビリティの高い設計がよい設計」を受け入れるか
- テストファーストをするとテスタビリティは強制的にあがるが、それによって発生した設計がよい設計か?という意見も出てきている
- 視野がせますぎないか、界面が多すぎないかといった指摘。引数が多すぎる、インターフェイスが広すぎるという設計を導くことも多い
- バランスをとる必要がある。外部から注入するのは悪いと思わないが、テスタビリティのためにprivateメソッドをpublicにしますというと怪しい
- よい設計の観点には結合度と凝集度や、認知負荷がある
- テスタビリティが高いと結合度も低いというのはある程度正しいが、凝集度に対してテストコードが関与するというのはあまりない。認知負荷も人次第になってしまいがち
- テストコードを書くことでテスト対象とやりとりする回数が多くなるので、よりよい設計に気づくきっかけは増えるが、腕次第なところもある
テストダブルの使い方と開発文化
SWETメンバー質問:
モジュール境界であっても観察可能な振る舞いでなければテストすべきでないという著者の主張について。モジュール境界で担当者が変わる場合に、テストが落ちたときの責任が誰かはっきりさせるためテストダブルを積極的に使っていた現場もあった。アジャイル開発のような全部のモジュールをみんなで作ろうという文化では、境界を意識しなくてもいい。
テストダブルの使い方にチームの文化が関連しているように思ったがどうか?
t_wadaさん回答要約:
- 責任境界におけるテストダブルの利用は、問題の発見を遅らせる。自組織であれば発見を早めるべき。全員で責任を持ち全員で直していく
- 問題の発見を遅らせてしまう理由は、テストダブルを使うことで偽陰性を持ち込む可能性があるため。本物の動きとテストダブルの動きが異なる可能性がある
- 社外とのやりとりに関しては契約・Schemaの考えでテストダブルを使う、あるいはアンチコラプションレイヤーを用意するというのはある
- 組織内の責任分界点においてテストダブルを使うというのもあると思うが、アジャイル開発のような開発文化にはそぐわないかもしれない
関数型アーキテクチャの考えを採用した際の結合バグへの対応
SWETメンバー質問:
テスタビリティを高めるために関数型アーキテクチャを採用し、純粋関数的な部分と状態をもつものを分離するという著者の主張について。それ自体に異論はないが、結合バグに対して著者は触れていない。結合バグをどう対処するかという話を入れてほしかった。
自分自身はプロセス同士を合成していくとテストケース数が爆発するので手で書くのは無理だと思っている。形式手法等を使って、プロセス同士の合成を検証するような技術に行き着くと思っている。結合バグへの対応について意見を聞きたい。
t_wadaさん回答要約:
- そう思う
- 統合テストをカジュアルに書けるようにしよう、単体と統合の違いよりテストサイズの違いを気にしよう、と最近言っている。単一プロセス内の組み合わせはどうにかできるところまで来ている
- 分散コンポーネントの領域でモデル検査や形式手法が成果を出しているのは良いニュース。まだカジュアルに使えるようになっていないのをどうするか
- 組合せ爆発や副作用をどう扱うかは設計者に必要とされるスキルだが、あまり啓蒙は進んでいない。試みとして純粋関数型から考えを輸入している
- 無矛盾性や自分たちが把握しているバグのなさににこだわることはできないので、Observabilityを高めることでカバーしていこうというのが2023年のトレンド
ユーティリティに対するテストの価値
SWETメンバー質問:
著者は単体テストを行う価値がもっとも高いプロダクション・コードは複雑なコード、もしくは、ドメインにおける重要性が高いコードと言っている。さらにユーティリティはドメインでないと言っている。ドメインにおける重要性の高いコードの一部をユーティリティに切り出すと、切り出されたコードは単体テストを行う価値が低くなってしまう。また、ユーティリティは広く薄く使われるので、壊れたときの影響も大きい。
単体テストを行う価値のあるコードの定義についてどう思うか?
t_wadaさん回答要約:
- 同意
- ユーティリティはドメインではないという点はよいが、だからテストを書く価値が低いというのはおかしい
- 著者は依存度に対して被依存度をあまり重視していない。依存度が低くて被依存度が高いコードへのテストはコスパがよいので、テストすればよいと思う
- 著者的には被依存度の高い箇所が壊れたら、どこかのテストが壊れるだろうという考えなのかもしれない
- ユーティリティに対して網羅されたテストがあって、使う人みんなが安心という構造のほうが健全
協力者オブジェクトが多いコードのテストでテストダブルの利用
SWETメンバー質問:
コントローラのような協力者オブジェクトが多いコードについて、単体テストは行わず統合テストで行うという著者の主張について。自分自身の感覚だと、協力者オブジェクトのハンドリングに関するロジックはモックライブラリを使ってテストする。一方で、そのようなテストが壊れやすいというのも理解はできる。
そのあたりのバランス感覚について意見を聞きたい。
t_wadaさん回答要約:
- テストのスタイルに関する部分
- 自身のスタイルは古典派寄り。あまりインタラクションベースのテストも書かないし、テストダブルもあまり使わない。著者とスタイルは近い。昔はロンドン学派だった
- サイズが上がらざるを得ない箇所はテストダブルを使ってsmallでおさまるようにしている。呼び分けは呼び分けた結果の戻り値やステートを見る。smallサイズの統合テストとして書くようにしている
- 自動テストをテストサイズで整理したことにより、テストダブルの使いどころを説明しやすくなった
- 「なるべく早く信頼できる結果にたどりつく」という目標を定めて、どうやって信頼性の高いテストを積み上げていけるかで整理した
- なんとなくテスタビリティを上げたり網羅率を上げるために使ってきたが、サイズを下げるところが使い所だという認識を得た
SWETメンバー質問:
ロンドン学派から今のスタイルになったきっかけは?
t_wadaさん回答要約:
- 2004〜2006頃はロンドンスタイルだった
- 当時はモックライブラリがいまほど優秀じゃなかった。シグネチャを変更するたびに手でメンテナンスがいる状態だった。リファクタリングへの耐性が低く、仕様変更のたびにコストがかかっていた
SWETメンバー質問:
最近は強力なモックライブラリも登場し、不必要に使われているケースも見かける。実際にモックライブラリを使いすぎてテストが壊れた経験をしていないと、この本で偽陽性について強く言っていることが理解できないかもしれない。
実際にモックライブラリの多用でテストがメンテナンスできなくなったりした事例は知っているか?
t_wadaさん回答要約:
- 現場によりけり
- 強力なモックライブラリの副作用はでかい。現在の設計に対してそのままテストを書く道具として使われがち。結合度高くても介入しちゃえばいいよといって使われてしまう
- たとえば、網羅率をあげるためにテスト対象のPartial mockみたいなことを始めてしまう。privateメソッドはprvateメソッドをこじあけてテストするし、publicメソッドはprivateメソッドをスタブアウトしてテストしている現場がある
- そういったテストは、コードをリファクタリングしようとしたときにテストが頼りにならなくなってしまう。リファクタリング耐性がないテストコード
- たとえば、メソッドの切り出し方が悪いので一度インライン化して別のやり方で切り出そうとしても、既存のテストが役に立たない
- 腕次第やテスト方針立ててないからといえばそうなんだが、強力な道具を与えるとそういう使い方になってしまうというのを目撃している
- 他にも「モックが作りにくいのは設計がよくない兆し」と言いたいのに、強力なライブラリでゴリ押しできてしまう
SWETメンバー質問:
テスト対象の仕様と振る舞いが何なのかという点からテストダブルを使うか使わないかの判断するようにしている。オブジェクト間のコミュニケーションを通信として捉えたときに、モジュールの中で通信が発生することを振る舞いと捉える。その振る舞いをチェックするためにテストダブルを使う。通信も振る舞いの一環として捉えるモデルの考え方があって、モデルとコードの距離が近くなるため。
このような考えはどうか?
t_wadaさん回答要約:
- 本で出てくるどこが観測可能な振る舞いなのか?という話につながる
- 間接出力の向かう先が外部なのか内部なのか。外部であればテストダブルを使うことに妥当性があることもあると思うし、内部だと個人的にはやりすぎだとも思う
単体テストが単体の正しさを保証している度合い
SWETメンバー質問:
テストはバグがないとこを保証できないとはいうものの、感覚としてはテストを書いているとかなり保証できているんじゃないかなと感じる。実際にはテストの漏れがあったりして、その感覚があっているわけでもない。
単体テストを書いていて保証されている度合いをどう感じているか?十分高いと感じるなら、なぜそう感じるのか?あるいは十分高いとはいえなくてテストという手法について限界を感じるのであれば、どうやって補っていけばいいと考えているか?
t_wadaさん回答要約:
- 単体テストは「使ったときこうすればいいと思っていました」が「いまも認識どおりか?」というのを高速に低コストで確認するぐらいしかできていない。わかっているものにはテストが書けるが、わかっていないことすらわかっていないものにはテストは無力
- テストを書いていくことによってテスト対象にふれる機会が増えるので、気づきやすくなるメリットはあるが、ひらめきや注意深さは個人の性質による
- Unknown unknowns領域(知らないし理解していない領域)を収集していかないと、動作に対する確信には繋がらない。わかったことはKnown knowns領域(知っているし理解している領域)として自動テストにしていく
- スキルフルな人がやる探索的テストもあれば、無作為に色々やるというのもある。インフラの領域ではカオスエンジニリアリングなどのアプローチもある
- わからないのだからunknownsに対してすぐに反応できるようObservabilityを高めるという考えもある
* オブザーバビリティと監視
SWETメンバー質問:
ひらめき、注意深さは伸びていくもの?
t_wadaさん回答要約:
- 訓練の結果伸びる人も多数いるが、Top of Topには才能や向き不向きがあるように感じる
- 探索テストの才能が抜きん出て高い人は実在するが、教育や訓練などによって育成できるかどうかはよくわかっていない。才能だけだとスケールしないのでどうにかしないといけない
- 過去に抜きん出てすごい人がいたが、昔のコンシューマーゲームのように、リリースしたあとで挽回するチャンスはないような環境で鍛えられてきた
著者の主張と意見が異なる点について
SWETメンバー質問:
著者の主張と和田さんの考えで異なる部分があれば聞きたい
t_wadaさん回答要約:
- 「ものすごく良い本なのでみんな読んでほしいけど、鵜呑みにはして欲しくない」みたいな読後感。細かいところで違うと感じる点は多々ある
- たとえば著者が主張するテストメソッド名について、最近生成AIがテストコーディングに強く関与し始めている。テストメソッド名をどう書くとAIに理解されやすいかも重要になってくる
- テストダブルの使い方は筆者のスタイルと似ていて齟齬がない
振る舞いとはなにか
SWETメンバー質問:
テスト界隈で出てくる「振る舞い」という言葉が表わすものはなにか?
自分の理解だとあるユーザーストーリーを振る舞いと言っている人が多いように見える。ただはっきりと主張している人を見たことがあるわけではない
t_wadaさん回答要約:
- この本ではテスト対象のシグネチャではなく、対象の実行前後の差異とそれによって目的が達成されたか、という認識なのではないか
- Behaviorという言葉は歴史的に混乱もあったのであまり使いたい言葉ではない
- テスト界隈では2000〜2004あたりに「振る舞い」が出てきた
- テスト駆動開発の過去・現在・未来
- TDDのTが、これまでのテストのイメージに引きずられて言いたいことが伝わらない。出てきた言葉がBehavior (BDD)
- それ以降Behaviorが使われるようになったが、はっきりした定義はないまま
- コードの見た目をしているから伝わらないという意見も出てきて、Gherkin記法が登場した。Gherkinで書くことをBDDという人もいる
SWETメンバー質問:
本書には技術者以外が読めるようにテストメソッド名をつけるという記述があったが、単体テストをエンジニア以外が読むとは考えにくい。
どう書いたらエンジニア以外とのコミュニケーションがうまくいくだろうか?
t_wadaさん回答要約:
- 「全員同席」と「顧客がテストを書く」という夢を見て作られたのがGherkin。テストを形式化された自然言語で書けば、顧客がテストを書いてくれるしQAエンジニアがテストを読めるという考え
- ワンチームでやっているチームでは回っている。そうでないチームでは、顧客もテストエンジニアもテストコードを読まないのにプログラマにとっては間接層を増やしている感覚
- 距離が近いチームではモブプロ・ペアプロでやるとよい。非エンジニアもエンジニアと一緒だったら読み書きできる
- そうではないチームではドキュメントにするしかないが、どういったドキュメントだったら伝わるか、メンテできるか。どのようなドキュメントを作ればよいかは、各社模索中
「退行に対する保護」と「リファクタリングへの耐性」の表現
SWETメンバー質問:
4章のはじめで導入されたよい単体テストを構成する4本の柱のうちの2つ「退行に対する保護」と「リファクタリングへの耐性」という表現は、著者固有の定義か。それともテスト界隈で広く使われている表現か?
t_wadaさん回答要約:
- 「退行に対する保護」は、表現は違えど通常これを目的に自動テストをするので以前からあった言葉
- 「リファクタリングへの耐性」は、みんな思っていたことだが名前はなかった。それにこの著者が名前を与え、4本柱に入れようと提案した。その点は本書の価値
再現テストをどのサイズとスコープで書くとお得か
SWETメンバー質問:
再現テスト(バグがみつかったときにそのバグを再現させるテスト)はサイズとスコープのマトリクスのどの領域で書くとお得?
t_wadaさん回答要約:
- small x 単体
- 謎の振る舞いが見つかったときにスコープの広いテストで再現させることができたら、最小の単位まで絞り込んでいく。再現ケースをもっとも小さいスコープ・サイズで作れたら勝ち
- 自社開発でもするし、OSS開発でもする。ほとんどの場合そのケースを作れたら修正は容易
まとめ
書籍の内容に限らず単体テストをテーマに幅広い内容の意見交換ができ、書籍を読んで疑問に感じていた部分の解消と、自動テストについての新しい気づきにつながったと感じています。また、SWETメンバーの質問は自分1人で書籍を読んでいたときには気がつかなかった視点もあり、t_wadaさんの回答とあわせて学びの多い時間でした。
個人的には特に次のトピックが印象的でした。
- テストサイズとテストスコープのマトリクス
- 良い設計とテスタビリティの高い設計の関係
- Unknown unknowns領域の収集
この記事がSWETメンバーと同じように「単体テストの考え方/使い方」を読んで疑問に感じた方、さらに理解を深めたい方の参考になれば幸いです。
最後になりますが、t_wadaさん、お忙しい中時間を作っていただきありがとうございました!