不具合解析のための思考プロセス／フレームワーク

# はじめに
この記事は [アイスタイル Advent Calendar 2017](https://qiita.com/advent-calendar/2017/istyle) の 7 日目です。
本日のおはなしは

泣きたくなるようなやっかいな不具合に直面して投げ出したくなるときに
心を落ち着けて考えてみると糸口がつかめたりする話

になります。
長くなってしまいましたが、お付き合いいただけると幸いです！

# 背景
システム開発をやっていると、向き合わなければいけないもの。不具合。
どんなに注意深く設計しても、入念にテストしても、不具合ってやつは無情にも顔を出してくる。
リリースが過ぎて忘れかけたころに重いやつが出てきたりとか。

筆者はIT業界に入ったばかりのころにテクニカルサポート業務を担当していたこともあり、数多くの不具合と向き合ってエンジニア人生を生きてきました。自分が作った不具合だけではなく、同僚が作っちゃったものならまだよくて、商用フレームワークの上にお客様が載せたプログラムで起きた不具合（ただし該当のソースコードは非公開）っていうハードモードな不具合解析も体験しました。
自分なりに不具合解析の手順とかセオリーみたいなものを掴んできたかな、という頃に、ある大手製造業グループの子会社にプログラマとして転職しました。そこでの社員研修で学んだ問題分析の手法が、自分が体得してきた解析のやり方とすごく合っていて、はるかに論理的に整理されているものでした。思ってたけど言葉にできなかったことをまとめてくれてありがとう！な感じ。
手順を追って考えやすいフレームワークになっていたので、それ以降、難解な不具合に出会って頭が溶けそうになったときにはこれを使って情報を整理して、不具合の原因を突き止めるようにしていました。

その手法とは『**KT法**』。その中には4つのプロセスがありますが、『問題分析(PA)』と呼ばれるプロセスが、不具合解析にぴったりなのです。

あれから数回の転職を経てアイスタイルに来ていますが、この手法の話って、研修のあった会社以外では聞かなかったんですよね。元がマネージメント向けの問題解決手法だからなのか、製造業での事例が多めだからなのか、単に流行ってないからなのか。ロジカルシンキングとかマネージメントゲームとかはあったんですが。だけど、このKT法の問題分析プロセスほどエンジニアの実践に即したものはなかったので、せっかくだからご紹介してみたいなと思いました。

# KT法について

## KT法ってなに
ケプナーさんとトリゴーさんが「優秀な人たちはどうやって問題を解決しているのか」を調べて体系化した、問題解決と意思決定ための論理的思考法です。（[Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B1%E3%83%97%E3%83%8A%E3%83%BC%E3%83%BB%E3%83%88%E3%83%AA%E3%82%B4%E3%83%BC)）

## 4つのプロセス
KT法の思考手順は、4つのプロセスから成り立っています。

| プロセス            | 目的                   | 質問                         |
|:--------------------|:-----------------------|:-----------------------------|
| 状況把握(SA)        | 現状把握と課題抽出     | 何が起きていて何をすべきか？ |
| 問題分析(PA)        | 問題の明確化と原因究明 | なぜ起きたのか？             |
| 決定分析(DA)        | 目標設定と最適案決定   | どのように対応すべきか？     |
| 潜在的問題分析(PPA) | リスク想定と対策計画   | 何が起きそうか？             |
※出典：[Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B1%E3%83%97%E3%83%8A%E3%83%BC%E3%83%BB%E3%83%88%E3%83%AA%E3%82%B4%E3%83%BC#.E6.A6.82.E8.A6.81)

このうち不具合解析に役立つのは『問題分析（PA）』プロセスです。すぐに原因が予測できない難解な不具合を解析するには、

* 問題の状況を正確に把握し、
* 持っている情報を整理し、
* 本来あるべき結果と比べてどこがどう違うかを検討し、
* 原因の仮説を立てて検証する

といった手順を踏んでいきますが、この流れがフレームワーク化されており、手順にそって考えていくことで客観的・合理的に考えを進めていくことができます。

ちなみにほかのプロセスももちろん、システム開発における意思決定に役立つものですが、本記事では詳細を割愛します（記憶薄れてきてるし）。
[ものづくり.com](https://www.monodukuri.com/gihou/article_list/69/KT%E6%B3%95)に解説がありますので、ご興味ある方はぜひ読んでみてください（※要・無料会員登録）。

## 問題分析のプロセスフローとチェックポイント

PAプロセスにおける思考の流れ（プロセスフロー）と、正しい方向で考えられているかどうか確認すべき点（チェックポイント）は以下のようになっています。
（[ものづくり.com](https://www.monodukuri.com/gihou/article_list/69/KT%E6%B3%95)より引用）

### プロセスフロー
1. 原因究明すべきトラブルの明確化
2. 差異ステートメント化（問題点をひとことで言うと？）
3. 発生していることとしていないことを "IS/IS NOT" で、発生したことを "WHAT, WHERE, WHEN, EXTENT" (3W1E) の視点で整理
4. 区別点と変化点の明確化
5. 原因の想定
6. 原因のテスト
7. 最も可能性の高い原因を絞る
8. 裏付け

### チェックポイント
* 差異ステートメント化の対象は一つに絞られているか
* これはなぜ起きたのかを繰り返し真の問題点をつきとめるステア・ステッピング（なぜなぜ展開）は完了しているか
* 抜けている情報はないか
* 原因のなかに憶測は含まれていないか

# KT法で不具合を解析してみる

ここからは、具体的なケースを使って、PAプロセスで不具合の原因を解析してみます。
※ケースの内容はフィクションです。繰り返しますがフィクションです。フィクションです。

```text:ケース
ブログ記事Aと記事Bがあり、それぞれの記事には閲覧者が「お気に入り」をつけることができる。
記事Aと記事Bを統合することがあり、その場合はそれぞれにつけられたお気に入りの数を合算し、統合後の記事のお気に入り数とする。
（同じユーザーが2つの記事にお気に入りをつけていた場合は1件に統合される）

この統合処理で統合された記事について、1ヵ月前ごろから、お気に入りの数が極端に少ないという現象が数件報告された。
同じユーザーの2つのお気に入りを統合した分を考慮しても、明らかに統合後のお気に入りの数が少ない場合がある。
（過去の傾向から、お気に入りの重複率は10～20％程度）
報告された記事は、いずれも統合前の状態で数万件程度のお気に入り数がある。

特にエラーやアラートは報告されておらず、問題の発生に気づけないため、現在はだれかが気づいた時点で手動でデータ修正を行っている。
この現象は本番環境でのみ報告されており、ステージング環境や開発環境では報告されていない。
```
ケースにもとづく具体的な現象の分析や推定にツッコミどころ多々あるかもしれませんが、考えるプロセスの解説ということで目をつぶっていただけると幸いです。。


## 1. 原因究明すべきトラブルの明確化
まず、「解決すべき問題は何か」を明確にすることから始めます。ここでの問題設定によって、その後の解決への道のりが変わってきます。
ケースから読み取りうる「解決すべき問題」としては以下のようなものがあげられるかと思います。

* 記事のお気に入りの数（そのもの）が極端に少ない
* 統合後の記事のお気に入りの数が想定より少ない
* 問題の発生に気づくことができない

このケースでは、解決すべき問題は、「統合後の記事のお気に入りの数が想定より少ない」とします。
「記事のお気に入り数（そのもの）が極端に少ない」ことを問題とすると、記事の人気が低いなどさまざまな原因が考えられ、問題が広すぎます。このケースは統合による影響で数が減っている疑いが濃厚なため、統合処理に絞って原因を分析します。
また「発生したことへのアラートがあがらない」ことを問題とすると、アラートが上がらない理由の解析、アラートを上げるための対策などを進めることになります。ここでは根本的な問題解決を目指します。

## 2. 差異ステートメント化
ここでいう「差異」とは、本来あるべき姿とのギャップをいいます。不具合とは「このように動くはずが、期待通りに動いていない」ことであり、正常な動作と異常な動作の間に差異（ギャップ）がある状態です。
明確化した課題について「ステートメント」として設定する目的は、情報の収集範囲を限定すること、問題解決に関する検討や議論の逸脱を防ぐことです。

ここでは差異ステートメントを『統合後の記事のお気に入り数が想定より少ない原因を究明する』とします。

## 3. IS/IS NOTと3W1Eで整理する
差異ステートメントに関して起きている事象、わかっている情報を整理します。
整理には「3W1E」「IS/IS NOT」の観点を利用します。

* 3W1E … 
    * WHAT(WHO) ：なにが起こっているか
    * WHERE ：どの場所で、どの部分に起こっているか
    * WHEN ：いつから、どんなタイミングで起こっているか
    * EXTENT ：どのくらいの頻度、ボリュームで起こっているか
* IS/IS NOT
    * IS（存在する、起こっている）
    * IS NOT（存在しない、起こっていない）<br>→ISが起きているなら起きていてもおかしくないのに、起きていない事象

3W1Eそれぞれの観点について、IS/IS NOTの事象を確認していきます。
マトリクス形式の表が整理しやすいです。（さきほど決めた差異ステートメントも併記します、迷子にならないように）
![matrix1.png](https://qiita-image-store.s3.amazonaws.com/0/148546/4a0ce2dd-d4a6-e3ce-3446-0e6c487d7c96.png)

今回のケースの情報をマトリクスに書き込んでいきます。
![matrix2.png](https://qiita-image-store.s3.amazonaws.com/0/148546/d0e1fd5a-c1f7-0559-50a9-77be8e5e68a4.png)

## 4. 区別点と変化点の明確化
マトリクスに書き出したIS/IS NOTを見比べて、なにが違うのかを考えます。あわせて、その違いがいつからどのように発生したかを検討します。
これにより、問題の原因を推定する手掛かりができてきます。

さきほどIS/IS NOTを埋めたマトリクスに、区別点とその変化について書き込みます。
![matrix3.png](https://qiita-image-store.s3.amazonaws.com/0/148546/61859186-977a-32b7-5b41-776705f564b9.png)
すべて埋まらなくても構いませんが、明確なものでも書いていくことで頭の整理に役立つと思います。

## 5. 原因の想定
事象の整理ができたところで、これを手掛かりに原因についての仮説を立てていきます。
考えられる仮説はひととおり挙げていきます。正しいか正しくないかの検証はあとで行うため、この時点では不要です。真偽を気にして仮説を立てていると、問題の事象に対して主観が影響して、真の原因にたどり着くのが遅れる可能性があるためです。

今回のケースの推定原因として以下を挙げてみます。

1. 統合処理が高負荷になり、統合処理プロセスがダウンした
2. 統合対象のお気に入りデータ取得処理がタイムアウトした
3. 統合処理で一度に処理可能なお気に入り数を超えた
4. 統合処理に不具合があり、誤ってお気に入りが削除された

## 6. 原因のテスト
推定原因のひとつひとつに対して、マトリクスで整理した「IS/IS NOT」と整合性が取れるか（説明できるか）を検証します。

さきほど挙げた推定原因について検証します。
![test.png](https://qiita-image-store.s3.amazonaws.com/0/148546/eb171d74-3c8e-8dae-220d-82a40166ccbc.png)

原因1については、統合処理プロセスがダウンした場合は記事の統合処理も失敗し、記事が統合されないなどの不具合がでるはずなのに出ていない、という点で「対象：×」とします。
原因3については、不具合発生のたびに一定数（一度に処理可能な数まで）で止まると思われるところ、実際には数の減り具合は一定ではないので、「傾向：×」とします。
原因4につては、統合処理自体に不具合があればステージング環境や開発環境でも発生するはずなので「場所：×」、不具合であれば1ヵ月前ではなくリリース時点から発生しているはずなので「日時：×」とします。


## 7. 最も可能性の高い原因を絞る
推定原因を検証してみて、最も可能性が高いと思われる原因を絞り込みます。

今回のケースでは、原因2のみすべて〇なので、原因2に絞れます。
複数の原因がすべて〇だったり場合は、この後の裏付けと組み合わせて判断するか、あるいはIS/IS NOTでほかに着目すべき事象がないか立ち戻ってみるのもよいかと思います。
逆にすべての推定原因に×が含まれている場合、単独の原因ではなくて組み合わせで発生している可能性が高いので、合わせてすべて〇になるような複合原因があるか検討します。

## 8. 裏づけ
最も可能性が高い推定原因を絞り込むことができましたが、この段階ではまだ「推定」なので、この推定原因を裏付けることができるか検証します。

* 実際の不具合発生状況に立ち戻って、IS/IS NOTや変化、推定原因が矛盾なく説明可能か観察する
* 推定原因をもとに不具合が再現できるか検証する
* 推定原因を取り除く対策を行って、問題が解消するか検証する

このケースの場合、データ取得処理をわざとタイムアウトさせて同様の現象が起きるか、タイムアウト値をのばして問題が解消するか、を検証していきます。
無事に裏付けがとれれば原因確定です！

# おわりに
いかがでしたでしょうか？　手順が多すぎて面倒と感じられたかもしれません。小さな不具合や原因がすぐに思いつく不具合であれば、毎回こんな手順は踏まなくてよいのですが、なんで起こっているのかさっぱりわからない不具合、再現性が低い不具合など、じっくり取り組む必要がある場合には有効です。やみくもに悩むよりもPAプロセスのようなフレームワークに沿って整理して考えてみると、問題を客観的にとらえることができ、複雑さの奥に隠れた真の原因にたどりつくのが少しでも早くなるのではないかと思います。

もしPAプロセスに興味を持っていただけたなら、ぜひKT法全体も学んでみることをおススメします。DAプロセスは開発プロジェクトで使うライブラリやサーバなどの選定そのものだし、SAやPPAのプロセスもプロジェクトでのさまざまな意思決定に役立つものです。
KT法以外にも、ロジカルシンキングに関する考え方や手法など、さまざまに編み出されたものがありますので、気になったものは一度触れてみるといいかなと思います！

エンジニア生活をしていると、勉強するべきことは胸焼けがするほどありますが、どうしてもプログラミングや設計の技術を仕入れることで精一杯になってしまいがちですよね。ですが、直面した課題、よくわからない事象に対して、どのように解決していくか、論理的に考えるやり方を身につけることは、プログラミングでももちろん役立ちますし、開発プロジェクト、組織、プライベートの生活、さまざまな場面で活きるスキルとなります。おばちゃんウソつかない。

明日のアドベントカレンダーは、インフラエンジニア @hirosesa が分散ストレージのなにかについて語るとのことです。ぜひご覧ください！

# References
* http://www.kepner-tregoe.co.jp/ <br>
  KT法の総本山、ケプナー・トリゴー社。書籍やセミナーなど展開されています。
* https://www.monodukuri.com/gihou/article_list/69/KT%E6%B3%95 <br>
  KT法について詳しく解説されています。
* http://matsumurahp.server-shared.com/ <br>
  KT法に関する技術レポートやプレゼンテーションスライドを公開されています。