Secret Ninja Blog

Support Engineering Director してます

テクニカルなトピックやIssueの良い質問の仕方

コンテキストが共有されていないことによって、質問の意図が汲み取れず、回答にたどり着くまでに非常に時間や手間がかかってしまう様子が散見されてたので、下記のツイートをしたところ、それなりに皆さん困っているんだな・・・っていうのが見受けられたので、社内向けに英語で書いた内容をDeepLとかを使って日本語にざっくり直したので、言葉の揺らぎなどもあるが記事として残しておく。

そもそもなぜ良い質問の仕方を学ばないといけないのか?

当たり前のことかもしれないですが、下記の3点がコミュニケーションの意思決定として多分に左右するものであり重要なため、事実として受け止めておく必要があります。

  1. 言語:私たちの多くはマルチリンガルですが、英語(や日本語)を母国語としない人も当然多くいます。シンプルに、明確に、そしてダイレクトに説明するための努力が必要です。
  2. 場所:グローバル企業、OSS活動、コロナ禍におけるリモートワーク。多くのケースにおいて、日本国内にかぎらず、さまざまな場所に拠点を置いているため、相手が常に自分の質問に回答できる状態ではないです。タイムゾーンが異なれば、回答に1日かかることもあるし、様々な都合で対応がすぐにできないことなどあります。
  3. 文脈:同じお客様、同じプロジェクトであっても、私たちは常に同じ文脈を理解しているわけではありません。昔から働いている人もいれば、新しくジョインしたばかりの人もいます。ある人は1つの顧客やプロジェクトに専念している場合もありますし、複数を浅く広く担当している人もいます。

そして、どんなに経験を積んでいても、誰もが仕事で誰かに質問しなければならないことがあります。上記の事実を踏まえて、質問をする人は、相手の時間を尊重し、必要な答えを得るチャンスを最大限にするようにしなければなりません。

なぜなら、不適切な質問/問題報告は、ほとんど価値をもたらさないだけでなく、相手の貴重な時間を費やすことになり、ほとんどのプロジェクトでは通常その余裕がないからです。質問や問題をトリアージする人にとって、情報の混乱や不完全さのために追加の質問を何度も送り返さなければならないことほど、時間を浪費するものはありません。

サービスのテクニカルな内容に関するより良い質問の仕方

1. 事前に調べる

助けを求める前に、自分で解決しようとすることです。質問することに抵抗感を持つ必要はないですが、相手の時間を尊重し、まずは自分でできるかどうかを試してみましょう。

ここで重要なのは、調査の時間に期限を設けることです。具体的にどのくらい待つかは、プロジェクトの緊急性などによりますが、通常は30分から数時間の間にしてください。

数分調べれば答えが出るような質問を繰り返していると、人に頼りすぎてしまい、自分の検索スキルを高める機会を失ってしまうかもしれません。逆に、他の人が数分で教えてくれるような答えを、何時間も何日もかけて探すようなことが多いと、自分やチームの生産性が低下してしまいます。

このバランスを取ることが、生産性を維持しながら自分自身のスキルを向上させるための重要なテクニックです。ここでは、答えを見つけるためのヒントを紹介します。

  • Slackなどのコミュニケーションチャンネルで関連情報を検索する
  • Confluenceなどの自社のナレッジベースで関連情報を検索する
  • Google でエラーメッセージを検索し、仮説を立てる。
  • Githubでエラ〜メッセージやコードを検索する
  • Jiraなどの自社のバグトラッカーで、過去チケットを検索する。解決した場合は、どのようにして、なぜ解決したのかを理解しようとする。解決しなかった場合は、その旨をメモしておきます。

これらの方法で解決できなかった場合は、パブリックなslackチャンネルして質問をしたり、Jiraでissueを報告したりします。

2. 質問や課題を十分な文脈と共に書く

質問をするべきだと判断したら、質問に答えてくれる人にできるだけ多くの文脈を提供することが役立ちます。

例えば二つの質問をSlackでするとします。

  1. "@here デプロイが失敗したんですが、原因わかりますか?"
  2. "サービスXのデプロイ中に'xxxxxx'というエラーメッセージがログに出力されて、デプロイが失敗しました。直前に行った変更は'Pull Req X'です。何が原因か見てもらえますか?ログは[link]にあります。ステージング環境での失敗なので、緊急性は低いです。よろしくお願いします。"

前者では、誰も反応してくれないか、反応してくれた場合でもその人は問題を明確にして状況を把握するために、あなたとの長いやりとりを強いられることになります。

後者では、相手が問題を理解するのに十分な情報を得て、あなたを助けてくれると思います。

チームメイトの時間を節約し、答えを得る可能性を高めるためには、できるだけ多くの状況を提供することが役立ちます。回答者はすべてを知っているわけではなく、回答者自身も自分で調査する必要があることが多いため、予め必要な情報を出しておくことで大きな違いが生まれます。

例えば、サービスで問題が発生した場合、実際のエラーやジョブを確認するためには、以下のような情報が有効です。

  • 環境 ( 開発 / ステージング / プロダクション )
  • AWSのどのリージョン
  • システムのリソースIDなど
  • 変更の内容がわかるPull Reqなど
  • 実際のエラーメッセージとリクエスト、レスポンス(スクリーンショットではなく、テキストで)

エンジニアであれば、内部で広く採用されている一貫性のあるシステムラベルなどがあると思うので、そういったものを明示的に利用するとよいです。

3. 再現するための正確な手順を書き、これまでに試したことを列挙する

相手が問題を再現できないことを常に想定しておくことが大切です。それは、あまりにも多くの潜在的な変数が関係しているからです。問題が再現できない場合、その問題を解決して回答することは、不可能ではないにしても、非常に困難です。問題が発生したときに何をしていたかという文脈と、問題を発生させるために行った最小限の手順を提供することで、多大な労力をかけずに問題を再現することができます。

文脈を提供するだけでなく、質問者がすでに試したことを相手に伝えるのも有効です。質問をする前にステップ1に従って自分で調べたのであれば、すでに試した方法があるはずですし、少なくとも検索した内容のリストがあるはずです。文脈を提供するのと同様に、自分がすでにやったことを相手に伝えることで、相手があなたを助けている間の行き違いをなくすことができます。

あるアプローチがうまくいかなかったことを知っていれば、うまくいきそうな方法をより簡単に見つけることができます。また、あなたがすでに知っているすべての方法を試していることがわかれば、より専門的な知識を持った他の人に指示を出す必要があることもわかります。

ですから、問題に遭遇したら、すぐにできるだけ文書化してください。そして、その問題を再現してみてください。問題を再現したら、再現するために必要な最低限の一連の出来事を記録します。可能であれば、スクリーンショットやビデオを添付してください。さらに、問題を再現するために、彼らが理解しやすいコードを提供するとより良いでしょう。

特に、コードを提供する場合、下記が実現できているかを確認すると良いでしょう。

  • 最小限 - 同じ問題を解決するために、できるだけ少ないコードを使用します。
  • 完全 - 問題を再現するために必要なすべてのパーツを質問の中で提供する。
  • 再現性 - あなたが提供しようとしているコードをテストして、問題が再現されることを確認してください。

Ref. How to create a Minimal, Reproducible Example - Help Center - Stack Overflow

以下に良い例と悪い例を示します。

悪い例 (再現できる例がない)

APIを使ってHiveにクエリを実行しました。しかし、"Schema public does not exist "というエラーが発生しました。原因を教えてください

良い例(実際のcurlリクエストとレスポンス)

Production環境のHiveを実行するためにAPI経由でクエリを実行し、そのジョブのステータスを確認した結果"Schema public does not exist "というエラーが返却されました。以下に再現手順を示します。再現環境ではXXXのYYYユーザを使用しています。

1 - 下記でクエリを実行

% curl -X POST -H "AUTHORIZATION: " https://api.xxxxxx/yyyy/hive_query -d 'query=SELECT * FROM public.test' 
ログ

2 - ジョブのステータスを確認。

% curl -X GET -H "AUTHORIZATION: " https://api.xxxxxx/yyyy/job_status | jq
ログ
Schema public does not exist

先日XXXのジョブを実行した際には同様の操作で正常に結果が帰ってきました。このジョブがなぜエラーが発生するかわかりますか?Jiraでこのエラーを検索しましたが、同様の問題は見つかりませんでした。これは私のテストで利用しているものなので、この問題の優先順位は高くありません。

4. 問題の背後にあるゴールと緊急性を記述する

さて、ここまである程度質問・問題を明確にするための良いサマリーができました。しかし、(プロジェクトでの近い関係であればともかく)他の人はあなたが何のために働いているのかわからないので、質問の背景にあるゴールと緊急性を説明しなければ、あなたが期待していない仕事をする可能性があります。そして、他の人自身も自分の仕事に責任を持ってスケジュール通りにタスクを完了する必要があります。だからこそ、質問の目的と緊急性を適切な文脈で表現する必要があるのです。

実際、"ASAP"や至急と言った言葉は、コミュニケーションが苦手な人や、英語を母国語としない人がよく使うように思います。例えば、"@here デプロイが失敗しました。大至急調査してください」といった具合です。しかし、この方法では、実際の緊急性やゴールを示すことができていません。例えば、調査してエラーの原因を特定したいのか、調査して回避策を知りたいのか。大至急というのは1時間以内、1日以内、1週間以内に問題を解決したいのか、そしてなぜそんなに急いでいるのか?といったことです。

次のようなアプローチをとることで、回答者はゴールと緊急性を理解するのに十分な状況を把握し、あなたの手助けを始めることができます。

”サービスXへのデプロイが失敗し、ログにYのエラーメッセージが表示されました。直近で行った変更はZでした。明日までに原因を特定したいと思います。なぜなら、私たちの本番環境へのリリースは2日後に予定されているからです。そのため、それまでには修正や回避策を考えたいと思います。ログは[リンク]から、私の変更に対するプルリクエストは[リンク]から参照できます。”

このような情報がなければ、回答者はあなたの質問に答えるためにどれだけの時間を使うべきか、優先順位をつけることができません。

5. 答えを書き留める

最後に、質問をして答えが得られたら、必ずその答えをどこかに書き留めておきましょう。すべてを知らなくても問題ありませんが、答えを書き留めていないために同じ質問を何度もしなければならないのであれば、相手の時間を尊重していないことになります。 "動きました!”だけではなく、”このコマンドを実行した結果、期待通りの結果が得られました。”と書くことによって、最終的な結論をシェアすることができます。さらには、Wikiなどに回答を追加することも検討してください。同じ質問をする人が今後でてくるはずなので、解決策を公開することで、将来的に他の人の時間を節約することができます。

場合によっては、予想外の回答が返ってくることもあるでしょう。 例えば、APIのレスポンスが期待しているものを返さなかったりとか、仕様の定義が自分の期待するものとは違っていたりということがあると思います。なんでこんな変な挙動なんだ!と苛立つこともあるかもしれません。 しかし、自分たちのサービスが成長途中であるときに、早く市場にサービスを提供するために、意図的に「間違った」方法で何かを行っていたり、あるいは、ビジネスの成長に伴い、当初のユースケースでは現在のユースケースをカバーできなくなった。こういったことはよくあることです。 その背景にある歴史を尊重し、理解する必要があります。そしてその後に、もっと良くしたいと思ったら、機能改善をしたり、Issueとして報告したりサービスの一員としてよりよくしていく建設的な活動をしましょう。