こんにちは、かきぴーです。
僕は現在、スマホアプリのサーバーサイドエンジニアとして働いています。
自社サービスを運営しているため、自社サービスの機能追加や不具合修正、リファクタリングなどが主な業務です。
(1から新しいアプリやAPIを作るといった業務はしたことありません)
今回は、僕が就職してから学んだこととして、「不具合への対処方法」についてまとめてみようと思います。
- エンジニアの仕事内容がイメージできない
- 自社サービスの開発者って何しているんだろう
- 不具合とかエラーとかの対処方法について知りたい
という人は、ぜひ参考にしてみてください。
toC向けのサービスの話に偏っていますが、一サンプルにはなると思います。
不具合は、エラーログor問い合わせで発覚しがち
まず、不具合の見つかり方ですが、僕が知っている経路は以下の3つ。
- エラーログ
- ユーザーからの問い合わせ
- 社内の人間が使っていて気づく
プログラミングの勉強をしていたら、エラーログはみたことがあると思います。
PHPだったらApacheのログとして出力されますし、JavaScriptだったらconsoleに出てきますね。
サーバーでのエラーは、各サーバーにログとして残りますので、それを可視化するツール(kibanaとか)を使ってエラーを監視することができます。
スマホアプリでも、FabricなどのSDK(software development kit / 開発者向けのツールの詰め合わせのこと)を使って、アプリがクラッシュ(予期しない動作をして勝手にアプリが落ちる事)したことを感知できたりします。
何か新しい修正をリリースするときには、必ずリリース前後に、エラーログの監視を行います。
もしリリース後に、エラーが出たら、そのリリースを元に戻したりするわけです。
もう1つがユーザーからの問い合わせです。
「〇〇が使えない」とか「〇〇の様子がおかしい」とか、ユーザーから問い合わせがあることで、発覚するパターンですね。
その他には、社内の人間から指摘されることもあります。
開発チームの他のメンバーから指摘されることもあれば、他の課の人から指摘されることもありますね。
不具合発覚で一番多いのは、ユーザーからの問い合わせ、次にエラー、その次に社内の人間からという感じです。
テスト環境では見つからなかった不具合が、本番リリース後に発覚することが多いイメージですね。
不具合が見つかったらどうするか?
ユーザーからの問い合わせがあった場合や、社内の人間から指摘があった場合は、以下のような流れで対処していきます。
(エラーログが出た場合は、問答無用でrevert(リリース前の状態に戻すこと)します)
- ステップ1:不具合を正確に把握する
- ステップ2:不具合原因の切り分けを行う
- ステップ3:不具合原因の特定をする
- ステップ4:修正による影響範囲を考える
各ステップについて細かくみていきましょう。
ステップ1:不具合を正確に把握する
不具合が起きた時に、最初にすることは「不具合の把握」です。
不具合を把握することで、不具合の緊急度と影響範囲が見えてきます。
ここの結果で以降の対応が変わるので、迅速かつ確実に行わないといけない、重要ステップです。
知りたいのは以下の情報。
- 誰から指摘されたか?
- いつ発生したか?まだ起きているか?
- 誰に影響があるか?
- どの動作で発生しているか?
- 不具合を再現できるか?
です。
不具合の影響範囲について
大事なので、1つ1つ見ていきます。
まず、「誰から指摘されたか?」ですが、ユーザー問い合わせなのか?クレームに発展しそうか?というのは重要なポイントです。
もしクレームに発展しそうな不具合であれば、早急に、確実に潰す必要があります。緊急かつ重要度Maxです。
次に「いつ発生したか?まだ起きているか?」ですが、不具合の発生期間を特定します。
期間がわかることで、不具合の影響範囲が見えてきます。
続いて、「誰に影響があるか?」。
- 社内の環境だけか?
- 一部のユーザーだけか?
- iOSユーザーだけか?
- はたまた全ユーザーに発生しているのか?
影響のあるユーザーが多ければ多いほど、重要度が高い問題になります。
そこまでわかったら「どの動作で発生しているか?」と「不具合を再現できるか?」を見ていきます。
たとえば、新規登録やログイン、決済周りで不具合が出ていたら、緊急かつ重要度Maxになります。
また表面化している不具合以外で、問い合わせや不具合がないかどうかもチェックします。
不具合が起きうる動作が、他にもあった場合、以降の原因追求作業がうまくいかないからです。
ここまで明確かできたら、不具合の再現方法を確認し、原因を探すステップに移ります。
ステップ2:不具合原因の切り分けを行う
不具合の影響範囲が見えてきたら、次に不具合の切り分けを行います。
これは、「ここは絶対に不具合の原因じゃない。大丈夫」といえる箇所を増やしていくイメージです。
たとえば、ある日突然で始めた不具合であれば、その日以前のソースは安全である可能性が高いです。
不具合発生日以降のリリース箇所を検討する必要があります。
またサーバー側の同じファイルにアクセスしているのに、iOSとAndoridで挙動が異なれば、アプリ側の不具合である可能性が高いです。
逆に、iOS、Androidともに同じように不具合が起きていれば、サーバーの問題である可能性が高いですね。
このように、「ここは不具合の原因ではない!」というのを見つけます。
ステップ3:不具合原因の特定をする
どうやらこの辺に不具合があるぞ、ということがわかったら、不具合の特定に入ります。
不具合の特定は、怪しい箇所を順にスキャンしていくイメージです。
まずは怪しい箇所周辺のソースを読み込み、仮説を立てます。
仮説を立てたら、いろんなところにログを仕込んで、不具合を再現してみます。
PHPだと、
error_log("debug log".__LINE__"\n",3,"/var/www/test/log/debug.log");
みたいなのを入れまくります。
そうすると、不具合の時にどこのソースが実行され、どんな値になっているか見えてくるので、
「何行目を通ったけど、何行目は通っていない。ってことはこの分岐の結果が想定と違う? なら判定につかっている変数$hogeって何がきているんだろう…」
みたいな感じで「何行目のこいつが悪い!」とか「DBから思った値がきていない!ってことはinsertのとこが悪い!」みたいな感じで、原因がわかります。
仮説→怪しところにログ→動かす→結果からさらに仮説を立てる…
というのの繰り返しです。
応急処置は基本的に避ける
不具合の調査をしていると、「原因はよくわからんが、こうすれば現象自体は消えるっぽい」というのを見つけることがあります。
ですが、基本的にはこういった応急処置的な手当ては避けるべきです。
理由は2つ。
- 他にも不具合が起きる可能性があるから
- ソースが汚くなるから
たとえば、DBに入っている値そのものがおかしいのに、受け取る側の処理だけを整えた場合、今後同じテーブルを使った処理を作ったときに不具合が起きる可能性があります。
また「まだ発覚していないだけの不具合」が潜んでいる場合もよくあります。
その場合、不具合を見つけるたびに応急処置をしていたら、どんどん同じような処理が増えていってソースが汚くなって、他の不具合の温床になりかねません。
応急処置を使うのは、「緊急度が高く、どんな手を使ってでも今すぐに修正しないといけない」かつ「調べたが原因がわからない」という場合だけにしましょう。
ステップ4:修正による影響範囲を考える
不具合の原因がわかったら、修正方法を考えています。
修正する時に気をつけるのは、「二次被害がでないこと」です。
たまに、不具合修正が原因で、別の不具合が起きることがあります。
特に、複数ファイルで使われている関数で不具合を出したりすると、サービスに甚大な被害を及ぼしかねません。
もし、影響範囲が大きい箇所を修正する必要がある場合は、臨時で別関数を作ると影響を一部に留められます。
たとえば、getTestRow()という関数が複数ファイルで使われていて、1つの呼び出し元で不具合が起きている場合、あえてgetTestRow2()という不具合修正済みファイルを作り、不具合が起きている呼び出し元だけで使うなどすると影響範囲を絞れます。(※ソースはめちゃくちゃ汚くなりますけどね…!)
不具合を修正した場合は、影響範囲が特定できていること、影響範囲に関してテストをしっかり行ってリリースを行うのが大事です。
まとめ
僕自身が行っている、不具合への対処の仕方についてまとめてみました。
実際には、この手順通りではなく、複数の手順を同時に行ったり、手順を行ったりきたりしたりすることが多いです。
ですが、最終的には、今回挙げた要素すべてを明らかにしていきます。(じゃないと不具合修正完了といえない。。。)
- ステップ1:不具合を正確に把握する
- ステップ2:不具合原因の切り分けを行う
- ステップ3:不具合原因の特定をする
- ステップ4:修正による影響範囲を考える
細かい話が多かったので、未経験エンジニアの人にはわかりにくい記事になってしまったかもしれません。
(逆に、ベテランの方からみたら、それは違うだろ!とかそれは下手なやり方だ!とかもありそう。。。ご指摘ありましたら、そっと教えていただけるととても嬉しいです。。。)→@kakipy722
1サンプルではありますが、プログラミングの勉強や仕事で詰まった時の参考になったら嬉しいです。
また書きますね。
コメント