問題への取り組み方
はじめに
大きな機能の設計・実装を任された。本番環境で発生した障害の調査を任された。プログラム開発中のエラーが発生した。一般の方にはカッコいいイメージが持たれがちですが、エンジニアやプログラマの日常はこのような様々な問題に地道に取組む日々でもあります。
問題への対応を間違えば、時間をむだに費やすことで多方面に影響を及ぼすだけでなく、自分自身の成長も遠回りすることになります。
本稿では、主に新人エンジニアの方々に対して、問題への取り組み方について紹介したいと思います。
アンチパターン
最も大きな間違いは問題の解を直接求めることです。これには3つのパターンがあります。
いきなりクグる
いきなり検索エンジンで答えを求めるのはやめましょう。答えは簡単に見つかるものではありません。どれだけ時間をかけてググっても答えは見つからないのです。仮に簡単に見つかるのであれば、それは問題ではないのです。
私たちエンジニアは新しい価値を産み出すために仕事をしています。新しい価値を実現するための答えは世の中にまだないのです。自分達で見つけるしかありません。
もちろん、エラー発生時にググってエラーメッたセージを調べることはあるでしょう。しかし、それは既知の現象の意味を調べているに過ぎません。
問題をそのまま扱う
大きくて複雑な問題に真正面から立ち向かっても解決できません。なぜなら、複雑な問題は関連するパラメータが多過ぎるため、それらを完全に理解して制御することはできないのです。
複雑な問題の解を直接求めるのは普通の人間には困難です。どれだけ時間をかけても答えは見つからりません。
トライアンドエラーを繰り返す
エラー発生時、闇雲にトライアンドエラーを繰り返して原因を追究する新人エンジニアがいます。これは時間の無駄なのでやめましょう。
たとえ、これによって解がたまたま見つかったとしても、それは真の解決ではありません。根本的な原因の理解に至ることは少ないですし、今後もこのような非効率な方法を繰り返すことになります。
どうすべきか?
小さな問題に分解する
大きな問題は小さな問題に分解しましょう。これを分割統治法と言います。分割された小さな問題はプログラムレベルではモジュールと呼ばれます。各問題は再帰的により小さな問題に分けていきます。最終的にクラスや関数(メソッド)といったそれ以上分けられないモジュールまで小さくなるでしょう。
問題分割に当たって大切なことは、HowではなくWhatに意識することです。サブ問題(モジュール)が何(What)を解決すれば、最終的な問題の解が求められるのか?という思考です。これは尋ねるな、命じよというプログラミングの原則にも通じます。
それ以上分解できない問題まで分割できれば、そこで初めて解を求め方(How)を検討することになります。
仮説、検証を繰り返す
本番障害やプログラムのエラーに取り組む場合は、まず原因の切り分けが必要です。これは前節の小さな問題に分割するの考え方にも通じます。
まず、障害やエラーが発生する考えられる原因を列挙、つまり仮説を立てます。次にそれぞれの仮説を検証することで原因を絞り込んでいきます。
例えば、データベースへの接続障害が発生したとします。この場合、ネットワーク障害、
データベース障害、データベースの接続情報の設定ミス…などいくつかの要因が考えられるでしょう。それらの要因を1つずつ検証して真の原因を見極めます。
この仮説・検証のサイクルは最終的な原因が見つかるまで、再帰的に繰り返します。
一次情報をしっかり確認する
本番障害やエラーが発生した場合、まずは一次情報をしっかり確認しましょう。この場合、一次情報とは、エラーメッセージやエラーログのことです。
一次情報を無視してトライアンドエラーを繰り返すのは愚の骨頂です。これはベテランエンジニアでもたまに起こります。ベテランエンジニアはこれまでの経験から認知バイアス、つまり間違った先入観により時間を浪費することがあります。
まとめ
今回は特に新人エンジニアの方に対して、問題への取り組み方について私見を述べました。まず、アンチパターンをいくつか紹介した上で、いくつかの方法論について論じました。抽象的な話で終始してしまいましたが、新人エンジニアの方に少しでも有益な結果となれば幸いです。
Discussion