デバッグの極意〜初めてのペアプロから学ぶ仮説検証のPDCAサイクル〜

# 記事を書こうと思った経緯
私は現在、[fjordbootcamp](https://bootcamp.fjord.jp/)（以下 fjord）でWEBエンジニアになるための学習をしております。
fjordではメンターさんへの質問はもちろん、ペアプロも行っていただけます。

学習に取り組む中でメンターの伊藤さん（@jnchito）に相談をさせていただいたのですが、

- 自身の質問の作法が不十分であった
- デバッグ（仮説と検証）ができていない

上記2点もあって、伊藤さんから直接声をかけていただき初めてのペアプロを行いました。

ペアプロを通して、自分の弱点及び、それをどう改善していくかという気づきや、デバッグの際のテクニックを学ぶことができたので以下まとめていきます✏️

まとめとしては下記3点です

- 質問をする際に気をつけたいこと

- 仮説と検証

- デバッグ時のTips

尚、fjordではRialsアプリケーションの開発を学んでいるため、所々Railsに関するメソッドなどが記載されていますが、Railsを触らない人でも分かる内容になっております。

# 質問をする際に気をつけたいこと

今回僕は下記のような質問をしました。

<details>
<summary>自分がした質問</summary>
※所々割愛しています。

こちらを含めるとテストの不安定さが解消されないので削除しました。

テストの対象を「テキストを入力した状態でプレビュータブを開けること」として上記のように変更してます。

ちなみに`プレビューができます`というテキストはフォームに入力をした時点で画面に表示されているはずなので、
元のテストの`assert_text 'プレビューができます'`はテストをしたことになっていないとも思いました🤔


上記を踏まえ、`fill_in 'js-user-mentor-memo', with: 'プレビューができます。'`の直後に`assert_text 'プレビューができます。'`を入れて確認ができればOKと考えましたが、それをするとやはりテストが不安定になるので一旦削除しました。

***
別の方の似たようなPRを参考に

```ruby
test 'can preview editing of user-memos' do
  visit_with_auth "/products/#{products(:product2).id}", 'komagata'
  find('#side-tabs-nav-3').click
  click_button '編集'
  fill_in 'js-user-mentor-memo', with: 'プレビューができます。'
  assert_selector '.is-editor.is-active'
  find('.form-tabs__tab', text: 'プレビュー').click
  find('.is-preview.is-active > div > p', text: 'プレビューができます')
  assert_selector '.is-preview.is-active'
end
```
とした所、テストも安定したままテスト内で行っていることもよりわかりやすくなった気がしますがいかがでしょうか🤔
***
</details>

ご指摘をいただいてこれは良くなかったと反省する点がいくつもありますが、今回は下記3点についてまとめたいと思います。

- 自身に起きているエラーの再現方法を記載していない
- エラーログ、スクリーンショットといったエラー時の重要な情報が欠けている
- 不安定という抽象的な言葉を使用している


## 再現方法を記載する
エラーが起こっている状況を再現するための手順を記載すること。

自分に起こっていることをテキストで伝え切ろうとすると、文章が冗長になったり、相手にうまく伝わらないケースがほとんどです。

それよりも同じプログラムを実行した結果を確認してもらう方がテキストで伝えるよりも遥かに問題点が伝わりやすいと思います。

もちろんそれだけでは不十分なのでテキストによる補足が必要ですが、まずは問題点を相手に理解してもらうためにも必ず再現方法を記載することを忘れないようにする。

## 重要な情報を必ず載せる
重要な情報とは主に下記などです。
- エラーログ
- エラー時のスクリーンショット(システムテストや画面側の不具合の場合)

またこの時、エラーログについては質問相手がログを検索しやすいように必ずテキストで伝えるようにする。

NG
![image.png](https://bootcamp.fjord.jp/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBM3ZHQWc9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--e8923547732d00baeedf0f81433e61ebd8cb3774/image.png)

GOOD
```
Error:
Notification::AnnouncementsTest#test_announcement_notifications_are_only_recived_by_job_seekers:
ArgumentError: wrong number of arguments (given 3, expected 2)
    app/models/notification_facade.rb:57:in `post_announcement'
    app/models/announcement_callbacks.rb:32:in `block in send_notification'
    app/models/announcement_callbacks.rb:30:in `each_with_index'
    app/models/announcement_callbacks.rb:30:in `send_notification'
    app/models/announcement_callbacks.rb:24:in `after_first_publish'
    app/models/announcement_callbacks.rb:7:in `after_create'
    app/controllers/announcements_controller.rb:45:in `create'
```
## 具体的な言葉を使用する
抽象的な言葉を使用することで余計なコミュニケーションロスが生じます。
より具体的な言葉を使用して双方の認識の齟齬をなくす。

今回の自分の質問を例に挙げると「不安定」という言葉が抽象的な表現にあたります。

自分はこの「不安定」という言葉を「〇〇行目のテストがパスしたりしなかったりする」という意味で使いましたが、これを聞く相手がこの「不安定」という言葉からそこまで理解できるはずがなく、人によって受け取り方が何通りもあります。

- 「○○テストファイルを全実行すると△△テストの××行目でテストが必ず落ちてしまう」
- 「■■テストを単体で実行した時は100%通る」

こんな感じでより具体的な情報を伝えることを心がける。

## 質問するときに気をつけたいことまとめ
自分が誰かに質問をする時ってどんな時か考えてみました。
自分の力では目の前の問題が解決できずに誰かに助けて欲しい時です。

自分の力で解決を試みようとする時必要になるものは**情報**です。
その情報が具体的で十分な量がある場合、仮説が立てやすくなります。

自力で仮説と検証を繰り返してお手上げとなった時が人に質問をする時であり、その場合は質問相手の経験に頼りたい時です。

質問相手も情報が少なく、抽象的であると立てられる仮説が限られてしまいます。

こうならないためにも十分な量の具体的な情報を伝えることが大切なのだと感じました。

# 仮説と検証
引き続き今回のPRでの質問を例に仮説と検証についてまとめていきたいと思います。
まとめたい内容としては下記です。

- デバッグをする際の仮説と検証
- 先入観、思い込みは赤信号🚨
- エラーが起きないからOKという考え方も赤信号🚨

## デバッグをする際の仮説と検証

> [デバッグは「うまく動かないピタゴラ装置の原因調査」だと考えてみよう \- Qiita](https://qiita.com/jnchito/items/e4b75ff2c3eeccfffec1#%E4%BB%AE%E8%AA%AC%E3%81%A8%E6%A4%9C%E8%A8%BC%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%97%E3%81%A6%E9%9A%A0%E3%82%8C%E3%81%9F%E3%83%90%E3%82%B0%E3%82%92%E3%81%A9%E3%82%93%E3%81%A9%E3%82%93%E8%BF%BD%E3%81%84%E8%A9%B0%E3%82%81%E3%82%88%E3%81%86)

こちらの記事でデバッグ力というよりはデバッグの際の思考、持つべきメンタリティみたいな部分を学びました。

「デバッグとは」を簡単にまとめるとすれば仮説と検証のPDCAをガンガン回してその原因を突き止める行為だと思います。

まず、仮説を立てるために必要なのが情報です。
自分の目の前で起こっている「異常」をログやスクリーンショットからかき集め、
そこからその異常がどこから発生しているのかを考えます。
これがPlanにあたります。

次にかき集めた異常から、異常の発生源にに対して何らかの変更を加えたり、処理を追加してみる。
これがDoにあたります。

Doから得られた結果を確認するのがCheckです。
変更を加える前後で変化があったのか否か。
変更を加えた際に自分が想定した結果が返ってきたのかどうかこれを確認する作業です。

最後にその結果から新しいActionを起こします。
例えば「数値を与えたらnilが返ってきたから次は文字列を与えてみよう」みたいな感じです。

そしてこの一連のPDCAを行って得られた結果からまた新しいPDCAを実行してどんどん異常の根源へと近づいていく、デバッグとはそういう行為であると学びました！

## 先入観、思い込みは捨てよう
今回のissue、PRでのデバッグの際に僕は仮説を立てる段階でかなりの先入観を持っていました。
それは「原因は自分のマシンスペックに違いない」という先入観です。

なぜかというとメンターの方からいただいたコメントで、メンターの方の環境では必ずテストがパスするという情報が得られたためです。

そしてこの先入観が悪さをします。
そう、仮説と検証を怠らせてしまうんです。

今回、自分の環境で発生したエラーは以下のようのものでした。

- `assert_text 'hoge'`が通るときと通らない時がある
- 通らない時は`foo`というテキストが表示されている

この事実と自分の環境以外ではテストが毎回パスするという情報から僕は「これはマシンスペックが低くて前後のテストの影響を受けているに違いない」と決めつけて誤った方向でのデバッグを進めてしまいました。

結果、テストは通るようになったものの根本的な解決にはなっておらず、また、「通らない時は`foo`というテキストが表示されている」という危険信号をミスミス見逃してその原因究明を放棄してしまいました。

これが実務となると、爆弾を放置することと同義であり大変危険な行為だと思いました。

今回のケースに限らず、先入観や自分の実装に対して自信がないとどうしてもそっちに意識が入ってしまい、判断を誤りがちです。

先入観とは無意識に持ってしまうものだとは思いますが、ことデバッグの際にはより一層先入観に対するアンテナを持つべきだと感じました。

## エラーが起きないからOKは全然OKじゃない
> 結果、テストは通るようになったものの根本的な解決にはなっておらず、また、「通らない時は`foo`というテキストが表示されている」という危険信号をミスミス見逃してその原因究明を放棄してしまいました。

自分はエラーを解決することばかりを急いでしまい、エラーの根源を確かめることをしていませんでした。

何か異常が発生している場合は必ずそこに原因があります。
その原因を突き止めないまま先に進む行為は時限爆弾を無視する行為と同じです。

デバッグにおいては仮説と検証を繰り返すことでその異常の原因を突き止め、確実に爆弾を止めなくてはいけません。

その行為を繰り返し行うことでエンジニアとしての基礎力が養われていくのだと感じました。

## 仮説と検証まとめ
今回のペアプロを通して自分のデバッグ力が弱いことに気づくことができました。
その原因は下記と考えてます。

- スピードばっかり意識して本質を見ようとしていなかった
- それ故に早期に原因を決めつけてしまい誤った方向へ進んでしまっていた

デバッグとは仮説と検証を繰り返すことで目の前で起こっていることを正しく理解する行為であり、そしてそれを愚直に繰り返すことでより精度の高い仮説を立てられるようになるのだと思います。

これこそがエンジニアとしての基礎力であり、プロとして求められるスキルなのだと感じました。

これからは時間をかけることを厭わず、基礎力向上と心に言い聞かせてデバッグ、仮説と検証に注力していきたいと思います。

# デバッグ時のTips

## save_screenshot
Capybaraのメソッドでシステムテストにおけるテスト時のスクリーンショットを保存してくれるメソッド。

システムテストではテストが失敗した際にテストが落ちているところでスクリーンショットを保存してくれますが、save_screenshotは任意の場所でスクリーンショットを保存できるのでデバッグの際に使用するとデバッグ効率が上がります。

スクリーンショットの保存先は`app/test/tmp/capybara`です。

## エディタの検索機能を駆使する
自分は普段VSCodeを使用しているので`Shift` + `command` + `F`でプロジェクト内の検索ができます。

エラーログに出ている怪しい文言などがあれば、その文言を検索にかけることで異常が起きているファイルを絞り込むことができます。

検索は積極的に使用していこうと思います。

## db/schema.rb
データベースの情報の宝庫です。
テーブルやカラムについて調べたい時はこちらのファイルで検索を行うとあっという間に情報が得られます。


# まとめ
初めてのペアプロで自分の不甲斐なさを痛感しましたが、それよりも多くの気づきがあり、自分の弱さ、改善点を見つけられたのは僥倖でした。

基本テキストベースでのコミュニケーションしか取ってこなかったため、このような気づきとは無縁でした。

メンターの方と１対１は緊張するのでハードルが高く感じていましたが、それ以上に得られるものが大きく、積極的に活用していきたいと思いました！

今回は自分の手元を見てもらうのみでしたが、おそらくメンターの方の手元を見せていただいたら、「今のショートカットどうやったんですか？」みたいな細かいテクニックをたくさん得られる気がします。

こういった気づきはやはりテキストだけでは得られないので、失敗や緊張を恐れず、積極的に活用していきたいと思います。

デバッグが苦手だな...
ペアプロってなんか緊張するし敷居が高くて頼みづらいな...
そう感じている方々の参考になれば幸いです。

## あわせて読みたい

今回の記事の中でも紹介させていただきましたが、デバッグの進め方や取り組む上での心構えなど、デバッグが苦手な方のヒントになる内容が詰まっていると感じたので、是非一緒にご覧ください！

[デバッグは「うまく動かないピタゴラ装置の原因調査」だと考えてみよう \- Qiita](https://qiita.com/jnchito/items/e4b75ff2c3eeccfffec1#%E4%BB%AE%E8%AA%AC%E3%81%A8%E6%A4%9C%E8%A8%BC%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%97%E3%81%A6%E9%9A%A0%E3%82%8C%E3%81%9F%E3%83%90%E3%82%B0%E3%82%92%E3%81%A9%E3%82%93%E3%81%A9%E3%82%93%E8%BF%BD%E3%81%84%E8%A9%B0%E3%82%81%E3%82%88%E3%81%86)