障害の発生原因の切り分けのポイント

テストや本番運用で障害が発生した場合、既知の障害等で原因が明らかな場合を除き、対応のために原因を調査する必要があります。
原因を調査する上ではどこに原因があるのかの切り分けが必要になります。
以下では、切り分け作業を行う上でのポイントを順を追って説明します。

1.障害が発生した状況を保全する

障害が発生したデータやその状況を記録したログは後の調査で使いますので、誤って更新したり削除したりしないように保全する必要があります。
テスト中であればそのデータを用いたテストは中断する必要がありますし、場合によってはコピーして別の場所に補完する必要があります。

2.期待される値との比較を行う

データやログを見て、設計上期待される値と異なる点を探していきます。
コーディングの単純な誤りであれば、大抵の場合は、データが期待値と異なるようになった箇所やログの出力内容から原因を特定できます。
場合によっては、その期待値自体が合っているのかどうか、設計や要件の確認・再検討が必要になる場合もあります。

3.障害発生手順を確立させる

ログの出力内容が不足している場合や原因が込み入っている場合は、データやログを見ただけでは原因がわからない場合があります。
その場合は、障害が発生した時と同じ手順で障害の再現を確認します。
障害が再現すれば、障害を発生させる手順が確立されたということになります。
厄介なのは障害が再現しなかった場合で、一意キー(顧客番号や受付番号の類)が障害発生時と異なることに注目して一意キーと結びつくデータを洗い出す、ランダムに処理が変わる箇所がないか(乱数を使っている箇所や振り分け先がランダムなロードバランサー等に注目する)、という観点で再現しなかった理由を調査し、障害発生手順を確立させます。
どうしても確立できない場合は、ハード障害である可能性を視野に、障害発生時の状況をまとめてハードウェアを提供するベンダーに確認する、というアクションを起こす必要がある場合もあります。
(私の経験上、「太陽フレアでビットが入れ替わってしまった」という冗談のような原因を告げられたこともあります)

4.再現手順を元に開発環境で原因調査を行う

再現手順が確立したら、開発環境で再現手順を試し、徐々に原因を絞り込んでいきます。
もし環境を変えたことで障害が再現しなくなった場合、環境問題である可能性が出てきます。
(例えば、マスタデータの不備、機器の構成の違いに起因する問題、等)
障害が再現する場合、開発環境ではデバッグを入れて変数の内容を表示することができますので、それをログの代わりにして原因調査を進めることができます。
また、開発環境ではデータも自由に書き変えられますので、データを少しずつ書き変えて挙動を確かめることでも、原因調査を進められます。


いかがでしたでしょうか。

障害調査は経験則で語られることが多いので、私自身の経験を基に文章にしてみました。
もし参考になれば幸いです。

カプセル化によるルールの強制

オブジェクト指向を適用すると、ソースコードの重複した記述を排除でき、生産性や品質を向上することができます。
それとは別に、他の開発者にルールを強制できるメリットもあります。
カプセル化を例にして説明するのがわかりやすいので、今回はカプセル化を例に挙げてルールを強制するメリットを書いていきます。


例えば、自分は商品の金額を計算するPriceCalcクラスを作成していて、他の開発者はPriceCalcクラスを利用するUserクラスを作成しているとします。
自分としては「このロジックで金額計算して欲しい」というのがあるのですが、他の開発者にそのロジックの実装をさせるようにしてしまうと、意図が上手く伝わらなかった時に誤ったロジックで計算されてしまいます。
この状況をソースコードで表すと下記のような形になり、PriceCalcクラスは計算に必要な変数をまとめるだけ、PriceCalc側でその変数を参照して独自に業務ロジックを実装するような形となります。


それでは困るので、クラス変数に付随する業務ロジックもPriceCalcクラス側に実装することにします。
変数とメソッドをひとまとまりにして一つのクラスとして提供することで、Userクラス側ではメソッドを呼び出すだけであるべき業務ロジックに基づいた計算を行うことができ、Userクラス側で業務ロジックを意識する必要が無くなります。

しかし、メンバ変数がpublicだと、Userクラス側でその変数を参照して独自に業務ロジックを実装することもできてしまいます。
自分としてはそれでは困るので、「変数を参照して独自に業務ロジックを実装しないでください」と伝えるのですが、それが上手く伝わらないと独自に業務ロジックを実装されてしまう可能性があります。
自分一人でプログラムを作っている場合は全ての変数をpublicにした方が便利だったりもしますが、複数人で開発している場合は意思疎通がうまく行かなかった場合に意図通りではないコーディングをされてしまうリスクがあります。


それを防ぐためには、変数のアクセスレベルをprivate等にして、変数に自由にアクセスできないようにするのが有効です。
こうすることで、変数を参照して独自に業務ロジックを実装しようとされた場合に、コンパイルエラーとして機械的に失敗させることができます。
これが、カプセル化によるルールの強制であり、意思疎通がうまく行かなかった場合に意図通りではないコーディングをされるリスクを減らすことができます。


いかがでしたでしょうか。

一人で開発する時と複数人で開発する時では、気を付けるべきポイントが変わることがあります。
オブジェクト指向の考え方の一つである「カプセル化」も、単なる慣習として捉えるのではなく、複数人で開発する場合にルールを規定するものとして捉えることで、実務で有効に使えるのではないかと思います。

プログラム上の変数やロジックの意味を現実のビジネスルールと合わせることの重要性

通常、初回リリースの時点では、ソースコードは現実のビジネスルールを反映したものになっています。
(なっているべきです)

そして、障害対応や保守開発でソースコードを修正する際は、将来の保守性を犠牲にしないために、ビジネスルールに沿った修正を行うべきです。
ビジネスルールに沿わない修正を行ってしまうと、ソースコードの解読が困難になったり、後々新たなバグが生まれやすくなったりします。


例えば、麺・スープが入った器に具材を入れて料理を完成させるシステムを開発しているとします。
取り扱う料理は以下の通りとします。

また、

という処理が存在するとします。

ある日、「みそラーメンにはこしょうではなく七味を入れたい」という要望が入り、システムを改修するとします。

ここで、「みそラーメンの分類をうどんにする」という修正を行うべきではありません。
この修正でも要望に応えることはできますが、ビジネスルール上はみそラーメンはうどんに分類するべきではないので、このような修正を行うと保守性が低下します。
システムの実装を良く知らない人がソースコードを読んだ場合、「みそラーメンはラーメンである」という予想を立ててソースコードを読むことになるので、「実装上はみそラーメンはうどんである」となっていると、ソースコードの読解を誤るリスクが高まります。
また、将来、「うどんには揚げ玉を入れたい(ラーメンには入れたくない)」という要望が入り、「分類がうどんの場合は揚げ玉を入れる」という処理を追加してしまうと、みそラーメンにも揚げ玉が入るというバグを埋め込んでしまいます。

ここは、処理を以下のように修正し、ビジネスルールを崩さないようにすることが望ましいです。


いかがでしたでしょうか。

プログラムの改修は直せば良いというものではなく、その後の保守のしやすさも考えて直す必要があります。
今回は、実務で目にしたケースを元に、記事を書いてみました。

ソースコード中に顧客情報を記述してはいけない

特定の顧客用に特別なビジネスロジックを用意している場合、以下のようにソースコード中に顧客情報を記述することで実装することはできます。
(顧客番号が’1111111’である場合に特別なビジネスロジックを実行するとします)


しかし、この実装方法には以下の問題があり、望ましくありません。
特別なビジネスロジックを適用する対象の顧客の情報は、(データの管理にDBを使用しているシステムであれば)DBに持たせるべきです。

・頻繁なソースコード修正が必要になる

対象となる顧客が追加されたり削除されたりする度にソースコード修正が必要になる。
コンパイルやデプロイも必要となり、対応工数や対応のリスクが増加する。
→DBで管理すればDB内の情報の補正だけで済む。

・データを一元管理できなくなる

対象となる顧客を調べるためにはソースコードを見なくてはならなくなる。
→DBで一元管理すれば情報の検索が容易になる。

・セキュリティを確保するのが難しくなる

ソースコードが流出した場合に顧客情報も同時に流出してしまう。
→DBで一元管理すれば、顧客情報の流出のリスクを減らすことができる。


対象となる顧客の情報をDBに持たせる場合、以下のような実装になります。

1.特定処理対象顧客テーブルを別途作る場合

※特定処理対象顧客テーブルには、特定処理の対象となる顧客番号を格納する。

2.既存のテーブルにフラグを持たせる場合

※「特定処理対象フラグ」のカラムを追加し、処理対象なら’1’、処理対象外なら’0’をセットする。

いかがでしたでしょうか。

ソースコード中に顧客情報を記述してしまい保守性が低下するという話は良く聞きますし、私自身もそのようなソースを保守開発して苦労したことがあります。
また、最近ではソースコードと共に顧客情報が流出したという事故もニュースになっています。
そのような背景があり、今回の記事を書いてみました。

顧客情報が記述されたソースコードを目にする機会は珍しくないと思いますが、それはアンチパターンであるというのは認識しておくべきでしょう。