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

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

モノリシックなテストケースという概念を考えてみる

The Monolith. Vigeland sculpture park. Oslo

 TEF道(Test Engineer's Forum 北海道)のメンバーと、「テストケースの実行効率と説明責任」というテーマでディスカッションしていた頃からつらつらと考えていたアイデアのメモです。朝一の殴り書きなので、雑はご容赦。議論のきっかけになると嬉しい。

 なおその時の議論の一部をInSTA(International Workshop on Software Test Architecture)の発表資料にし(てくれ)たものがコチラ

 なお、Twitterでの以下の会話もキッカケになっています。

モノリシック/アトミックなテストケース

 美しいテストケースはどれも似たものですが、汚いテストケースはいずれもそれぞれに汚いものです。
 とはいえ、テストケースを汚くする要素の一つに、「何でも詰め込み過ぎ」というものがあるということには異論ないでしょう*1。一つのテストケースでいっぺんにいろいろ確認しようとするあまり、長大で複雑な、全体としてよくわからない内容になってしまうことがあります。

 一方で、一つのテストケースが一つのことだけを確認するようにデザインされたテストケース群もあります。こちらはテストケースとしての見通しがよく、後述するように保守性も相対的に高くなりそうです。

 ソフトウェア界隈の言葉を借用するなら、前者は monolithic(モノリシック)であり、後者は atomic(アトミック)と表現してもいいかもしれません。
 その明確な定義はちょっとおいておくとして、まずモノリシックなテストケースの特徴について整理してみます。  

モノリシックなテストケースはなぜ生まれる?

 そもそも、なぜテストケースはモノリシックになっていくのでしょう。
 一つは、「効率よく実行したい」というモチベーションです。

 よく分割された*2テストケースは、それぞれが短い一方で、テストケース間のステップの重複も発生しがち。なぜなら、テストケース間の依存関係を低くするために、各テストケースを独立して開始/終了できるようにするためです。たとえばWebアプリケーションを考えてみると、ほぼすべてのテストケースで「ログイン」「ログアウト」が発生するといった具合です。
 その他にも、テストケースの長時間化の原因となるステップ、たとえば「システム障害」が複数のケースに入っていたりすると、「いっぺんに確認したい」誘惑が強くものです。一度の「障害」で、いっぺんにいろんな挙動を確認した方がよさそうに思えますから。

 手動テストにおいて、こういうテストケースの実行を効率化するには以下の二つの方法があります。

  1. テストケース自体はそのままにして、確認ポイントと関係ないステップを省略する。たとえば、ログアウトしないまま次の確認項目に進む
  2. テストケースを「統合」することで、一度のログイン/ログアウトでたくさんの確認項目を消化できるようにする

 この2.を選んだ場合、アトミック性を下げることになります。またこの先、別のテスト観点が追加された場合にも同じ「統合」 が行われ、そのテストケースがさらに肥大化しがちです。 

モノリシックなテストケースの特徴

 モノリシックなテストケースの困った点について述べていきます。

テストケースの見通し

 テストケースのアトミック性が高いと、何を目的としたテストなのかが読み取りやすいです。
 もちろん適切な情報(たとえばテストコードの名前、ヘッダ、コメント)がテストケースに与えられていることが望ましいですが、テストステップ/テストスクリプトを読めばやりたいことがおおむねわかる。

 モノリシックなテストケースでは、それが途端に難しくなります。
 観点を詰め込むために不自然な流れになっていることもあり、「やたら長いけれど、ユースケーステストになっているのかといえばそうでもない」ようなテストケースが生まれがちです。

テストケースの保守性

 見通しが悪いと、テストケースを直すことも難しくなります。各ステップの必要性が見えづらく、ステップ間の関連性も複雑になっているためです。
 やたら迂遠な流れになっていても、その流れが必然のものなのか、建て増しによる弊害なのかが判断しづらい。迂闊に触ることができないので、「最適化」が妨げられます。「最適化」した結果、実は一部の観点の確認が失われていた、あるいは確認になっていなかったということが起こりえます。恐ろしいことに、それに気づけない可能性が高い。

 同じ理由で、あるテスト観点が不要となった場合も、そのテスト観点を大きなテストケースから「剥離」することは難しくなります。効率化したつもりが、その逆の効果を生んでしまうわけです。 

テストケースのトレーサビリティ

 観点の集合体になってしまったモノリシックなテストケースでは、「もともと確認したかったこと」とのトレーサビリティが失われることがあります。
 アトミック性の高いテストケース10個を一つの(モノリシックな)テストケースにパックしたうえで、その「大きなテストケース」のステップや確認項目が変化していくと、元の10個をトレースすることが難しくなっていきます。すると、「この10個の観点は、このテストケースで確認できているはず」という信念だけが残り、実際に確認できているかは実はあいまいということになります。

自動テスト失敗時の対処

 まず単純に、モノリシックで長大なテストケースをそのまま自動化すると、テスト実行時間が相対的に長くなります。このテストケースが fail となった場合、それまでかかった時間が無駄になってしまいますし、複数の観点のうちどれが確認済みで、どれが未確認なのかをいちいち調べる必要が出てきます。

 アトミック性が高いテストケースであれば、fail したときのダメージが比較的低いです。短くてシンプルなテストケースなので、やり直しも簡単です。
 ただし、多くのテストケースに共通するような根本部分にバグがあった場合は話が変わってきます。自動実行を制御しておかないと、「ほぼすべての自動テストケースが fail する」という事態になってしまいます*3

テスト管理の容易性

 テスト管理ツールなどを使って、テストケースに属性情報を付加している場合を考えてみましょう。
 たとえば「品質特性」とか「テスト観点」といったラベルを使っているとして、アトミック性の低いテストケースには、このラベルが大量に貼られることになります。

 リグレッションテストにおいて最低限確認したいテストケースを、これらのラベルを使って絞り込もうにも、多くのテストケースに多くのラベルが貼られているため、有効な絞り込みができない、という弊害が考えられます。

まとまっていないけど、まとめ

 目的、テスト観点を詰め込み過ぎた「モノリシックなテストケース」について簡単に考えてみました。
 名前があると議論がしやすいのと、あとなんとなく monolithic test cases とかいうとかっこいいからです。

 プログラム設計のアナロジーを使って「責務の分担」「凝集度」「結合度」といった概念も流用して、テストケース(群)の品質特性を考えることができるのかもしれません。こういうの楽しいですよね。

*1:テストケースの「美しさ」「汚さ」とその要素という議論自体、面白そう。

*2:well-devided とかいうとかっこいい

*3:とはいえ、自動テストのコケた範囲から、バグを埋め込んでいる個所を特定するという技術はありそう。

Test Procedure(テスト手順)とは何か

Footprints in the Sand

 ソフトウェアテストの用語「テスト手順」についてのメモ。

 ミスアンダスタンダビリティが高すぎるよね。

「手順」は、テストケースの属性ではない

 まず大前提として、ISTQBやISO/IEC/IEEE 29119でいう「テスト手順」は、「単一のテストケースをどのように実行するかを記述したもの」を指すものではありません

A sequence of test cases in execution order, and any associated actions that may be required to set up the initial preconditions and any wrap up activities post execution.

 この「test cases」がポイントですね。二つ以上のテストケースを、実行の順番に並べたもの、です。
 では、「単一のテストケースをどのように実行するかを記述したもの」を指す言葉は定義されていないのでしょうか。ISTQBや29119の用語集をパッと見た感じでは、見当たりません。何か理由はあるのかしら。

 とはいえこれに相当する言葉がないのは不便でしょう。
 たとえばPractiTestなどテスト管理ツールでは、「ステップ(step)」という用語を使うことが多いようです。

www.kzsuzuki.com

 「テストケースステップ」と呼べば多くの人が同じものをイメージできそうですが、若干冗長かな。
 だからみんなで使っていこう、「テストステップ」!  

process と procedure

 test procedure とは別に、test process という用語もありますね。
 まず procedure と process の定義を、ISO 9000(JIS Q 9000:2015)で確認してみます。こちらのサイトを参考にしました。

3.4.1 プロセス(process)
インプットを使用して意図した結果を生み出す,相互に関連する又は相互に作用する一連の活動
注記 1 プロセスの 意図した結果 を,アウトプット,製品又はサービスのいずれと呼ぶかは,それが用いられている文脈による。
注記 2 プロセスへのインプットは,通常,他のプロセスからのアウトプットであり,また,プロセスからのアウトプットは,通常,他のプロセスへのインプットである。
注記 3 連続した二つ又はそれ以上の相互に関連する及び相互に作用するプロセスを,一つのプロセスと呼ぶこともあり得る。

3.4.5 手順(procedure)
活動又はプロセスを実行するために規定された方法。

 プロセスは、インプットを処理してアウトプットにするためのハコ。
 手順はそのハコの中身というイメージですね。

test process
provides information on the quality of a software product, often comprised of a number of activities, grouped into one or more test sub-processes
ソフトウェアプロダクトの製品の品質についての情報を与える。たくさんの活動から構成され、それらが一つ以上のサブプロセスとしてまとめられることもある。

 まあ、この定義は「プロセス」という言葉に着目したものではないですね。
 テストケースとは直接関係なく、「活動のかたまり」として説明されています。

DDP(欠陥検出率)とは何か。

Jenga

 秋山浩一さんがTwitterで、DDP(Defect Detection Percentage、欠陥検出率)の良さについて言及されていました。

 わたしがDDPについて初めて知ったのは、『システムテスト自動化標準ガイド』の翻訳をしているときです。おっと、ついアフィリエイトリンクが・・・。

システムテスト自動化 標準ガイド (CodeZine BOOKS)

システムテスト自動化 標準ガイド (CodeZine BOOKS)

 DDPについては、メトリクスとしては知っていても実際に使ったことがないので、少し調べ直してみました。

DDPの定義

 こちらは秋山さんのツイートの中で説明されている定義です。

DDP値=検出バグ数÷当初保有バグ数×100

 『標準ガイド』の著者の一人であるDorothyさんは、JaSST'13 Tokyoでの講演の中でDDPに言及していますので、聴講レポートから引用してみましょう。

www.kumikomi.net

欠陥検出率は,テスト・フェ-ズで摘出した欠陥の数を,テスト・フェ-ズおよびリリース以降の別のフェ-ズで見つけた欠陥の総数で割った値のパーセンテージで示される.

 分母になる数字として、「当初保有バグ数」も「テスト・フェーズおよびリリース以降の別のフェーズで見つけた欠陥の総数」も、すんなり読むと間違えると思います!
 これらの意味は、そのテストフェーズが始まった時点で残存しているバグの数、ということです。裏を返すと、そのフェーズより前に見つかったバグの数は、式には現れません

具体的な値で計算してみる

 テスト開始から現在までで、バグの全数が535件だったとしましょう。
 で、各テストフェーズで以下のようにバグを検出したとします。

f:id:kz_suzuki:20200208123410p:plain

 CT(コンポーネントテスト)では、405件見つけています。535件のうち405件を検出したので、DDPは 405 / 535 = 75.7% ということになります。

 33件を検出したIT(統合テスト)ではどうでしょう。
 計算式は、33 / 535 ではありません。33 / 130 で、74.6% です。
 33というのは、535 - 405、つまりCTを経てITまで流れ込んできたバグの数、ですね。名前を付けるなら「当該フェーズ開始時潜在バグ数」などとなりますが、長すぎる・・・。ここでは「当初保有バグ数」をこのまま使います。
 最終的なバグ数に対して各フェーズで検出した割合、ではないので注意が必要です。

 上表からは、以下のようなグラフが得られます。

f:id:kz_suzuki:20200208123617p:plain
バグ検出とDDP

 帯グラフの高さが、当初保有バグ数です。薄いグレーはそのフェーズで検出したバグ数。濃いグレーはそのフェーズでの残存バグ数であり、次のフェーズにとっての「当初保有バグ数」になります。

 当初保有バグ数(分母)は、後ろのフェーズになるほど小さくなるので、検出されたバグの数(分子)に敏感になり、DDPを高く保つのが難しくなりそうです。

 なお「リリース後」のDDPは意味ないですね。常に100%になります。

全数とは・・・

 さて、この時点でだいぶ大きな違和感があるでしょう。
 そう、「バグの全数って何だよ」という点。

 それは未知の数なので、「現時点の累積」で代替するしかなさそうです。そのため、あるテストフェーズ完了時点では、DDPは100%になります。次のフェーズが始まって新しいバグが検出され始めると、「当初保有バグ数」が増加方向に修正されるので、DDPは下がっていくことになります。

 先ほどのフェーズ別の検出数を日々の検出数に開いたのを以下の表として、

f:id:kz_suzuki:20200208123927p:plain
日々の検出バグ数

 DDPの推移をグラフにしてみました。

f:id:kz_suzuki:20200208124016p:plain
各テストのDDP推移

 CTが終わる1月12日まではDDPは驚異の100%を誇っていますが、13日からのITでバグが検出されると分母が増え(そして分子が変えられず)、DDPが低下していきます。IT、ST(システムテスト)、AT(受け入れテスト)も同様ですね。
 特にATは、完了時点で分母が6だったものの、リリース後に4件バグが出てしまったため、DDPは60%に低下してしまいました。時間経過は加味されないので、このバグがリリース直後に出ても、リリース1年後に出ても、結果は同じです。

欠陥密度と似ているところ、違うところ

 「欠陥密度」は、検出バグ数を開発規模で割ることで得られるメトリクスです。「毎回の開発において、欠陥密度は同じような数字に収束するだろう」という仮定に基づき、開発前に定めた目標値の実際の値を比較して、テストの十分性の一助に使います。

 欠陥密度とDDPは、分子が検出バグ数であるという点は同じです。
 分母について、欠陥密度の分母は開発規模であり、定義が決まれば一意に求められる値で、わかりやすい。
 ただし、「開発規模とバグ数はおおむね比例する」という仮定や、プログラミング言語、開発スキル、プロダクトの性質といった条件が同一であることも(暗黙の)前提になるため、場合によっては納得感の低いメトリクスとなります。

 DDPは当初保有バグ数を分母として「見つけたバグの割合」を求めることになるので、欠陥密度で前提したようなことはそれほど加味しなくてよく、さまざまな開発で横断的に使える可能性があります(すみません、実践していないのではっきり言えない・・・)。
 しかし上述の通り、分母の「真の値はわからない」という本質的な問題をはらんでいます。テスト完了時点では DDP = 100% になりますので、リリース後「一定期間」待ったうえで、DDPを再度確認することになります。「期間」はプロダクトに依存しますし、待ったところでやっぱり真の値はわからないのですが。

 一方、テスト完了時点で、各テストフェーズのDDPが(暫定的とはいえ)見えているので、各フェーズが健全に行われたかの判断に使うことはできそうです。ITフェーズに入って、その前フェーズであるCTのDDPが急激に下がっていくようであれば、

  • CTフェーズでのテストが足りていない
  • ITフェーズに対応する設計や実装に問題がある

といった可能性を疑うことができます。

 二つのメトリクスの共通点として、「高ければいい、低ければいい、と単純にいえない」というものもあります。
 欠陥密度が低いのは、プロダクトの品質がもともとよかったのか、テストが足りていないのか。
 DDPが高いのは、後フェーズでのテストが不十分で、分母が増えていないだけではないのか。
 これは、1つのメトリクスから判断すべきものではありません。メトリクスはあくまでもキッカケでしょう。

DDPの良い効能

 DDPの効能として秋山さんは、「分母を減らそうとするモチベーションが働く」旨を書かれています。

 単純に数字だけを扱うと殺伐としがちですが、メトリクスの改善のためにできることは何かを考え、具体的な施策に落とし込むような文化では、楽しく取り組めそうです。

 また別の観点でちょっと面白いなと思ったのは、あるテストフェーズでしっかりテストしておかないと、以降のフェーズのバグ検出により、そのフェーズのDDPをガンガン下げられてしまうという点です。
 フェーズでチームが分かれていれば、チーム間のゲームのような感じもありますし、チームが同一でもたとえばITでのがんばりがCTのDDPを下げてしまうジレンマを解消するためにCTからしっかりやる、というモチベーションになります。なかなか興味深い性質だと感じます。

アジャイルでは使えるのか

 Dorothyさんの講演によると、テストフェーズをスプリントに読み替えて、DDPを使っているとのこと。
 検出したバグが、どのスプリントで「検出すべき」バグかを調べて記録しているような組織であれば、簡単に使えそうですね。

 以上です。念のためもう一度貼っておきます。

システムテスト自動化 標準ガイド (CodeZine BOOKS)

システムテスト自動化 標準ガイド (CodeZine BOOKS)

「定義」の難しさについてのポエム

WORDS!  #3

 概念の「定義」って難しいなあという気持ちについての雑記。
 きっかけは「testing」という言葉の定義について、ISO/IEC/IEEE 29119 の定義を確認したことです。

 定義は、以下の通り。

set of activities conducted to facilitate discovery and/or evaluation of properties of one or more test items
1つ以上のテストアイテムの特性の発見かつ/または評価を促進するために行われるアクティビティ群

 「ソフトウェアのテスト」と聞いて思い浮かべがちな、quality とか bug とか failure いう単語は、定義には現れないんですね。一方で、testing の定義の中に、test items が来るのはいいのか?という気持ちになる・・。
 そして、この定義を聞いて、ソフトウェアテストを知らない人が「テスト」をイメージすることができるんだろうか、とふと思ったわけです。

 では、言葉の定義に必要なものって何だろうと考えてみると、以下の3つがあると嬉しいのではないでしょうか。

  1. 何であるか(できれば、何でないかも)の簡潔な表明
  2. 関連する他の言葉との関係
  3. 定義に属するものの例

辞書を引いてみる

 デジタル大辞泉である単語を引くと、こんな説明が載っています。

バラ科の落葉高木。

 これだと「植物だな」くらいしかわからないですね。

バラ科の落葉高木。また、その果実。

 情報が付加されて、「果物がなって、その名前でそのまま呼ばれる植物か」と想像できますが、まだまだです。

バラ科の落葉高木。また、その果実。葉は卵円形。4、5月ごろ、葉とともに白または淡紅色の5弁花を開き、のち球状の赤色などの実を結ぶ。

 中間の情報はわたしにとって、対象の絞り込みにまったく役に立ちません。「球状の赤色の実」まできて、「赤い実? これはもしかして」となります。
 全部を引用すると、こうなります。

バラ科の落葉高木。また、その果実。葉は卵円形。4、5月ごろ、葉とともに白または淡紅色の5弁花を開き、のち球状の赤色などの実を結ぶ。甘酸っぱく白い食用部は、花托の発達したもの。ヨーロッパ中部から南東部の原産。日本には明治時代に欧米から紅玉・デリシャスなどの品種が導入され、青森・長野などで栽培。古くは、在来の和林檎などをさした。りゅうごう。《季 実=秋 花=春》「―噛む歯に青春をかがやかす/麦南

 そう、「リンゴ」です。
 この定義は、上述の1~3を備えていますね。

定義を狭めること

 辞書的な定義において「AとはBである」としたとき、A = B ではなく、A→Bという関係になりますよね。
 上のリンゴの定義だと、リンゴであればかならず「バラ科の落葉高木」ではありますが、一方で「バラ科の落葉高木」だからといってそれがリンゴとは限らない。つまり定義は必要条件を提示するにすぎません。Bが粗いとAを絞り込めないので、情報を追加していくことで少しずつ限定していくわけです。
 AやBを集合と考えると、上述の1.は「集合Aを含む集合Bを記述する」ことになります*1

 一方、リンゴの定義において例の上がっている「紅玉・デリシャス」は、「CとはAの一種である」を示しており、C→Aという関係です。
 このCも集合と考えると、上述の3.は、「集合Aに含まれる集合Cを記述する」ことになります。1.と対照的なんですね。

 以下の2つを通じて、Aを少しずつ正確に記述できるようになります。

  • 集合B-Aが空集合になるまで、Aを説明する条件を追加していく。
  • 集合Cが集合Aを埋め尽くすまで、例を追加していく。

 これらは、「定義を狭める」行為だといえるでしょう。

定義を広げること

 一方、「定義を広げる」必要が出てくることもあります。
 たとえば「芸術」を引くと、以下のように定義されています。

特定の材料・様式などによって美を追求・表現しようとする人間の活動。および、その所産。絵画・彫刻・建築などの空間芸術、音楽・文学などの時間芸術、演劇・映画・舞踊・オペラなどの総合芸術など。「芸術の秋」「芸術品」

 では、マルセル・デュシャンの『泉』はどうか。

www.artpedia.asia

 これは美といえるのか。美といえないのであれば、芸術ではないのか。芸術なのだとしたら、「定義を広げる」必要がある。ということになります。「美」という限定的な価値観を一段抽象化し、『泉』を「芸術」の範疇に含めていくわけです。

「品質」の定義では

 単純化しすぎかもしれませんが、「具体的な事物」「モノ」に比べて、「抽象的な概念」「コト」の方が、定義を広めようとする圧力が強い印象があります。

 たとえば「品質」の定義を、秋山さんのブログ記事からコピってみます。

note.com

 Crosby の定義である

要件に対する適合である。

よりも、Weinberg の定義

品質は誰かにとっての価値である。

となっており、一段階抽象化が進んでいるように見えませんか?

 この「広がった定義」のしんどいところは、定義の変遷の経緯や暗黙の前提を備えていない人には、何が何だかわからないということです。
 上述のブログ記事で、秋山さんはこの定義を称賛しています。秋山さんはソフトウェアの品質のプロフェッショナルであり、Weinberg が定義の中で「誰か」という表現を使った意図に思いをはせられるからだと思います。

この定義の素晴らしい点は「誰かにとっての」の部分です。
つまり、品質の良し悪しは誰かが持っている基準によって決まるということです。
言い換えれば、「ソフトウェアの作り手ではなく、受け取り手(誰か)の判断基準によって品質の良し悪しが決まる」ということです。これはとても重要な指摘です。(“誰か”には開発者自身を含むこともありますが、その場合でも客観的な立場をとります。)
なぜなら、この定義を受け入れたら、受け取り手のことを考えざるを得なくなるからです。
誰かが価値を感じてくれたかどうかが唯一の勝負です。ワインバーグの品質の定義を採用するなら、開発もテストも全ての活動は、「受け取り手に価値を提供する」目的にフォーカスされます。

 しかしそうでない人から見ると、Weinberg の定義は「何も言っていないに等しい」ようにも感じられるのではないでしょうか。

「テスト」の定義では

 testing の定義を再掲します。

set of activities conducted to facilitate discovery and/or evaluation of properties of one or more test items
1つ以上のテストアイテムの特性の発見かつ/または評価を促進するために行われるアクティビティ群

 この定義において、たとえば evaluation という言葉から「これは、verification と validation を両方含めた概念かな」などと、定義内の言葉の定義を自動的に呼び出して、簡潔な抽象的な定義を、詳細で具体的なものに展開できる人もいます。でもそうでない人にとっては、「抽象的で衒学的な表現」にも見えてしまいます。

 「定義を広げる」ことは、本質を捉えるために必要な行為である一方、読む人間に「悟り」を求めるという厳しさも伴います。エッセンスを鋭く切り取りながら、読む人の理解を促せるような定義。おそろしく困難な仕事だと思いました。まる。

まとめ

 もう少し書きたいこと書くべきことがありそうなのですが、キリがないのでこれで終わりです。
 特に結論もなく。

 「定義」を考えていく過程で「定義の定義」でググれば、ものすごくエキサイティングな考察が読めそうだなと思ったのですが、現実にはTwitter口喧嘩でした。しんどいわ。

togetter.com

*1:数学に詳しい人のつっこみご容赦。。

インシデントの「発生頻度」という言葉について

Raven- Queen Charlotte- Haida Gwaii. For those that know me, most of my pictures I take are around where I live.

 この記事は、欠陥のトリアージについてのメモ書きポエムです*1

 ソフトウェアのテストや本番環境で検出されたインシデントには、さまざまな情報が付加されていきます。
 インシデント管理システムなどへの最初の登録の際には、発生したソフトウェアのバージョン、事象、再現させるための条件などがあるでしょう。また調査や原因特定の過程で、事象の原因(ソフトウェア自体の欠陥なのか否かも含めて)、対策案といった情報も追加されていきます。

 こういった情報の一つとして、「重要度」や「発生頻度」を管理することも一般的です。
 重要度は、「重大度」「Severity」「Impact」などと呼ばれることもあります。「開発しているソフトウェアにとってどれほど致命的か」という情報です。

 発生頻度は、「Frequecy」と呼ばれることもあります。「そのインシデントがどのくらいの頻度で起こり得るか」という情報です。
 この「発生頻度」について、複数の意味があるなーと常々思っていたので、整理しておきます*2

「発生頻度」の三つのパターン

 「発生頻度が低いインシデント」というとき、少なくとも以下の三つがあります。
 なおMECE性にまったく配慮していません。

  1. ロジック的に発生頻度が低い
  2. ユースケース的に発生頻度が低い
  3. 利用環境的に発生頻度が低い

パターン1: ロジック的に発生頻度が低い

 内部状態の特別な組み合わせや、レアなタイミングでのみ起きるインシデントです。たとえば、「通信のシーケンス番号がある値をとったタイミングで特定の処理を実行した場合」みたいなものです。

 「発生頻度が低い」というとき、一番イメージしやすいのがこのケースかもしれません。ユーザが意識的に制御できないのが特徴です。メモリリークもこのパターンに含まれそうです*3

パターン2: ユースケース的に発生頻度が低い

 発生させるための手順などが非常にまれ、普通はやらないようなものなので、通常は起こりえないと考えられるインシデントです。たとえば、「画面の”進む”と”戻る”を1,024回繰り返した場合」みたいなものです。

 ユーザが意識する手順・使い方が発生条件なので、その条件をわざと満たせばサクッと出てしまうのですが、その条件をユーザに回避してもらうことで普通に使えるケースが多いです。使い方に制限を課すことになるので不便を強いることもある一方、ワークアラウンドが提示しやすい。

パターン3: 利用環境的に発生頻度が低い

 ソフトウェア自体ではなく、それを利用する環境が特別な組み合わせの場合に起こるインシデントです。たとえば、「OSが〇〇でブラウザが△△でウィルス対策ソフトが◇◇の場合」みたいなものです。

 この手のインシデントは再現条件に環境が含まれるので原因が特定しづらく、本番系で起こると調査が難航して泣きが入りやすいやつですね。

三つのパターンの違い

 どれも「発生頻度が低い」と呼ばれうるものですが、注意すべき違いがあります。

 まずパターン1と2は、「どのユーザにとっても発生しづらい」インシデントです。パターン1はユーザの意志で避けることが難しいかわりに、滅多には起きない。パターン2は、レアな使い方をしなければ発生しません。一方パターン3は、「起きるのはわずかなユーザに過ぎないが、そのユーザでは確実に起きてしまう」場合があるのが問題です。

 雑な絵ですが、イメージを以下に示します。オレンジ色の部分が「インシデントが発生してしまう条件」です。

f:id:kz_suzuki:20200102060418p:plain
発生頻度「低」のパターン

 パターン1と2では、すべてのユーザ(縦軸)が同じ「頻度」でインシデントのリスクを受け持つのに対して、パターン3では一部の「特別な」(少なくとも開発側が「特別」だと信じている)ユーザが全部のリスクを引き受ける形になってしまいます。言い換えると、このユーザにとっては、発生頻度「高」なのです。

 パターン3であっても、「ディスプレイの改造がものすごく低く、かつWindowsのハイコントラストモードで使用している場合」といった条件なら、まだ回避が可能そうにも思えます。しかし、ウィルス対策ソフトの動作との兼ね合いで起きてしまうようなインシデントに対し、「ウィルス対策ソフトを止めてください、ウチのソフトウェアと干渉するので」とは言えないわけで、回避不可能になりかねません。

 パワポでお絵かきしてまでこんな話を長々としているのは、「発生頻度」がインシデント対応の優先度付けに使われることが多いためです。
 発生頻度が低いと、それだけで対処の優先度もそのまま下げられてしまいがちです。そんなとき、「ここでいう発生頻度とは何を指しているのか。一部のユーザを犠牲にする判断になっていないか」という観点に立ち戻ることが必要だと思います。

 正月早々のポエムでした。

unsplash-logoRiho Kroll

*1:「ポエム」と言っておえば記事のクオリティが低くてもいいという免罪符になっていたが、最近の自称ポエムはクオリティも高く逆効果になりつつある。

*2:Webサービスのように「手元で」の修正・バージョンアップをできるソフトウェアではなく、メディアやダウンロードによってユーザに配布され、ユーザがそれぞれの環境にインストールして利用するソフトウェアを想定しているため、コンテキスト依存の部分があるかもしれません。

*3:ただしメモリリークにによるインシデントはそんなに時間がかからず発生しまうこともあるので、発生頻度が低いとは限らない。