シンプルに考えるということ @Tomofiles
目次
はじめに
こんにちは、Tomofilesです。
今回の記事は、物事をシンプルに考えることを心がけると、問題解決能力が上がりますよ、というお話です。
何か物事にアプローチするときに、皆さんはどこからどうやって、取り組み始めますか?
自分が今書いているソフトウェアのソースコードのバグ一つとっても、どうやったら解消するかと考え、バグを取り除こうとする営みは、問題解決にほかなりません。
問題解決能力が上がると、自分にとってのわかるという感覚が、わかるようになります。
何か問題を解こうとする取り組みは、そのまま何か知らない知識を理解しようとする、自分だけの方法論にもなります。
ぜひ、皆さんもこの記事を読んで、自分だけの問題解決方法を見つけてみてください。
とあるシステムの障害対応
私の経験談になりますが、こんな経験をしたことがありました。ちょっと長いです。
私が新人で参画した、ある超大手銀行の資金取引システムの開発の総合試験のフェーズで、ある事件がありました。
そのシステムは、複数の銀行のシステムと接続し、取引の資金授受をリアルタイムで行うもので、取引を表すデータを送受信して銀行の残高を更新していくものでした。
総合試験というのは、ほとんど実際の業務に即した(というか、本物の銀行のデータ)を使用して、動作検証をしていく試験になります。
特に、自行のデータだけでなく、他の銀行のデータも連携して試験をしていくので、発生する不具合事象というのは、それだけ深く難解を極める場合があります。
ある他行との結合試験を実施している際に、データの中身が意図しない内容になっていることが原因で、自行のシステムで受け取れないという事象が発生しました。
大体、関係者が他行までかかる試験は、タイムチャートを組み、その計画に従って他行と連絡を取り、試験を進めていきます。
不具合事象が発生すると、スケジュールがストップするので、早く状況を把握し、対策を決めて、他行に報告しないといけません。
現場は、緊張感に包まれ、リーダークラスのメンバーが、自らテキパキ動いて対応に当たるような状況になります。
データ受取エラーとなったのは、自行内システムの末端であり、その末端と、他行への連携システムの間には、自行用の中継システムを介していたため、意図しないデータが発生した場所が、具体的にどこのどのシステムなのか、現時点ではっきりしません。
このときのデータ不正の内容的に、実は、ほぼ自行システムが起因の事象ではないのでは、という意見が多かったのですが、確証は得られてなかったのです。
他行に、「自行が起因の事象ではない」と報告したいですが、確証がないので主張できないのです。こういうときに、想像で下手なことは対外には言ってはいけません。
早速、原因究明に取り組むため、リーダーの一人が以下のような、図をホワイトボードに描きました。
ほぼ、当時(もう5〜6年前)のことを思い出して、そのまま書いています。
「自行が起因の事象ではない」というのは、つまり、自行が受け取った時点で、すでに意図しない状態になっていた、ということを証明する必要があります。
自行の範囲は、上図では黄色で塗りつぶされているのが、その対象です。
まず一つ、解析をはじめて、わかったことがありました。
中継システムA、Bは、受信したデータのヘッダを取り除いたり、一回データベースに永続化してから、次のシステムに連携したりしていたため、確実にシロだと言えない、ということでした。
データを少しでも触っているのであれば、こういう場合は疑ってかかるべきです。
上図には、中継システムを含めて、すべての関連システムが記載されていました。
すべての登場人物(関連システムなど含めて、よくこういう風に表現します)をとりあえず登場させ、まずは全体像を掴むのです。
下図は、これらの要点が追記されたものです。
赤字で図示し、全体像を捉えたまま、新情報を追記していきます。
こうしてわかったのは、業務システムに至るまでの、各中継システムにおいて、本事象が発生しうるかどうか、仕様を確認する必要があるということです。
また、上には書かなかったですが、中継システムBのログを確認することで、自行が一番最初に受信した際の状態を確認できます。
次に、また判明したことがありました。
中継システムAでは、データベースに永続化してから次のシステムに連携する仕様となっていましたが、詳細に調べてみると、データの中身は一切の手を加えず、データの格納・取得だけ行っているということでした。一応、ログを見ても、その裏付けが取れました。
つまり、中継システムAはシロということです。
ホワイトボードは、下図のように、シロになった範囲が対象外とされていきます。
全体から、一部範囲が対象外になり、原因が含まれる領域が小さくなって、解明に一歩近づきました。
そして、さらに、判明したことがありました。
中継システムBでは、受信したデータのヘッダーは除去していましたが、ペイロード(データの正味の部分)は一切触っていないので、データの値レベルで内容が変化する可能性はない、ということが調査してわかりました。
このとき、例えば文字コードの不一致等の文字化けも可能性として考えられますが、文字化けの場合、データ全体が不正になる可能性が高いのですが、今回は一部のデータ項目に限られており、全体には及んでいませんでした。
また、ログも確認して、受信したデータ自体の内容が、すでに不正だったことも確認できました。(このときは、ログがアーカイブされており、調査に時間がかかった)
つまり、中継システムBもシロでした。
リーダーの一人が、ホワイトボードにその結果も描き込み、図で見ても、自行範囲の起因による事象ではないことの確証が得られました。
ホワイトボードは下図のようになりました。
こうして、他行に対してデータ不正の可能性を指摘して、スケジュールのタマ持ちを相手に渡すことになったのです。
複雑な事象をシンプルに切り分ける
私は当時、リーダーたちの、この鮮やかな事象解決の取り組みを、注意深く、でも非常に感心して、眺めながら、手伝っていた記憶があります。
この事象解決へのアプローチには、見習うべき重要な点がいくつか含まれています。
整理すると、以下のようになります。
- 事象解決のゴールを決めること
- 図を描いて、何よりもまず、全体像を把握すること
- 全体から、適切に部分を切り分けていくこと
- 各部分が、原因である/原因ではないことを、証明する方法を決めること
一つずつ見ていきましょう。
事象解決のゴールを決めること
何か問題にぶち当たり、それを解決しないといけない状況になったとき、一番重要なのは解決したというのは具体的にどういうことか、というのをはっきりさせることです。
そんなの当たり前じゃんと思うかもしれないですが、チームで問題に取り組む場合、その当たり前が全員に共有されていない場合があるのです。
というか、全員が同じことを考えていることなど、絶対にありません。言葉にして、しっかりと共有しないと、絶対に伝わっていません。長年同じメンバーでやってきたチームだとしてもです。
往々にして、このゴールを決めるということが軽視されがち(SIerでやっていると、特に感じますが)なのですが、非常に重要です。
今回の、上記の経験談においては、「自行が起因の事象ではないことを証明する」というのが、ゴールでした。
当時私は新人に毛が生えたレベルでしたが、リーダーたちが、このゴールを先に明確にしておいてくれたから、私でも状況を把握できて、今でも記憶に残っているのだと思っています。
図を描いて、何よりもまず、全体像を把握すること
図を描くことは、とても大切なことです。
図を描くことで、視覚的に全体像を認識できるので、自分が取り組むべき問題空間を捉えることができます。
問題空間というのは、別に怪しい思考論の話などではなくて、問題を解決するために便宜的に設ける、枠みたいなものです。
問題解決にも色々種類はありますが、今回のような「ある原因を究明する」というアプローチの場合は、手当り次第調べるのは効果的ではありません。
原因が含まれていそうな範囲を便宜的に決めて、その枠の中から、関係ない部分を取り除いていき、徐々に原因が含まれる領域を絞っていって、原因までたどり着こう、というアプローチが、最も効果的です。
手元に、調べるべき事・物がある状態で、その全部の中から、関係ないのを落としていけば、手には原因が残る、という考え方ですね。
この思考法を活用するにあたり、まず図を描くことで、手元に置くべき、調べるべき事・物の全量を、認識することができます。
それから、図を描くことにより、他の人もその図を見て、認識を共有することができます。
言葉で伝えることも重要ですが、図を描くことで一瞬で通じることもあるので、図というのは非常に効果てきめんなのです。
全体から、適切に部分を切り分けていくこと
上記までで、全体の枠を決めて、関係ない部分を取り除いていく、という話をしました。
正直、この関係ない部分、というのを、どのように決めるのか、非常に難しい問題で、こうすればいいという案はお話できないのですが。
経験談の例では、自行内システムすべてを問題空間と定義して、その中でシステムごとに部分を分けていました。
すべてのシステムがシロであれば、自行内に原因が含まれないことが証明できるので、まず取っ掛かりとしてシステムを部分として、調査を開始してみたという例です。結果的に、今回の事件は、その部分の切り分け方で正解でした。
ある程度適切な単位で、部分が切り分けられていると、その部分が今回求めている原因かどうか、判断する方法がはっきりしてきます。
つまり、部分(ある機能の一部分)と不具合事象との、一対一の比較検討になるため、よりその関係性が浮き彫りにされるのです。
全体と部分という関係で、原因の所在にアプローチでき、部分と不具合事象という一対一の比較検討により、原因の内容に対するアプローチの質が向上するということなのです。
各部分が、原因である/原因ではないことを、証明する方法を決めること
適切に部分に切り分けられれば、あとは部分と不具合事象との一対一の、比較検討になります。
もうあとは、その部分に、原因が含まれるか、含まれないかを探っていけばいいのですが、調査をするにあたり、一つ気をつけるべきことがあります。
それは、調査を始める前に、原因をある程度、推測しておくことです。
経験談の例では、調査をはじめてすぐに、ホワイトボードの図に赤字で追記したことがあります。
これらは、今回の不具合事象に対して、受信したデータを加工・編集する可能性のある処理を、先に洗い出し、それらの処理が原因である可能性を、目に見えるかたちにしたものです。
図に描き加えることで、全体像に対する部分の輪郭がよりはっきりして、その部分に対するアプローチ方法もはっきりします。
つまり、適切に部分に切り分けて、その部分における原因の可能性を図示することで、原因である/原因ではないことを証明する方法の、妥当性の確認と、メンバー間の認識の共有ができます。
なんか抽象的で、難しくなってきたかもしれませんが、頑張ってついてきてください。
とにかく、こういう調査を行っているときは、各々が、どういう可能性を、どの証跡の、どの箇所を見て、原因である/原因ではないと判断したか、というのが重要になります。
つまり、あなたは、どのように証明したんですか?ってことです。
どのような原因が考えられて、それを確認する方法は、どの証跡(ログ・データベースなど)の、どの箇所を、どういう観点で確認するか、そして、その結果どうだったか。
自分の口で言えるようにする必要があります。
初心者エンジニアがやりがちなこと
ここまで、私の経験談を踏まえて、ある問題に取り組むときの、アプローチ方法について述べてきました。
初心者エンジニアの皆さんにとっては、正直かなり難しい話だったかと思います。
でも、皆さんが普段、業務中に書くソースコードにバグがあったときや、知らないテクノロジーの調査をしないといけない状況のときは、まさしく問題解決を試みているときと言えます。
技術面の勉強が苦手な人ほど、問題解決能力をつけるべきだと、私は考えます。
ソースコードのバグを取り除く
私はこれまで数人程度、初心者エンジニアの指導を行ってきましたが、バグに苦しんでいるときほど、その人がどんな能力を発揮するかが見られるチャンスだと考えていました。
残念ながら、ほとんどの初心者エンジニアは、期待した能力を見せてくれませんでした。
彼らに共通している特徴を挙げてみると、以下のようになります。
- とにかく絵を描かない
- 期待する状態とバグの状態を口頭で説明できない
- ちょうど今インターネットで検索しているトピックと、その理由と経緯が言えない
- 開発中の本物のソースコードで、バグの解消をしようとしている
ここまで読んできた人ならわかると思いますが、バグの解消だって、絵を描いて全体像を捉えるのは重要ですし、どんな状態を期待しているのに、それが実現できなくて困っているのか、口頭で説明できることは重要ですし、今どんなことを考えて調査しているのかを、口頭で説明できることも重要です。
追加で一つお話しておくと、バグの解消をするにあたり、いま自分が担当しているアプリケーションの、本物のソースコードを使って、バグの解消を試みるのは、基本的にやめたほうが良いと、私は考えます。
バグに対しては、早い段階から、再現可能性を視野に入れて調査したほうが良いです。
再現可能性とは、違う環境で同じように作っても、同じようにバグ事象が発生するかどうか、確認するというものです。
例えば、新規で新しくプロジェクトを作成し、同じようなソースコードの書き方で、開発中の機能を再現してみる。(このとき、ソースコードをコピペするんじゃないですよ)
インターネット上の質問サイトなどで不具合事象の質問がかなりの数、投稿されていますが、ほとんどが情報が不足しています。
その際、回答者からの要望で、再現可能な小さいサンプルを求められることがあります。(例えば、stack overflowでは、以下の記事が用意してある)
How to create a Minimal, Reproducible Example - Stack Overflow
初心者エンジニアは、これを作るのが、かなり苦手だという印象があります。
再現可能な小さいサンプルは、それ自体が質問サイトでの回答者への価値ある情報提供方法ではありますが、それよりももっと重要なことがあります。
それは、バグと戦っている自分が、バグを最小単位で認識できているか、ということです。
大体、開発中の本物のアプリケーションのソースコードというのは、複数のテクノロジーの集合体であり、それなりの複雑さを持っています。
その複雑さを把握できていない状況で、その中でバグの解消を試みるというのは、自分が混乱している可能性を認識しないまま、バグの解消に取り組んでいるということになります。
そのため、普段から、ある程度バグの状況が深そうだと直感でもいいので思ったら、再現可能な小さいサンプル作りに取り組んでみてください。
もしかすると、その過程でバグの原因を自分で見つけられるかもしれませんし、もし駄目でも、先輩に見てもらうときに、そのサンプルを渡すと、(たぶん)喜ばれます。
知らないテクノロジーをわかるために
自分が知らない領域の技術、例えば、新しいプログラミング言語だったり、インフラ、ネットワーク、セキュリティの知識など、勉強しないといけないことがあったとします。
これらの技術を勉強していて「あ!わかった!」と思ったときって、どういうときでしょうか?
まだ、あまり、経験がないですかね?
知らない技術の勉強をする場合にも、今回の考え方を用いてアプローチするのは、有効です。
さきほどの、事象解決へのアプローチ方法を、再掲します。
- 事象解決のゴールを決めること
- 図を描いて、何よりもまず、全体像を把握すること
- 全体から、適切に部分を切り分けていくこと
- 各部分が、原因である/原因ではないことを、証明する方法を決めること
知らない技術をわかるようになるためには、原因を究明するのが目的ではなくて、逆に、ゴールを導き出すのが目的になります。
つまり、この技術って一言で言うと何? っていう質問に答えられるようになることです。
そのためには、全体像を絵に描いて、重要な構成要素を部分として切り分けて、それら部分の理解に務め、最後に、各部分の理解した内容をまとめ上げて、ゴールにつなげるように取り組みます。
初心者エンジニアの学習の過程を観察していると、自分が学習すべき範囲・全量がまず適切に定まっていないことが多いように感じます。
関係ない部分に手を出して、本筋からズレて調査をしているようなイメージです。
なので、図を描きながら、いま理解に務めているその部分的領域が、その技術を構成する要素なのかどうかを、確認しながら進めたほうが良いです。
これを意識して学習をしていると、そのうち、いろいろな技術要素が、別の技術要素に、従属しているかどうか、という関係性が気にせずにはいられなくなります。
こうなってしまえば、技術要素同士の関係性を前提に学習するようになるので、知識の吸収力は向上していきますね。
ちなみに、ライブラリーやフレームワークのような技術は、公式サイトに目的(ゴール)がデカデカと載っています。
例えば、UIフレームワークのReact.js。
公式サイトには、以下のトピックが並んでいます。
- 宣言的なView
- コンポーネントベース
- 一度学習すれば、どこでも使える
最初にこれを見たときにはよく理解できなくても、学習の過程でこのゴールは常に頭の片隅に置いておき、自分が導き出すゴールが、最終的には一致するように取り組むと良いです。
結局、一言でこの技術を言うならば、この3点に集約されることになるので。最初から答えは、公式サイトに書かれているのです。
(だからって、理解せずにこれだけ言ってても、駄目ですよ)
おわりに
今回は、前回以上に抽象的な、概念的な話になっていて、より難しかったかと思います。
考え方の話って、本当に掴みどころがなくて、要領を得ないというか、結局どのように実践したらいいの? って話になりがちです。
ある意味、先陣が考えに考え抜いて生み出した方法論なので、結論だけ取り出そうにも、そう簡単にはいかないのです。
私のブログの記事は、全体的に長いのですが、それは、世の中に散らばる優れた知識・経験の、ちょうど中間を繋ぐ情報を提供したいからなのです。
私も、洗練された、簡潔な文章を書こうと思えば、書けるかもしれないですが、それでは、先陣たちが提供している価値には、およばないですからね。
洗練された情報は、一つ一つに大きな価値がありますが、その一つ一つをどのように組み合わせて活用するかは、個人のスキルによってしまいます。
意外と、そういう中間項の情報って、非常に重要で、状況がマッチすればかなりの利益をもたらすんですけど、それほど出回っていないんですよね。
◆コラム
IT業界全体が、ブログやQiitaにアウトプットすることが推奨されているのは、この中間項をシェアするのが最大の目的ですね。
Aという技術とBという技術の組み合わせを、Xという運用方法で試してみたら、こんなメリット・デメリットがありました〜、っていう情報が、より価値があると認識されていると、私は感じています。
なるべく概念的な話を、私の経験談と、初心者の皆さんを観察した傾向と、私の主張を織り交ぜて、いろんな方向から見て消化できるように、構成してみたつもりです。
ぜひ、この記事が、皆さんの参考になれば、嬉しいです。
それでは、今回はこの辺で。