Royceの言うとおりにしたらウォーターフォールでもバグゼロできたよ

まあ、Royceさんは ウォーターフォール なんて名前付けてないんですが！！

Royceさんの言うソフトウェア開発プロセスについては
* ご本人の論文「Managing the Development of Large Software Systems」を読むか
* これの和訳がどこかの大学サイトにあったと思うので検索して読むか
* この論文に言及しているブログ記事もたくさんあるのでそちらを読むか

してください。
やってらんね～って方は RSGT2023 に Tommy さんが発表しているので、そちらをどうぞ。

https://youtu.be/_RjMnyhd0FU

さて、本題です。

# この記事は

[開発でチャレンジして、失敗・成功したことをシェアしよう by 転職ドラフト Advent Calendar 2024](https://qiita.com/advent-calendar/2024/engineering-careers-1) に参加しています。

近年、若手と雑談する機会が増えてきたのですが（それだけ歳を取ったと言う）
成功体験を持っていない人が意外に多いなと思ったので、
私の自信に繋がった「バグゼロ」体験について記事にします。

# Royceさんの言うことにゃ

> DO IT TWICE

by Dr. Winston W. Royce

# やってみた

これが私の「バグゼロ」体験です。

## こんなプロジェクトで

GUI上でユーザがあれこれデータを作ったり操作したりする機能と
TCP/IPのサーバの機能を持つ、5年くらい前に作成されたアプリケーションを

* もう間もなく行われる見込みのOSの入れ替えを想定しつつ
* OSを除いたビルド＆実行環境（ライブラリ等）を丸っと最新に置き換える

というバージョンアップを、全部コミコミで3ヶ月で仕上げます。

## こんな風に

### Step1　お試し①

本番環境と同じ試験環境を作って、ライブラリ等を丸っと最新にアップデートし、
そこで既存コードをコンパイルし直しました。

**👼コンパイル通らぬ👼**

Error, Warning 全部洗い出して全部原因調べて直し方調べて
影響箇所も類似箇所も水平展開先も全部洗い出して
全部をドキュメントに残しました。

:::note info
ドキュメントといっても、チームメンバが読める程度のメモ書きです。
今風の例えだとNotionにちょこちょこ書いて、外部リンク貼って、必要なら絵やスクショを貼っていく感じです。
とにかく、コードを変える前にメモる。を徹底しました。
:::

その後で調べたとおりの直し方でコードを変えました。

**👼まだ通らぬ👼**

調べ直してドキュメントに反映してからコードを直しました。


➡ ようやくコンパイルが通った🥳


### Step2　お試し②

このアプリケーションには
実行は9割自動、結果判定は8割目視、という既存テストツールがありました。

このツール、全項目を実行すると
数時間かけて、アプリケーションが実装している全機能の正常系＋代表的な異常系を動作させ、その動作ログ等々を指定フォルダに全部吐き出してくれる
という、結構な優れものでした。
（ただ、結果判定は人間が目視チェックでした。
　期待値として使える比較対象のフォルダも用意されていたので、
　diffとって、その差分が許容できるかを人間がチェックする感じです。
　timestampとかが含まれるので下手に自動化しないほうが良いという判断）

ただ、この数年は「リグレッションテスト用」とされている
抜粋版ばっかり動かしていたのです。
（目視チェックが日数かかるのでね...）

ようやくコンパイルが通った、あんまり信用ならん状態のアプリケーションなので
取り敢えず抜粋版を動かしたところ…

**👼エラーでテストが完遂せぬぅ～👼**

ちゃうんです、テストツールはちゃんと動作しているんです。
アプリケーションのほうが落ちたり、それを直してもTCP通信がロストしたり、それを直したらフリーズしたり、とボロボロ過ぎたんです。

ということで、1つずつ、コンパイルのときと同じように
「原因を調べる」「直し方を調べる」「影響範囲や水平展開先を調べて直す」を
全部をドキュメントに残して、それからコードを変えました。

やっていくと結構「この部分、動いたとしても期待と違う挙動になるよね」と
動かす前に察知できる箇所が見つかりまして
そういうのも原因書いて、直し方や影響範囲や水平展開先調べて、と
ドキュメントに残しつつ、コードを変更していきます。

この頃になると「使っているライブラリ、結構な差分があるぞ...？」と思い始めたので
Change Logを参照して、関係ありそうなものはドキュメントに書き写し
自分たちのアプリケーションが大丈夫かチェックする、という作業も始めました。

**コンパイルエラーも動作エラーも、なんだ、ちゃんと Change Log に書いてあったじゃないか！🤪**

ということで、
担当者としては「もう大丈夫！テストは動くはず！」と自信を持って再テストしました。

**👼まだ期待値と違う箇所が～👼**

これはChange Logに記載されていないのか、私が読み取れなかったのか、ライブラリ側が想定していない使い方をしていたのか...
何にしろ、あそこまでやったのに未だ数カ所、修正が必要でした。

➡ ついにリグレッションテストもパスした！🥳

➡ ついでに探索テストもしたけど動いた！🥳


〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰

　**ここまで「人道的な範囲」の残業もしつつ3週間**

〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰

### Step3　全部捨てた

Step1, 2 で残したドキュメントを除き、
試験環境も修正したコードも
**ぜーーーーんぶ捨てました。**

後から聞いたところ
とある人だけ、やっぱり不安で、自分のPC（ローカル）に残してたようなんですが
「結局使わなかったや～😜」と言ってました。

### Step4　本番

ここまでで私たちは、何をどう変更すれば良いのか知見・経験を得ました。
必要な情報はすべて揃っている、と言えましょう。
あとは粛々と設計して実装してテストするだけです。

既存設計書と既存コードをベースに、変更設計を行いました。
具体的には
* 今回の作業のための「変更箇所に集中したドキュメント」を作成
* 後世に残す「ちゃんとした設計書群」を更新

しました。

変更箇所に集中したドキュメントができたら、コレを元にコードを変更です。
Unit Testがパスする状態になったら Done です。

設計と実装は **ノー残業で** 3～4週間ぐらいだった記憶です。
**遅延は一切なし**。

スケジュールに余裕が見えたので、
新・本番環境でのテストは一人で実施することにしました。
（もちろん「何かあったら」フォローする前提ですが、何もありませんでした）

アプリケーション単体のテストでは3件のバグが見つかりましたが
いずれもコーディングミス (typo) でした。
一人でよっゆー🥳で処理しました。

そこから先は
システムの他ソフトとの結合 (システムへの組み込み) テスト
→ システム全体でのテスト
→ 他チームによるユーザビリティテスト
と
テストをこなしていきました。


## こうなった

1. 設計書レビュー
「変更箇所に集中したドキュメント」はStep1, 2で作ったドキュメントを整形・補足しただけなので内容に納得で
レビュー指摘はほぼ出ませんでした🥳 (誤字衍字が見つかって恥ずかしかった)
「後世に残す設計書群」も、前者のレビューで知識共有できていたためか、設計そのものには異論がなく、
故に「これって後から見たときにわかりやすいかな？」という議論が盛り上がりました。
後世に残す、というドキュメントの目的に合致したレビューができたのは
コレが初めてかも！という声が挙がって、個人的にはちょー嬉しかったです🥳
　
2. コーディング
どこをどう直せば良いか、自信を持って作業ができるので
可読性に全力を傾けました。ノーストレス🥳
　
3. Unit Test
typoおおおおお🤮
既存テストが動くのは当たり前です。
テストの改善点を見つけて直しちゃいました🥳
　
2. コードレビュー
コメントや命名について数件の指摘がありました。
確かにそこ悩んだんだよね～とみんなで議論→納得の結果を得ました。
対面レビューの時間内に、余裕で解決までたどり着いたのでノーストレスです🥳
　
4. 単体テスト
前述のテストツールで全項目テストしました。
 Unit Testもコードレビューもすり抜けた typo が3件のfailを引き起こしました🤮
 だいじょうぶ、typoは直せば良い...🥲
 普段は抜粋で実施していたテスト項目を全件実施できたので
 「これはもう大丈夫！」と私たちは自信を持ったのでした🥳
 　
 5. システムとの結合テスト
バグ報告0件🥳
　
6. システム全体のテスト
バグ報告0件🥳
　
6. 他チームによるユーザビリティテスト
バグ報告0件🥳
　
7. リリース後
あれから5年以上経ちますが、まだバグ報告ありません🥳
(恐ろしいことに、まだ、実行環境ごと、当該アプリケーションは使われています)
OSバージョンアップも耐えたようです🥳

単体テスト終了後からリリースまで半月は余裕であったのですが
何もすることが無かったです。
別チームが全体テストでバグの山を出して残業重ねてましたが
私たちはノー残業で次の開発の準備を粛々と。
結果、次の開発も残業ほぼゼロで... と余裕は連鎖していきました。

# 理解したこと

この経験を共有したみんなが思ったことは
「わからないことを早めに潰しておけば、プロジェクトってうまくいくんだな」
でした。

PMBOK的な言葉だと「不確実性」ってやつですね。

よくわからないから仮に決めた仕様や設計が、先に進んでみたらから拙いとわかった際に工程を遡る「手戻り」が発生する、
いわゆる「ウォーターフォール」型の日程計画では手戻りを計画していないので、
手戻りが発生すると日程計画が破綻する。
というプロジェクトにおいて、
最初の「よくわからない」＝**不確実性を減らせば計画どおりに行く**のです。
　

私たちは、Royceさんのいう「DO IT TWICE」を以下のことだと理解しました。
* 1回目で小さく (ミニチュア・プロトタイプ) やって、不確実性を潰すことに集中せよ
  * 事前に見えていた不確実性は潰す
  * 見えてなかった不確実性を発見する→できるだけ潰す
* 不確実性が少ない状態で2回目を実施することで、成果物の品質を上げることに集中せよ
　

とはいえ
👼世の中すべてのプロジェクトが「DO IT TWICE」できる訳じゃないですよね～👼
🤓「DO IT TWICE」しなくたって、PMBOKに「リスクマネジメント」ってあるでしょ！🤓
🥳そうだった、リスクマネジメントって不確実性をコントロールする作業だった！🥳
　

という気づきを挟んで、私たちは
**リスクマネジメントがプロジェクトの成否を握る**
という結論にたどり着きました。

気持ち的には「リスク駆動開発」ぐらいの勢いで、リスクマネジメントって大事です。


ということで皆さん
「リスク～？目の前の課題こそ大事でしょ～」と鼻ほじせず
ちゃんとリスクとも向き合いましょう。

リスクの見つけ方がわからないときは、取り敢えず「初めてのこと！」「わからないこと！」に注目すれば良いと思います。
　

　

おわり.