不具合撲滅運動

この記事は[【マイスター・ギルド】本物のAdvent Calendar 2021](https://adventar.org/calendars/6579)  5日目の記事です。

最近のシステム開発で不具合への対処（アプローチ）ってとても大事だなと自分なりに振り返るシーンがあったので、品質管理の観点から不具合分析の押さえどころ（障害報告のポイント）や、そこから生みだされる可能性のある有益な資産について、書いてみたいと思います。

<img width="200px" alt="character_program_shutdown.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/5a2c3430-8eb5-b195-4541-2d8f746e1c4a.png">

# はじめに

この記事は日ごろガリガリとコーディングをされている若手プログラマ向けの記事となります。
この記事が何かの気付きに繋がり、より良いモノづくりの糧になれば幸いです。


# 不具合って何？

<img width="200px" alt="bug_mark12_tentoumushi.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/035e3592-0a61-5265-f12c-2b26069d4345.png">

いろいろ解釈はあると思いますが、今回はこういうものだと思ってください。

- 書いたコードが想定どおり動かない状態（バグ）
- 「想定どおり」とは、そのシステムを利用する一般ユーザまでを含めた、全ての利害関係者
    - 例：一般ユーザ、システム運用チーム、システム開発チーム、設計者、プログラマなど
    - とにかく、誰かが不都合に思う事象なら全て不具合です

# 不具合を起こすと何が待っている？

<img width="200px" alt="kaisya_tousan_woman.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/29c9a404-a5af-3b2d-d3ce-0dbfab3f2d26.png">

ちょっと脅すような見出しですが、不具合が出て喜ぶ人は基本的にいません（誰かにとって不都合となる）。品質保証なんかをしていると、書いた（評価依頼のために提出された）コードに対して、ある一定量の不具合を出すことをお仕事としてされている人は別かもですが。

また不具合の発生タイミングによっては、簡単に想定外の損失を被ったり、最悪の場合は会社が傾くなんてこともあるのが情報社会と呼ばれる今の世の中。サービスを提供する企業にとっては不具合というものはマイナスイメージでしかなく、また一度失った信用を取り戻すのには並々ならぬ努力が必要だったりします（最近は無料アイテムのばら撒きなんかで上手くヘイトを起こさせないような手法もあります、またWebサービスなんかだと多少の不具合が出ていたとしてもユーザーが望む体験を提供できていればサービスレベルをキープすることが可能だったりという話もありますが、それは別のところで）。

また不具合を出すと、それを今後出さないための施策（再発防止対策）を次からは必ずやらないといけないといった無駄？な作業が増えていくなんてこともザラです（負の連鎖）。

要は不具合を世に送り出す（人の目に晒す）と、碌なことはないのです。

- 不具合が発生した後のシナリオ
    - しなくてもよさげな作業手順を未来永劫こなしていかなければならない、妙な責務が生まれる
    - デスマーチへの門が開く
    - ヘイト情報などの拡散で信用・信頼を落とす
    - 最悪の場合、会社が傾く

なので、不具合は起こしたくないものです。

# ﾀﾞｹﾄﾞﾏﾀ、ﾊﾞｸﾞｯﾄﾙ...  ｳﾜｧｧ—｡ﾟ(ﾟ´Д｀ﾟ)ﾟ｡—ﾝ!!! 

不具合って、ほんと不思議。ゼロにならない。私も長年システム開発に携わってきましたがゼロにはなりません！
ってことで、タイトル「不具合撲滅運動」のオチですが、撲滅する（完全に退治する）なんて無理なのです。

# で、本題、次に活かそう（不具合分析）

<img width="200px" alt="document_data_bunseki.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/35018cc9-d40a-373e-3931-f8864f2b2457.png">

でもやっぱり出したくない。この気持ちも無視しがたいので、足掻いてみたいと思うのもやはり人の性。
なんで不具合は起こるのか、そこはやはり人のなせる業なのかなとも思います（人はミスをする）。
では、不具合を出すのが人なら潰すのも人の役目なので、真面目にその発生プロセスを分析して次に活かしたいというわけです。

また、さらには、ある意味失敗（恥ずかしいし、隠したい、とりあえずなかったことにしてしまいたい）とも言える不具合の発生を糧として、それを成功体験へ変えていくこともできます。不具合を逆手にとって信用を得るとか、分析から得た知見をもとに不具合が出にくい仕組みを作り上げるなどがそうです。そのためには、「言語化」とそれを「隠さずに連携する」ことがとても重要になってきます。

- 不具合を成功体験に変えるには
    - 不具合を分析し言語化しよう
    - 隠さずオープンにしよう

次はその分析について触れていきます。

## 不具合分析の押さえどころ

あたり前のことですが、コードを書くから不具合が出ます（コードを書かないという選択肢はここでは無しで）。コードを書くところできっちりと押さえたいところではありますが、まぁ何かとやらかすのが人の性です。
なので、やらかしそうなところで慎重になれる仕組みを考えたり、やらかした時にどういうアクションを取って、次に繋ぐかをしっかりと考えたいなと思います。そのためには今回発生したその不具合の事実関係を様々な角度からクリアにしていくことがとても重要になってきます。

## 不具合の事象を事細やかに理解する

どういう不具合が起こったのか、事実関係を正確に理解するためのポイントを列挙します。

- 発生の経緯を押さえる（押さえる＝理解する）
- 発生事象を押さえる
- 発生の原因を押さえる
- 原因の原因の原因の...を押さえる（根本原因、真因を押さえる）

### 発生の経緯を押さえる

ここはサービスインしたシステム障害などだとよく行われる事実確認。

- 5W1H的に経緯を押さえる
- 時系列で押さえる
    - 起点は不具合発生時、範囲は過去と現在（発生時点からすると未来）
    - スタートは不具合を作りこんだ経緯（作業プロセスや上流フェーズへの遡っていく）
    - 不具合発生により引き起こされた可能性のある関連する事象や、それらとの繋がりなどを把握する

### 発生事象を押さえる

不具合が発生！やばい！もうダメ！と無駄に騒ぐのではなく、何が起こった？問題は？影響は？というところを冷静に押さえていきましょう。
ポイントは言語化です（やばいやばい言うてても始まらないのでアウトプットしましょう）。

- 何が起こったのか（現象そのもの、発生手順など）
- 何が問題なのか
    - どうあるべきところが、どうなってしまったのか
    - それが発生することで、どういったリスクが発現するのか

### 発生の原因を押さえる

- 不具合原因を探る
所詮はプログラムのなす技なので、書いた通りにしか動かないものです、不具合発生のメカニズムの説明書きを準備していきます。
説明自体はアルゴリズムの内容にも踏み込みますが、ソースをペタっと張るのではなく説明を書き出す（言語化、少し抽象化した日本語での説明書き）のが望ましい。
また説明の範囲についてはプログラムを作るもととなったインプット情報（提供資料や設計書類）にも及ぶ場合がある。



- 不具合発生のメカニズムの説明例

<img width="200px" alt="kazetooshi_kaisya_bad.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/ad440276-b706-2144-0c44-fd2e591e0c3a.png">

|悪い説明例：||
|-|-|
|-|変数にセットする値が間違っていた|

:::note alert
不具合発生のプロセスがアルゴリズムとして説明されていない
何がいけないのかという点で具体性に欠けている
変数には何がセットされるべきだったのか
変数が持ちうる値のパターンや、範囲が不明確
何に利用する変数なのかすら、わからない
:::

<img width="200px" alt="presentation_kaigi_woman.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/61edf946-f07d-e668-4324-6334ff47da0f.png">

|良い説明例：||
|-|-|
|-|P処理のローカル変数として宣言されているK変数に対して、用意されている定数をセットせずにリテラル値をセットした|
|-|そのことにより想定していないQ値が入った、そのため、P処理内の条件分岐Lにて判断がなされなかった（漏れた）|
|-|判断されなかったことでR処理が呼び出されず、うんぬんかんぬん以下略、その結果、今回の不具合が生じた|

:::note info
処理名や変数名が具体的に記載されている
想定や異常な状態、状況などが記載されている
不具合に至るまでの処理のプログラムライクな手順（アルゴリズム）が示されている
:::

- 影響範囲の把握を行う
    - 修正方針が見えてきたら、その修正を加えることによる弊害が他のコードで起こらないかを確認する
    - グルーバルなスコープで利用されているメソッド内を修正するような場合は特に注意したい
- 類似するコードが他に存在しないか確認する
    - 不具合発生箇所を含有するコードが他に流用されていないか？
    - 類似プロセス（処理フロー、アルゴリズム）が他に存在しないか？

### 根本原因、真因を押さえる

アルゴリズム的にここをこう直せばOK（原因への対処のみ）ではなく、そこがなぜ「そのようにコーディングされたのか」という点を深堀していく（根本原因を見つける）必要があります。
これを行うことで、その場限りの対応ではない再発防止策の検討に役立ちます。

- 根本原因を見つけ、障害が発生しにくい環境を作り出す
    - また、さきほどの例を元に考えたときに、何故定数を使わなかったのかを深堀していく
    - 定数の存在を知りえなかった理由を突き詰めてみると、定数の宣言箇所が多岐に渡っており体系だったファイル名やパスに存在すべき定義がなかったことや、命名ルールがあいまいでgrepにも引っかかることがなかったなどが見えてくる
    - また、一部の人しか知らない情報になっていたりなど
    - 障害とは少し離れたところで、障害に関係性のある課題が浮き彫りになる

ちなみに、原因の深堀にはなぜなぜ分析がおススメです。あとは特性要因図（図法）である程度の太骨（要因）を事前準備したものを用意しておいて原因を探るのも、考えを整理するのに役立ちます。

## 不具合報告や分析した内容はオープンに共有しよう

<img width="200px" alt="kaigi_sagyouin_smile.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/83bcc703-4735-7ac1-7a0d-257e02708308.png">

ここはとても難しい心理的な障壁があったりするのですが、個人で抱えるのではなく素早くチームないし顧客と共有することで信頼を得たり、分析の妥当性を測ったり、さらなる深堀の機会損失を防ぐこと（有識者からのコメントをもらうなど）が可能だったりします。
また不具合分析の結果を障害報告書という形でアウトプットすると逆に信頼を得る結果に繋がったりすることまであります。

あと不具合報告のスピード感も重要です。言いにくいことではありますが、さっさと共有してしまって素直にフォローを受け、建設的な作業に集中できるよう自ら進んでオープンにしていきたいところです。

# 再発防止策を出す
ここまで来ていれば不具合の原因や対処ははっきりしているので、まずは不具合を直してしまうべきかと思います（周りとよく相談して素早く復旧するために動きましょう）。
ここでは不具合（影響箇所、類似箇所含む）を直したあとの根本原因に対する行動（再発防止策）について書きます。

根本原因が特定された場合、そこを解決すれば今回の不具合はもちろんのこと、その他、今後発生しうる類似ないし派生の不具合発現率も下がることが期待されます。
そういったことを目論んで打たれる対策のことを再発防止策と呼びます。

- 解決すべき対象となりうるもの
    - ハードウェア（スペック、構成）に起因する
    - ソフトウェア（コード）に起因する
    - 資料や設計書（ドキュメント）に起因する
    - マネジメント方法に起因する
        - レビュー体制、手順など
    - 人（スキル）に起因する
- 対策を打つにあたり考慮すべき点
    - 実現可能性、有効性
    - 一時的な対策なのか、恒久対策なのか
    - 対応にかかるコスト
    - 通達範囲

不具合が発生したら、ここまで考えて再発防止策に繋がるといいですね。

# 次のステップ（不具合管理、品質管理）

<img width="200px" alt="science_kannou_kensa_hyouka.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/51e04b3a-b386-3aea-c02d-ac49e31396a1.png">

ここまではある不具合に対する分析というピンポイントの話をしてきましたが、ここではもう少し上の目線（組織、プロダクト、プロジェクトと言った視点）での押さえどころを書きます。
各開発プロジェクトでは様々な不具合が発生しますが、そのひとつひとつを分類・データ化して、そこから見えてくる特性を押さえることで、不具合情報が次に活かせる有益なプロジェクト開発資産に生まれ変わります。
また、さらに不具合を撲滅していけるような踏み込んだ施策（全社単位、プロジェクト単位）を立てることができます。

以下にどのような情報を蓄積しておくべきか、参考例として書き出しておきます。

- 不具合要因の分類分け
    - 要因カテゴライズ
        - 仕様書不備
        - 仕様理解不足
        - コーディングミス
        - テスト不備
        - テスト漏れ
    - 不具合を作り込んだフェーズ
        - 要件定義
        - 基本設計、詳細設計、プログラム設計
        - 実装
        - 単体テスト、結合テスト、システムテスト
    - 不具合を本来発見すべきフェーズ
        - 同上
    - 不具合を発見したフェーズ
        - 上記フェーズに加え「市場」
    - 不具合の改修にかかったコスト
        - 調査コスト
        - 修正コスト
        - 確認コスト
- データ化
    - 件名（不具合をイメージしやすいシンプルな事象説明）
    - 不具合の内容
    - 問題点（事象から呼び起こされる可能性のあるものも含む）
    - 不具合発生のアルゴリズム説明
    - 影響範囲の調査結果
    - 類似箇所の調査結果
    - 修正方法
    - テスト方法

## おわりに

<img width="200px" alt="gakusei_undou.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2149410/85d05197-b07d-7fb8-240f-ed615cc5ab91.png">
（不具合撲滅運動って、こういうことかなと）
しっかりとした不具合分析を行い、それを対策や知識体系としてノウハウに落とし込むことで不具合が少しでも減ると思います（ゼロには絶対できませんｗ）。またその蓄積されたナレッジは活用することで資産となりえます。

最後に品質管理の観点から言うと、やはりチェックするポイントを要所要所、いろいろな角度で準備できていると分類やデータ化なども捗っていいなと感じます。
例えば、打合せをしたら議事録を残しましょう。議事録の内容は承認を得ましょう。モノを作ったら、誰かが必ずレビューしましょうとか、コードならテストコードとセットで用意しましょう。コードフォーマッターにかけたものをアップしましょう、必ず静的解析をかけましょう、自動化テストやテスト仕様書に基づくテスト実施、テスト結果をまとめましょうとか、それらが全てデータ化されていれば第三者目線での確認が容易となり、不具合検知の精度が上がることで、誤って不具合を世に送り出すという結果にいたる機会がグッと減ると思います。

もしこの考えに賛同できる方は、これを機に不具合撲滅運動への参加を検討くださいｗ

最後までご高覧いただきありがとうございました。


# おまけ
続編書きました。

https://qiita.com/ORESAMAChanMg/items/bfc0f15fcda64ed2e704