ソフトウェアの品質を学びまくる

ソフトウェアの品質、ソフトウェアテストなどについて学んだことを記録するブログです。

【翻訳】モダンテスティングの原則

 同僚に紹介してもらった「Modern Testing Principles」、わかりやすくていいなと思ったので、許可を得て翻訳してみました。原文のブログ「AB Testing」は、ABテストとは関係なくって、PodcastとSlackを主宰しているAlanさんとBrentさんの名前からですね。

www.angryweasel.com

 なお、Work in Progressということで今後も変更されていくようなので、現時点での原文を引用しておきます。

  1. Our priority is improving the business.
  2. We accelerate the team, and use models like Lean Thinking and the Theory of Constraints to help identify, prioritize and mitigate bottlenecks from the system.
  3. We are a force for continuous improvement, helping the team adapt and optimize in order to succeed, rather than providing a safety net to catch failures.
  4. We care deeply about the quality culture of our team, and we coach, lead, and nurture the team towards a more mature quality culture.
  5. We believe that the customer is the only one capable to judge and evaluate the quality of our product
  6. We use data extensively to deeply understand customer usage and then close the gaps between product hypotheses and business impact.
  7. We expand testing abilities and knowhow across the team; understanding that this may reduce (or eliminate) the need for a dedicated testing specialist.

 では以下、翻訳です。
 誤訳や改善点あれば、Twitterなどでご指摘ください。

翻訳

モダンテスティングのミッションステートメント

 リリースに足る*1品質の達成を加速すること。

モダンテスティングの原則

 これらはまだ仕掛かり中であり、コメントを歓迎します。また、より踏み込んだ議論のために、slackグループに参加してください。
 モダンテスティングの7つの原則は、以下の通り。

  1. わたしたちは、ビジネスの改善を優先する。
  2. わたしたちは、チームを加速させる。リーンシンキングや制約理論(TOC)といったモデルを利用して、システム*2のボトルネックを特定し、優先順位をつけ、軽減するのを助ける。
  3. わたしたちは、継続的な改善の力である。欠陥を捕まえるセーフティネットを提供するよりも、成功するための適応・最適化を助けるのだ。
  4. わたしたちは、チームの品質カルチャーに十分注意を払ったうえで、さらに成熟した品質カルチャーに向かうために、チームを助け、導き、育てていく。
  5. わたしたちは、自分たちのプロダクトの品質を判断・評価することができるのは、唯一お客様のみであると信じる。
  6. わたしたちは、広くデータを用いてお客様の使い方を深く理解し、プロダクトの仮説とビジネスインパクトの間にあるギャップを小さくしていく。
  7. わたしたちは、テストに関する能力やノウハウをチームに広める。そのことが時に、テストのスペシャリストを専任でおく必要性を減らして(あるいはなくして)しまうことを理解したうえで。

所感

 これを読んで、「当たり前のことしか書いていない・・・」と感じる人と、「はあ?」と感じる人がいるかもしれません。カルチャーやコンテキストによっては、この原則と真っ向からぶつかると思います。たとえば以下のような風土・考え方をもつ組織とは、合いそうにないですよね。

  • テストチームの第一の目的は、できる限りたくさんのバグを見つけて、外部品質を高めることである。
  • 開発チームは自分たちで品質を判断できないので、テストチームが判断する必要がある。
  • QA組織は、開発組織と独立した部門であり、開発の最後に品質保証の活動を行うものである。

 どっちが正しいかはわかりませんし、状況によるのかもしれませんが、どっちが楽しそうかといえば、「モダンテスティング」の方が楽しそうだなーとわたしは思います。

 これらの原則から感じられるのは、「お客様」「チーム」という2つの視点ですね。
 特にわたしが好きなのは、7です。テストチームは、テストをする人のポジションを守るためにあるものではなく、お客様のビジネスとチーム全体をよくするためにあるもの。「テストチーム」を守るために、テストの技術を秘法にするのでは、チームの加速に寄与することなんてできない。7が、自分自身の否定につながると感じるなら、それは成長のための学習を怠っているからでは?と言われているように思います。

 あ、リーンシンキングとTOCですか? もちろん書籍を持っていますよ。

IMG-1985

 持ってはいます!
 ・・・成長のための学習を怠っているなあ。(ザ・ゴールの焼けた背表紙を見つめながら)

ザ・ゴール ― 企業の究極の目的とは何か

ザ・ゴール ― 企業の究極の目的とは何か

リーン・スタートアップ

リーン・スタートアップ

  • 作者: エリック・リース,伊藤穣一(MITメディアラボ所長),井口耕二
  • 出版社/メーカー: 日経BP社
  • 発売日: 2012/04/12
  • メディア: 単行本
  • 購入: 24人 クリック: 360回
  • この商品を含むブログ (95件) を見る

*1:「Shippable」(出荷可能な)意訳です。定訳あるでしょうか?

*2:ここでいう「システム」とは、コンピュータシステムではなく、開発チーム・プロセスのことを指していると考えています。

寿司とシャンパン、ディープラーニングとExcel、そんなマリアージュ

 『大予測 次に来るキーテクノロジー2018-2019』という本を読みました。野村総研のアナリストである城田真琴さんが、「次に来る」8つのテクノロジーの今とこれからについて、ふんだんな事例とともに解説したものです。 

大予測 次に来るキーテクノロジー2018-2019

大予測 次に来るキーテクノロジー2018-2019

  • 第1章 人工知能
  • 第2章 自動運転
  • 第3章 音声インタフェース
  • 第4章 チャットボット
  • 第5章 VR・AR・MR
  • 第6章 バイオメトリクス認証
  • 第7章 センシング、IoT
  • 第8章 ブロックチェーン

 多くの人にとってはほとんどが、聞いたことのあるテーマ・分野だと思います。タイトルに「2018-2019」と明示しているだけあって、「すぐに古くなることは承知で、今まさに旬な情報を詰め込んだ」という割り切り方で、先端企業の取り組みを幅広くカバーしています。たとえば音声インタフェースであれば、Amazon、Google、Appleといった巨大企業の覇権争いに、日本からはLINEが殴り込みにいき、音楽配信サービスとの連携でも火花を散らしていますね。

www.phileweb.com

 新しい技術がもたらす既存の社会システムとのズレについても、興味深いものがありました。ハイレベルな自動運転が実現され、運転の過失をユーザに問えなくなったとき、自動車保険はどのような形をとるべきか。音声認識端末がホテルの部屋に設置された場合、ユーザと、(録音のログを確認・管理できる)オーナーが一致しなくなるが、プライバシーはどう守るべきか。偏見なしで中立的な判断をしてくれるかのような人工知能に、人種差別的なバイアスが含まれるとしたら?などなど。

smartdrivemagazine.jp http://www.sekaiwoyakusu.com/entry/machineracismwww.sekaiwoyakusu.com

 また、チャットボットは「次に来る」イメージがわたしにはなかったため、取り上げられていたこと自体が意外でした。「なんとなく不自然な受け答えをして、結局正解にたどり着けないナニカ」という思い込みしかなかったので・・・。
 サービスを提供する企業にとってチャットボットは、スマホアプリやSNSの次の顧客チャネルという位置づけになっており、そこでのサービス展開が重要になってきているのだそうです。  

 チャットボットもそうですが、紹介されているテクノロジーの多くが、人工知能・ディープラーニングとともに語られているのも印象的でした。何らかの判定を行うための基幹技術としてディープラーニングが前提となっているのです。もはや、テクノロジーを成立させるための基盤技術なのですね。

 そんなディープラーニングを学び始めるのに適した本はたくさんあると思うのですが(ここから本題)、その中で異彩の放ち方が異彩すぎるのがコレ、『Excelでわかるディープラーニング超入門』。

Excelでわかるディープラーニング超入門

Excelでわかるディープラーニング超入門

 いやいや・・・。・・・いやいやいや! Excelでって!
 ってなりませんか?
 表紙でこんな風に煽ってきます。

難しい数学計算はExcelに任せて ディープラーニングのしくみを 動かしながら理解できる!

 「難しい数学計算」といいますか、本書は偏微分どころか行列もΣも出てきませんからね。ほぼ、加減乗除のみです。

 本書の目的は、数学やプログラミングの素養があまりない人が、「身近な」Excelを使ってディープラーニングを理解できるようになることです。なので、Excelの基本的な関数を丁寧に追っていけば、ディープラーニングが詰まるところ何をしているのか、がわかった気になります。重みづけとは、閾値は結局何なのか。どうやって文字を判定しているのか・・・。
 そして途中でExcelの限界につきあたり、その限界を畳み込みニューラルネットワークで一度超えて、「それでもやっぱりこれ以上は無理だよね」というところまで導いてくれる。それが本書。

 使う関数は、以下の通りです。特に難しいものはありません。

• SUM: 目的関数の計算
• SUMPRODUCT: 入力の線形和
• SUMXMY2: 平方誤差の検出
• EXP: シグモイド関数
• MAX: MAXプーリング、ReLU
• RAND: 初期値設定
• IF: 画像の判定

 3×4のビットパターンに対し、「〇」か「×」かを判定するアプローチは、こう*1

01

 ビットパターンをExcelの3×4マスを使って表現している・・・*2。 この発想、面白過ぎると思うんですよね。言われてみたらできそうな気はするけど、本当にやる?っていう。

 こちらが、入力層→隠れ層→出力層までを計算するExcelワークシート。

02

  • 隠れ層には3つのニューロンがあり、ビットパターン4×3セルに対応する重みづけの初期値がRAND関数で選ばれる。 閾値も同様で、ニューロン3つに対応して3つ設定されている。
  • 入力層のビットパターンと隠れ層の重みづけがSUMPRODUCTで掛け合わされたうえでシグモイド関数にかけられて、隠れ層の出力になる。
  • 隠れ層での出力と、出力層の重みづけ・閾値も同様に計算され、出力層の出力になる。
  • 誤差は、出力層の値と正解のゼロイチとの平方差分がとられる。
  • 各「画像」に対する判定結果に対する差分の和が、QT。

 最後に、上の絵でいう色塗りされたセル(最初にRAND関数でランダムに決めたもの)を変数とし、QTを最小化するようソルバーで計算させます*3
 これで確かに、「難しい数学計算はExcelに任せて」、最適なニューラルネットワークを求めることができました・・・・。

 Excelのサンプルワークシートがあるし、説明も冗長なくらい丁寧なので、Excelに慣れている人ならこの理解ルートは意外にたやすいのでは!?と思ってしまいます。ディープラーニングの本の数式に慄いてしまった方は、この道も考えてみてください!

*1:技術評論社の「サポートページ」に掲載された自習用Excelのキャプチャです。

*2:灰色セルには「1」が立っていて、計算に使われます。

*3:わたしのパソコンでは10秒ほどで計算が終わりました。

アジャイル開発におけるメトリクスには、どういうものがあるのか

 アジャイル開発において、プロダクトや組織の現状を把握するのに役立つメトリクスを知りたいと思い、「agile kpi」などでググって上位のサイトを読むという丁寧なサーベイを敢行。20個くらい読んでいくとだいぶネタも尽きてきたので、整理してみました*1。参考にしたサイトについては、記事の最後に載せておきます。
 なお以下では、アジャイル開発とスクラム開発をほぼ同じ意味で使っていますが、怒らないでいただきたいですね。

メトリクスとKPI

 メトリクス(metric / metrics*2)とKPIはごちゃごちゃに使われがちです。こちらの資料では、以下のように説明しています。

www.slideshare.net

  • メトリック: プロセス・プロダクト・チームの定量的な評価・制御・改善のための物差し、またはその組み合わせ
  • KPI: 戦略的な目標に強く紐づけられた、最低1つの期限付き目標をもったメトリック

 KPIの設定方法として、有名な「SMART」や「INVEST」といった基準に言及しています。

 では、各サイトで言及されているメトリクスについて紹介していきます。
 ざっくりと、「開発能力」「進捗」「プロセス」「品質」に区分していますが、複数の区分にまたがるものもあります。

開発能力

 チームの開発能力を測ることのできるメトリクスは、以下のものです。

  1. ベロシティ
  2. サイクルタイム
  3. 平均欠陥修復時間 (MTTR)

ベロシティ

 スプリント内で完了できた仕事の量。
 仕事の量は、見積もり規模であったり、ストーリーポイントであったり、チームによってさまざまでしょう。
 ベロシティを測定する目的の一つは、自分たちが一定期間に開発できる量を知り、見積もりの精度を上げることです。スプリントを重ねていくと、ベロシティが安定していくことが期待できます。低下傾向にあるようなら、開発プロセスに非効率な部分があるとか、コードの保守性が悪化しているといった問題の兆候かもしれません。

サイクルタイム

 タスクの消化にかかる平均時間。要件の特定からリリースまでの「リードタイム」(TTM)の対となる概念という扱いです。
 具体的には、タスクが仕掛中(doing)になっている時間を測っています。タスクが適切に分割されていれば、サイクルタイムは一定になるはずで、開発能力や開発プロセスの安定を見ることができるという理屈です。
 このメトリクスは今回の調べる中で初めて知ったのですが、扱っているサイトは多く、一般的なもののようです。

 下の図は、Main Agile Software Development Metrics and KPIsから引用したものです。平均、移動平均、標準偏差と、サイクルタイムを1つの図に表現しています。

13-768x456_CycletTimeChart

 サイクルタイムが短いということは、開発の能力が高いというだけでなく、品質問題による手戻りが少ない、作業の待ち時間が短い、コンテキストスイッチが少ないなど、品質や開発プロセスの良さによるものかもしれません。逆もしかりで、サイクルタイムの悪化は、品質やプロセスに何か問題のある兆候と考えられます。
 サイクルタイムは「安定して」「徐々に短くなっている」ことを目指すことになります。実装と欠陥改修のタスクを分けて計測しているケースもあるようです。

平均欠陥修復時間 (MTTR)

 欠陥修復までの平均時間。欠陥数 / 改修のためのコーディング時間 で算出します。
 MTTR(Mean Time To Repair、平均修理時間)は、コンピュータシステムの保守性を表す指標として有名です。これを開発チームの効率を測るのに使ったものです。

www.dospara.co.jp

 ここでは「開発能力」にカテゴライズしていますが、問題発見から原因特定・改修・テストまでのプロセスが円滑であるとか、原因の特定や改修が容易な、保守性の高いプロダクトであるといったことも考えられます。
 この指標も、たとえば「バージョンを重ねるごとにMTTRが低下しているのは、技術的負債が増加しているためでは」「品質が悪すぎるので、新規開発を止めて改修に専念すべきなのでは」というように、問題の兆候と捉えたり対策を打ったりするのに役立ちそうです。 

進捗

 開発の進捗を測ることのできるメトリクスは、以下のものです。

  1. バーンダウンチャート
  2. テスト進捗率

バーンダウンチャート

 進捗をみるうえで代表的なのが、タスクの消化具合を可視化した、このバーンダウンチャートでしょうか(バーンダウンチャート自体はメトリクスではありませんが・・・)。残日数と仕事量から算出した理想線と実際の線を比較することで、進捗状況の把握や、完了見込みの推定を行います。スプリント単位でも、バージョン単位でも用途があります。

 ポイントとして、「開発の途中での総作業量の増加」を見える化することも大事です。ある1日に10SPの仕事を消化した一方で、何らかの理由で10SPの仕事が追加されてしまった場合に、単に「グラフが下がらない」と見えるだけだと困ります。「消化した分、下がる線」(傾きがベロシティに相当)と、「追加された分、上がる線」(各時点での全作業量に相当)を見られるようにしておくべきでしょう。
 他の表現方法として、「追加された分を棒グラフの負の側に出す」というものもありました。こちらの方が直観的にわかりやすいかもしれません。

 下の図は、サイクルタイムと同様、Main Agile Software Development Metrics and KPIsから引用しています。

7-768x430_ReleaseBurndown

 なおアジャイル開発において、1つの開発バージョンの中でスコープの変更が起こることは必然です。一方スプリントの中で頻繁にスコープクリープが発生するのはよくないことでしょう。要件の受け入れやタスクの工数見積もりに問題がないかの確認が必要です。

テスト進捗率

 テスト全数に対し、完了しているテストの数で、時間推移を見ます。
 チケット管理と一元化されているか、テスト管理ツールで別管理するかはチームによります。

プロセス

 プロセスの良しあしを測ることのできるメトリクスは、以下のものです。

  1. タスクのステータス分布
  2. リリースオーバーヘッド
  3. フロー効率性
  4. 予見性

タスクのステータス分布

 タスクのステータス(たとえば todo、doing、doneの3種類)を色分けして積み上げたもの(累積フローチャート、累積フロー図)です。doingの層の横幅が、上述のサイクルタイムに相当します。また、Main Agile Software Development Metrics and KPIsから引用しています。

14-1-768x464_CumulativeFlowDiagram

 健全な状況では時間ともにdoneの割合が増えていくことが期待されれます。
 doingの割合が増加傾向にあれば、doneに進められないようなプロセス上の問題や、ブロックしているバックログがあるのかもしれません。あるいは、WIP(Work in Progress)タスクが多すぎてコンテキストスイッチが多発し、開発効率が落ちているかもしれません。チームメンバーのWIP数と流出欠陥には相関があるという調査(PDF)もあります。

 これもやはり、問題を早期に発見するためのツールといえるでしょう。
 タスクの種類が、実装なのかバグの改修なのか、はたまた環境構築なのかによってグラフを分けてみれば、新しい知見があるかもしれません。インシデントレポートはどんどん増えているのに、一向にdoingにならない、とか・・・。 

リリースオーバーヘッド

 リリースのためにかかる時間やコストを表します。
 短い周期で定期的にリリースするのであれば、そのための時間とコストを小さくする必要があります。RC(Release Candidate)のテストやデプロイ前の確認フェーズでの時間やコストを計測し、ボトルネックを見つけることで、プロセスの効率化を図ります。

フロー効率性

 実働時間と待ち時間の割合を示します。
 他のタスクの完了を前提とするようなタスクが増えてくると、前提タスクの完了を待つ時間も長くなってしまします。そのような非効率を可視化し、プロセスの劣化やボトルネットを検出することができます。

 このフロー効率性と、対をなす概念であるリソース効率性については、以下のページがとてもわかりやすいです。

i2key.hateblo.jp

予見性

 各メトリクスにおける計画と実績の乖離をみるという、メタ的なメトリクスです。
 メトリクスについていろいろな記事を読んでいると、「開発能力が高い」ということと同じくらい、「安定している」ことが求められていることに気づきます。プロセスが安定していて、見積もりの精度が高い。これをpredictability(予見可能性)と呼んでいます。
 予定との差の大きさや、実績値の標準偏差を測定し、ばらつきが少なくなるように改善をすることになります。ばらつきが少なければ、見込むバッファも小さくてすむようになります。 

品質

 もともとこれが知りたくて調査を始めたのでした。
 品質の良しあしを測ることのできるメトリクスは、以下のものです。

  1. コードカバレッジ
  2. コードの複雑度
  3. コードチャーン (code churn)
  4. 欠陥密度
  5. 欠陥の出方
  6. DDP (Defect Detection Percentage、欠陥検出率)
  7. 平均欠陥検出時間 (MTTD)
  8. テストの成功率
  9. ビルドの成功率

コードカバレッジ

 JSTQB用語集(PDF)での定義は、以下の通り。

テストスイートが、ソフトウェアのどの部分を実行(カバー)し、どの部分が未実行かを判定する分析手法。たとえば、ステートメントカバレッジ、デシジョンカバレッジ、条件カバレッジ。

 品質の十分条件というより、必要条件的に使われることが多いと思います。
 ステートメントカバレッジ・デシジョンカバレッジ100%を目指す組織もあれば、『知識ゼロから学ぶソフトウェアテスト』では「一般の商用ソフトウェアなら60~90%で十分」としています。(60~90は幅広いですけど・・・)

 カバレッジの種類はいくつかあるので、意味を理解しておく必要があります。このブログでは以下で紹介しています。

www.kzsuzuki.com

コードの複雑度

 ソースコードがどれだけ複雑かを定量化したものです。
 コードが複雑であれば、欠陥を埋め込みやすく、テストも複雑になるため、プロダクトの品質の悪化につながるでしょう。 また、同じ理由で改修も難しくなってしまうので、保守性も悪くなり、長期的な品質に影響します。複雑度は、欠陥を埋め込みやすいリスクの高いコードを特定し、コードレビューやリファクタリングの優先順位付けに利用することができます。

 複雑度の例としては、ネストの深さやクラスの結合度、McCabeのCyclomatic複雑度、Halsteadの複雑度などがあります。ただ、人間と機械では複雑さに対する感覚が異なるので注意が必要です。先日の機械学習のイベントでも、富士通アプリケーションズさんのお話で、「コード解析では複雑と判定されなくても、人間にとっては読みづらいコードを学習させる」というお話がありました。

www.kzsuzuki.com  またこれ以外のコードメトリクスとして、コードクローンやセキュリティ脆弱性など、主にツールを使って検出するものもありますね。

コードチャーン (code churn)

 どのくらいのコードが追加・削除・変更されたかという情報から、開発ステージごとのコードの安定性を見る指標です。
 Qiitaの @hirokidaichi さんの記事では、以下のように説明されています。

複数人で複数回にわたって編集されたファイルは複数の目的でコードが編集されている訳ですから、「単一責務原則」を違反している可能性が高く、潜在的にバグを内在していそうだということです。

qiita.com

 増加傾向(コードの修正が頻繁になっている)であれば、テストが不足している可能性があります。また、リリース直前に複数の人間による多くのコミットがあれば、そのコードが安定しているかを調査する必要があるでしょう。

欠陥密度

 開発規模(SLOC、FP、ストーリーポイントなど)あたりの欠陥の数です。WFでも何かと議論になりがちなメトリクスですね。
 たとえばSLOC(source lines of code)を分母とするケースでのわかりやすい欠点としては、実装の難しさやコードの複雑さが考慮されないというものがあります。「大きな組織で1つの基準を設け、全プロジェクトでその基準を参照する」よりは、1つのプロダクトの中でトレンドを見る方がよさそうです。SPを分母にする場合は、他チームとの比較がそもそもできないでしょう。
 ベロシティなどと同様、安定していれば見積もりにも使えるようになりますし、何らかの異常を検知することもできます。

欠陥の出方

 アジャイル開発に限った話ではありませんが、欠陥をいろいろな観点で分析することは重要です。たとえば、機能・ストーリーでの分類、重要度での分類、品質特性(機能性、性能、ユーザビリティ、保守性、・・・)での分類、オープン/クローズの時間推移など。
 ただ、分類と数字だけで判断するべきではなく、傾向を見つけたらそのエリアのバグ票の中身にまで突っ込んでいくことが必要になるでしょう。
 アジャイル開発においてもシフトレフトアプローチは有効で、早期に見つけるほど改修コストは下がります。

DDP (Defect Detection Percentage、欠陥検出率)

 プロダクトの全欠陥のうち、開発の中で摘出できたものの割合です。DDPが高いほど、開発の中でしっかり欠陥を刈り取れているということになります。

 ウォーターフォールの文脈ですが、『システムテスト自動化 標準ガイド』では、「開発中」と「リリース後」の二分だけでなく、開発中の各テストフェーズでのDDPを算出する話が出てきます。たとえば、結合テスト(欠陥80件)→システムテスト(欠陥15件)→ユーザ受け入れテスト(欠陥3件)→リリース(欠陥2件) とすると、以下のように計算できます。

  • テストのDDP = (80+15+3) / (80+15+3+2) = 98.0 %
  • システムテスト完了時点での結合テストのDDP = 80 / (80+15) = 84.2 %

 たとえばテスト工程をスプリントで読みかえて・・・ということも考えてみますが、適切な読み替えではなさそうでもあり。アジャイル開発の文脈で、DDPをうまく使っている例があれば知りたいです。

 リリース後の欠陥という観点では、fabric.ioのようなサービスを利用しての、モバイルアプリクラッシュステータスの監視に言及しているサイトもありました。

平均欠陥検出時間 (MTTD)

 MTTRがはシステムの保守性を表していたのに対し、MTBF(Mean Time Between Failure)はシステムの信頼性を表現するメトリクスです。
 MTTDはそのアナロジーで、「テスターが次の欠陥にぶつかるまでの平均時間」になります。これはプロダクトの品質・信頼性に依存しますが、テストの質やテストエンジニアの能力にも依ります。

テストの成功率

 実行したテストの成功の割合です。時系列でみると、向上していくのが理想です。終盤で伸び悩んでいる場合は、欠陥をクローズできていないなどの問題があり、危険の兆候です。
 もちろん、テスト側に問題があることもあります。テストの期待値が誤っている、テストが壊れている、など。

ビルドの成功率

 「最後のビルド失敗からの日数」「ビルド連続失敗回数」などで表現するもので、ビルドプロセスが安定しているかの指標になります。
 システムテストに入る前のコードに問題がないか、チームのホワイトボックステストのやり方に問題ないかといった観点での改善につながります。

メトリクスの扱い方

 さて、アジャイルに限ったことではありませんが、メトリクスには以下のような注意点があります。

  1. 報告される側は、個人の評価に使わない。
  2. 報告する側は、取り繕うためにデータを歪めない。
  3. 収集に手間がかかりすぎるものは避ける。できるだけ自動で取得・集計・表示できるように。

 またこちらのページでは、短期と長期に分けて、ダッシュボードで見える化することを勧めています。
 メトリクスの例は、以下の通りです。

  • 短期 ビルドの成功率、自動テストの成功率、、バーンダウンチャート、追加された致命的バグ、未解決な致命的バグ、・・・
  • 長期 テストの失敗率、テストの数、ベロシティ、種類別バグ、・・・

www.slideshare.net

おわりに

 一通り紹介してみましたが、いかがでしょうか。
 もともとの動機が「品質に関わるメトリクス」だったので、偏りがあると思います。進捗を表すメトリクスが2つしかないし、コストに関しては1つも書いていません。実は、EVM(Earned Value Management)をアジャイルに適用する試みについての記事も読んだのですが、割愛しています。

www.infoq.com

 みなさんのチームで使われているナイスなメトリクスも教えていただきたいです。特に品質!

追記

 Twitterなどで寄せていただいた有益なサイトへのリンクです。

https://www.slideshare.net/oota_ken/agile-mericswww.slideshare.net

 辰巳さんからご紹介いただいた、SHIFTの太田さんのスライド。よっぽどちゃんとまとまっていました・・・。

www.slideshare.net

 LINEの伊藤宏幸さんの資料(楽天在籍当時)。Twitterで言及していたところ、ご本人に紹介いただきました。ありがとうございます。
 CFD、スループット、サイクルタイム、リードタイムなどに言及があります。

www.slideshare.net

 こちらも伊藤さんの資料。実際に現場で適用した内容なので、説得力が違いますね。
 また、メトリクスの悪化やボトルネックを発見したときも、対処は1つだけではないということを教えてくれます。

参考サイト

 本文中で直接言及していない記事・資料について、以下に列挙します。

reqtest.com www.getzephyr.com

www.slideshare.net www.slideshare.net www.slideshare.net www.atlassian.com www.testdevlab.com https://www.testingexcellence.com/how-do-we-measure-software-quality-in-agile-projects/www.testingexcellence.com Agile Metrics - What You Need to, Want to, and Can Measure(PDF) www.capriconsulting.co.uk http://www.everydaykanban.com/2016/09/25/flow-efficiency/www.everydaykanban.com

 まだ読み切れていないものも参考までに・・・。

implementingagile.blogspot.jp www.scaledagileframework.com www.swtestacademy.com techbeacon.com nesma.org

*1:メトリクスの複数形は「metrics」なのに、勘違いしてURLを「metrix」にしてしまい泣きたい。

*2:最初「metrix」と書いていたのを修正しました、しかしカスタムURLには残っている、恥しかない・・・。

JSTQB-TTAシラバスのお勉強 ─ 第2章「構造ベースドテスト」(1)

 TTAシラバスの第2章「構造ベースドテスト」は非常に謎めいた構成で、2.2から2.6までがコードカバレッジの話なのに、2.7が突然「APIテスト」なのです。なんだかとてもバランスが悪い印象なのですが、とにかく進むしかありません。
 あと「based」の訳が当初「ベース」と「ベースド」で不統一だったことから現在は「ベースド」に統一されていますが、さすがに「漢字熟語+ベースド」にはギャグ感があります・・・。

2 構造ベースドテスト

 構造ベースドテストは、シラバスに

テスト設計のベースとして、コード、データ、アーキテクチャ、およびシステムフローを使用する。

とあるように、プログラムの中身からテストを作っていく方法です。
 第2章で説明されるコードカバレッジについては、以前の記事で自分なりの整理をしました。詳しくはそちらを参照!ということで、個々で気になる点だけ補足していきたいと思います。

www.kzsuzuki.com

2.2 条件テスト

 対応するコードカバレッジは、条件網羅です。「判定」と「条件」がなんとなく似ているので混乱しがちなのですが、「条件」(condition)は不可分な命題です。∧や∨を含みません。「判定」(decision)は、条件やその組み合わせを評価した結果のブーリアンです。

 条件網羅はあまり実用的な意味のない概念だと思います。
 たとえば条件100個からなる、こんな判定を考えてみましょう。

(条件1 ∧ 条件2 ∧ ... ∧ 条件99) ∨ 条件100

 考えられる組み合わせは2100個ありますが、この場合に条件網羅を100%にするには、

条件1~99 = True、条件100 = False 条件1~99 = False、条件100 = Ture

の2つでOKです。一方、この2つのテストケースでは判定がともにFalseになるので、Trueの場合を実行できず、判定網羅は50%になってしまいます。

2.3 判定条件テスト

 対応するコードカバレッジは、判定網羅です。
 制限/注意事項としては「テストケースの増加」に言及していますが、条件網羅が保証されない点も重要でしょう。
 シラバスの表を少し書き換えて以下のようにしても判定網羅は満たされますが、条件網羅は満たされていない(条件AがFalseの場合がカバーされていない)ですね。

#ABA and B
1TrueTrueTrue
2TrueFalseFalse

2.4 改良条件判定カバレッジテスト

 対応するコードカバレッジは、改良条件判定カバレッジ(MC/DC)です。そのままですね。

定義が難解

 それにしても、シラバスの以下の文章は理解が難しいです。

N個の一意な不可分条件を想定した場合、MC/DCは通常、N+1個のテストケースで実現できる。MC/DCは判定条件カバレッジを達成するが、次の要件も満たす必要がある。
  1. 不可分条件Xが真になると判定結果が変わる1つ以上のテスト
  2. 不可分条件Xが偽になると判定結果が変わる1つ以上のテスト
  3. 各不可分条件に、上記の要件1と要件2を満たすテストが存在する。

 かみ砕いていうと、「その条件の真偽値が変わることで判定全体の真偽値が変わる」場合、そのテストケースはやっておけということ。裏を返すと、「その条件の真偽値が変わっても判定全体の真偽値が変わらない」のであれば、そのテストケースはやらなくていい(判定網羅を満たす範囲であれば)。

 TechMatrix社のページには以下のようにあります。こちらの1.は判定網羅、2.は条件網羅なので、シラバスの3つの項目が、3.の1文にまとめられていることになります。

DO-178Bに従うと、完全な(100%の)MC/DCカバレッジを得るには、次の3つの条件を満たす必要があります。
  1. 各「判断文」が、少なくとも1回すべての可能な結果を得ている。
  2. 1つの「判断文」中の各条件が、少なくとも1回すべての可能な結果を得ている。
  3. 1つの「判断文」中の個々の条件が、単独で全体の「判断文」の結果を左右する。

www.techmatrix.co.jp

具体例

 シラバスに示された、MC/DC=100%の例で確認してみましょう。

#ABC(A ∨ B) ∧ C
1TrueFalseTrueTrue
2FalseTrueTrueTrue
3FalseFalseTrueFalse
4TrueFalseFalseFalse
  • 条件A・B・Cが、TrueとFalseの両方の値をとるテストケースがある(条件網羅)
  • 判定結果 (A or B) and C が、TrueとFalseの両方の値をとるテストケースがある(判定網羅)
  • テスト1はAがTrueで判定がTrue。テスト3ではAだけをFalseに変えて、判定がFalseになっている。
  • テスト2はBがTrueで判定がTrue。テスト3ではBだけをFalseに変えて、判定がFalseになっている。
  • テスト1はCがTrueで判定がTrue。テスト4ではCだけをFalseに変えて、判定がFalseになっている。

 確かに、満たされているようです。

どうやって導出するのだ?

 さて、ではどのようにMC/DCを満たすテストケースを導出するのか。シラバスには書かれていません。「MC/DCは通常、N+1個のテストケースで実現できる」の根拠もわかりません。
 ネットを調べてみても(論文は調べていません!)、「これはMC/DC100%のテストケース群ですよ」といきなり「答え」が出ているものばかり。TechMatrix社のツールではMC/DCのカバレッジ分析ができるとのことなので、論理的に導出できるのではないかと思うのですが・・。。

 唯一希望を持てるのは、キャッツ株式会社のWebサイトで読める「ZIPC WATCHERS Vol.13」の記事「組込みソフトウェア開発課題への挑戦~網羅度~」(PDF)です。ここに以下の記述があります。

MC/DCテストケースを最小化する方法、MC/DCランダムテストに確率値誤差逆伝播法(バックプロパゲーション)を用いる方法については、別稿で述べる。→リンク先:松本

 でも「リンク先:松本」が見つからない・・・
 と言いますか、ん? バックプロパゲーション? ディープラーニングでちらっと勉強したあれ? 気になりすぎるのですが、とりあえず発見できませんでした。

導出方法を勝手に考えてみる

 ここからはあまり根拠のない話なので、冷やかし程度で読んでください。

 先の記述の、「ランダム」「最小化する」という言葉を見るに、MC/DCの場合は論理的に導ける唯一解があるわけではなく、何らかのランダム性を入れて、そこから最小な群を見つけていくアプローチなのでは、と想像しています。

 では自分なりにその方法を考えてみましょう。

 まずOR文。「または」なので、2つ以上の条件がTrueの場合、どれが独立にFalseに変わっても、OR文全体の結果は変わりません。
 次にAND文。「かつ」なので同様に、2つ以上の条件がFalseの場合、どれが独立にTrueに変わっても、AND文全体の結果は変わりません。
 よって、テストケース削減の方針として、以下2つを挙げることができるでしょう。

  • 方針1: OR内で複数条件がTrueになっているテストケースは省略する
  • 方針2: AND内で複数条件がFalseになっているテストケースは省略する

 では、シラバスの例である (A or B) and C について考えてみましょう。真理値表は以下の通りです。

#ABC(A ∨ B) (A ∨ B) ∧ C
1TrueTrueTrueTrueTrue
2TrueTrueFalseTrueFalse
3TrueFalseTrueTrueTrue
4TrueFalseFalseTrueFalse
5FalseTrueTrueTrueTrue
6FalseTrueFalseTrueFalse
7FalseFalseTrueFalseFalse
8FalseFalseFalseFalseFalse

 方針1から、AとBが両方Trueになっているテスト1と2を落とします。次に方針2から、(A ∨ B)とCが両方Falseになるテスト8を落とします。
 残るのはテスト3・4・5・6・7です。

 テスト3とテスト7は、条件Aを反転することで結果が反転しています。
 テスト4とテスト3は、条件Cを反転することで結果が反転しています。
 テスト5とテスト7は、条件Bを反転することで結果が反転しています。
 テスト5とテスト6は、条件Cを反転することで結果が反転しています。  

 条件Aの反転と条件Bの反転のために、テスト3・5・7は必須。あとは条件Cのために3・4を選ぶか、5・6を選ぶか。
 シラバスでは前者の3・4・5・7のパターンになっていますが、3・5・6・7でもMC/DCを満たしているといえるのではないでしょうか。なお、判定条件網羅はともに満たしています。

■シラバスの解

#ABC(A ∨ B) ∧ C
3TrueFalseTrueTrue
4TrueFalseFalseFalse
5FalseTrueTrueTrue
7FalseFalseTrueFalse

■別の解

#ABC(A ∨ B) ∧ C
3TrueFalseTrueTrue
5FalseTrueTrueTrue
6FalseTrueFalseFalse
7FalseFalseTrueFalse

 自力の導出方法として、この程度が限界でした。何かスマートなやり方あるんだろなあ。
 長くなってきたので、第2章の残りは別途。

#JaSST '18 TokyoのMicco氏のチュートリアルを復習し、少しデータで遊んでみる

 GoogleのテストマネージャーであるJohn Micco氏の、Flakyなテストについてのチュートリアルの内容は、こちらに書き尽くされています。なので、あらためてその復習記事を書くことはないのだけれど、SQLの勉強も兼ねて、要点を絞って振り返っておきます。

nihonbuson.hatenadiary.jp togetter.com 

 Micco氏のお話の要点は、以下の2つだとわたしは考えています。

  1. 自動テストが膨大になると、効率よい順番で実行したり、適切に間引いたりすることが重要である。
  2. シンプルな記録であっても、積み重ねればさまざまな洞察を導くことができる。

 この記事では、上述の2つを踏まえてチュートリアルを振り返るとともに、せっかく権限をもらったGoogleさんのログで、少し遊んでみたいと思います。

膨大な自動テストの効率を上げるには

 Micco氏の資料*1によると、Googleで継続的に実行されている420万件あり、1日あたりテスト実行が150万回とのこと。
 一方、バグが見つかるのはわずか1.23%のテストだけ。膨大なリソースを使うことから、テストを効率的に実行することが求められます。

 テスト結果を分析する中で、Micco氏はテストの結果の遷移(transision)に注目。過去にpassしていたテストがある時点でfailに変わるネガティブな遷移は、テストがflaky(あてにならないもの)であることが原因の1つであることがわかりました。flakyなテストについて、スライドでは以下のように述べられています。

  • flakyなテストとは、同じコードであるにも関わらず、passになったりfailになったりするテストのこと。
  • 420万件のテストのうち、16%が何らかのflakinessをもっている。
  • flakyなテストの結果の確認に、開発者の時間が浪費される。そのため開発者は無視しがちだが、その判断が誤っていることもある。
  • flakyなテストの(再)実行のために、2~16%の計算リソースを使っている。
  • flakyなテストは、進捗を阻害したりリリースを遅らせたりする。

 この無駄を減らすことが、自動テスト実行の効率改善の大きな助けになるというのがモチベーションです。 

Flakyなテストを見つけるには

 チュートリアルで教えてもらったのは、どのようなデータをどう使って分析しているか、ということです。

どんなデータを使う?

 実はこの目的に必要なデータベースは、次のシンプルな2つのテーブルです。targetsはテストケース、resultsはテストケースの実行結果と、ざっくり捉えてよさそう。

■targets

idINTEGERREQUIRED テストのID
targetSTRINGREQUIRED テストケース(のディレクトリパス。これでテストが一意に決まっているようだ)
flagsSTRINGREQUIRED テスト環境などの情報をフラグ化したものの組み合わせ

■results

target_idINTEGERREQUIRED テストのID
changelistINTEGERREQUIRED プログラム変更リストのID
resultSTRINGREQUIRED 実行結果
timestampTIMESTAMPREQUIRED タイムスタンプ

 resultsテーブルの「result」に入るのはテストの結果で、以下のようなものがあります。一部内容を聞いていないものもあります。

  • AFFECTED_TARGET
  • PASSED: 成功
  • SKIPPED
  • FAILED_TO_BUILD: コンパイルできずチェックイン不可
  • FAILED: 失敗
  • INTERNAL_ERROR: テストを開始する前提が満たされなかった。テストインフラの問題
  • PENDING: 実行開始できなかった
  • FLAKY: 一度のテストの中で、初めは失敗したが、リトライで最終的には成功したもの
  • ABORTED_BY_TOOL: 実行時間の閾値15分オーバーによる実行停止
  • FORGE_FAILURE
  • BUILD_TIMEOUT
  • PROHIBITED
  • BLACKLISTED

 このように結果を細かく分けることで、テストの問題なのか、インフラの問題なのかを切り分けやすくし、開発者とテストインフラチームがお互い時間を浪費しないように工夫しています。

 わたしのチームでもテスト失敗の要因は区別していて、自動テストインフラのどこに改善ポイントがあるのかがわかるようには、一応しています。
 プロダクトのバグ起因、自動テストケース起因、テスト環境起因、人の凡ミス、前のテストの影響が残ってしまった、などなど。
 Googleとの大きな違いは、この分類を、ほぼ人がやっているということで・・・スケールしないですね。

結局flakyって?

 チュートリアルの中では、flakyを2つの意味で使っているように感じました。
 1つ目はテスト結果の種類としてのもので、「1回のテスト実行の中で、最初は失敗したが、リトライで成功している」ことを指しています。2つ目はテスト結果の変化の種類としてのもので、「ある時に成功したが、次の実行の際には失敗した」ことを指しています。
 でもこの2つって本質的には同じで、結果の変化が1回のテストの中で起こったか、2回のテストの中で起こったかの違いだけなんですね。

 よって現時点では単純に、「同じコードで同じ結果を期待しているのに、結果が変わってしまう」ものだと捉えています。

遷移するテストを見つける

 チュートリアル最初は、resultsのレコード件数は?みたいなシンプル過ぎる練習クエリを投げていたのですが、遷移するテストを特定するクエリから、以下のようにややこしくなってきます。(MiccoさんのGitHubから引用しています)。

 以下読み解いてみますが、解釈が間違っていたり言葉遣いがおかしければご指摘ください。
 まず、WITH句で、サブクエリ「result_values」を生成しています。resultsテーブルを並び替えたもので、こんな感じ。*2

Rowrowtarget_idchangelistresult
2602601100515424AFFECTED_TARGET
2612611100518994AFFECTED_TARGET
2622621100519320AFFECTED_TARGET
2632631100520152AFFECTED_TARGET
2642641100522728PASSED
26512100005012AFFECTED_TARGET
26622100020333AFFECTED_TARGET

 PARTITION BYによって、target_idごとにレコードを区分し、changelistでソートしたうえでrow列でナンバリングしています。
 「区分」されているため、target_idが変わるとナンバリングが1から再スタートするというところがポイントです。264行目まで増加していたrowが、265で1に戻るのはそういうわけです。

 WITHが終わった後のSELECTでは、上で作ったテーブル result_valuesを、自分自身と結合します。結合の条件は、①target_idが一致している ②rowが1個ずれている。
 target_idとrowを指定すればレコードは一意に決まりますね。上のテーブルだと、たとえばRow260をRow261と、Row261をRow262と、1行ずらしで順に結合していくことになります。イメージ的には、以下。

changelistresultchangelistresult
100515424AFFECTED_TARGET100518994AFFECTED_TARGET
100518994AFFECTED_TARGET100519320AFFECTED_TARGET
100519320AFFECTED_TARGET100520152AFFECTED_TARGET
100520152AFFECTED_TARGET100522728PASSED

 WHERE句で、resultが一致していないものを抽出すると、1番下の行だけが残ります。これって、「あるテストと次のテストで結果が違う」、つまり遷移を表していますね。さらにこれをtarget_idでグルーピングして、遷移が4回以上起きているものを残す。とこういうことをしていたんですね。
 まあややこしかったけれど、遷移がよく起きるテストケースを特定することができました。

Rowtarget_idtransition_count
184818481
229299458
370376429
471932425
592007416

遷移の歴史を見抜く

 さて次の問題は、「flakyに見えるけれど実はflakyじゃなかった」遷移をどのように見抜くか、ですね。

 1つの仮説として、それぞれのテストのflakyさ≒遷移のパターンは、独立しているはずです*3 。逆に、複数のテストが同じような遷移の履歴を示すのであれば、それはテスト以外のものに由来する問題である可能性が高い。Micco氏はそのよ1うな現象の原因として、サブシステムやライブラリの問題を挙げていました。
 テスト自体がflakyなわけではないことが明確になれば、テストインフラ側の問題として引き取ることで、開発者の調査の工数を減らせそうです。

 まず事前準備として、先ほどのクエリを少し変えて、以下のようなテーブル「target_transitions」を作っておきます。遷移が起こった際のchangelistとtarget_idの組み合わせ表です。

Rowchangelisttarget_id
110000000117341
210000000128661
3100000001183752
4100000001228506
5100000001259831

 このテーブルに対し、以下のクエリを投げる。

 ざっくりいうと、target_idでグルーピングしたうえで、そこに紐づくchangelistをarray_agg関数で配列にしている。結果がこれです。

Rowtarget_idchangelists
1424100437692
100437728
100446646
100452444
1434100031939
100036158

 上の表でいうと、(424, [100437692, 100437728, 100446646, 100452444]) みたいになっているってことですね。つまり、「テストケース、遷移歴」のテーブルになっているってことですよ。
 この遷移歴が一致するテストケースが多ければ、その遷移・flakyさは、テスト自体と違うところに起因する(可能性が高い)といえるわけですね。
 この結果から、遷移する22,760のうち、1,610が遷移歴を共有していることがわかりました。これらはFlakyではないと判断できそうです。

Google先生のデータで遊ぶ

 さて、シンプルなデータですが、いろいろできそうな気もしますよね?
 少しだけ遊んでみました。

遷移回数を正規化する

 上で出た「flaky_tests」テーブルですが、内容は「target_id」(テストケース)と、「transision_count」(遷移回数)です。でもこれだと、実行回数が多いテストと少ないテストを公平に比較できないのでは?と考えるのが自然ですよね。
 実行回数はすぐ得られるので、遷移回数/実行回数 で正規化してみましょう。
 クエリはこんな感じか・・・?

Rowtarget_idexecution_counttransition_countflake_ratio
14956292068.97%
27764441636.36%
38881892224.72%
4545421419.05%
56792891617.98%
6434132518614.04%
76456132517212.98%
86031125414811.80%
98769102411210.94%
102468154414809.59%
11407389808.99%
12593745408.89%
1369021691408.28%
147811307118005.86%
1549018484004.72%
161529262912204.64%
17709189404.49%
187367280610103.60%

 さっき1位だった434は6位に、2位だった7811は14位に、3位だった6456は7位に。ランキングはそれほど変わらないかな?

Googlerの人たちのホワイトさを調べる

 テストと結果のテーブル以外に、「TensorFlowCommits」というコミット履歴のデータがありました。どんな言語でよくfailするのかを、修正対象となったファイルの拡張子から判断したりしています。
 チュートリアルで、「誰がよくfailを引き起こしているのか」という分析もあったのでですが、「いや、むしろ何時ごろの修正がfailを引き起こすのか、の方が面白いのでは!?」と。ただ残念ながら、コミット履歴のテーブルの一部が匿名化されており、またテスト結果のテーブルと結合できるキーもないため・・・、一気にスケールダウンし、「googlerは何時にコミットしているのか」を見てみましょう。クエリはたぶんこんな感じ・・・。

 この結果をグラフにすると、こう。いきなりExcelですけれど。

workingHour

 7時ごろに急に立ち上がりはじめ、昼前にピークを迎え、昼休憩をとった後16時ごろにもう一度ピークを見せて、17時ごろから急減。
 ただ、意外に、夜中働いていらっしゃる・・・。人間以外のコミットがあったりする、のでしょうか?*4

まとめ

 基調講演やチュートリアルで学んだことは、膨大なテストの効率的な実行が必要だけれど、ヒントはシンプルなデータの中からも得られる、ということでした。
 何億件というデータはGoogleならではですが、使っている情報も、ロジックも、とてもシンプルと言えるのではないでしょうか。
 自動テストはログの蓄積と相性がいいので、自分なりのメトリクスを考えるのは楽しそうですし、効果も見込めそうなので、仕事の中で何か見つけてみたいと思っています。
 Miccoさん、ありがとうございました! 謝謝!

*1:The State of Continuous Integration Testing @Google (pdf)

*2:実際は「AFFECTED_TARGET」は除外されている。

*3:実際のところ、20回同じタイミングで遷移するような組み合わせは、わずか2つしかなかったそう。

*4:@nihonbuson さんに、「多拠点開発だからなのでは?」とのご指摘いただきました。なるほどー。