メンテナンスできない出来ないコードのための3ステップ

またもや紹介記事ですが…
Patrick Steele’s .NET Blog より、Three Steps to Unmaintainable Codeです。
メンテナンスできないコードを生む3つの要因について、楽しく解説しています。ざっと要約しますと…
1)コメント
→コメントは多くの場合理解を助けるが、そうでないもの、コレがイケる!読む人の目をくらませ、混乱させるコメントを書けば、一発でメンテナンス不可能に。「コード見ればわかるわ!」なコメントとか、「コード直してコメント直さず」とかとか。
2)Boolean型に”flag”と名づける
→public static fieldだったりすると、もうボーナスポイント。いくつものフォームの中に “flag” の判定を撒き散らしておけば、もう完璧!
3)スタティック変数
→上の2)と、さらにインスタンス変数とスタティック変数を適度に混ぜて使えば、あっというまにコードをガラクタの山に!
#要因は他にもイロイロあるのですが、敢えて3つに絞っている所もミソですね。

眺めていても治りませんよ

切羽詰った状況下でデバックしていると、よく後ろに人だかりが出来ます。
その参加者は様々ですが、よくある顔ぶれとしてはこんな所です。
1)関係するプログラマ各位
2)このプロジェクトのマネージャー各位
3)多少なりとも利害関係のある「偉い人」たち
4)罪の無い興味本位の「野次馬」
4)はさておき、1)と2)は、当然のように参加資格を持つわけです。
自分たちの何処が問題であったのか、そしてそれがどのように解決されるのか。興味津々である気持ちはわかります。そして、デバックする側にとっても、「第三者の視点」-つまりペアプログラミングの相手-があるわけなので、まぁ悪くないわけです。そして、こういう「観客」には、たいてい「xxちょっとMSDNで調べて!」と言えば「よし来た!」とばかりにやってくれるヤツが混じっているので、そのあたりも「使える」のです。
ここで問題なのは3)です。往々にして、画面を肩越しに覗き込むわけでもなく、椅子に座って腕組みをしているだけという図です。私としては、この状況がもっともやりにくい状況です。
こういうとき、後ろで見ているときの心境は大体想像がつきます。
「ったく、下らんコンパイルエラーばっかり出しやがって…はやくしろよ…」
「これだけやってまだわからないのかよ…」
「テスト実行ばっかりで全然コード直さねぇじゃねぇかよ…(現象再現のためのテスト中)」
まぁ、大体にして、こういう状況で座っている目的は「圧力をかける」ことにあったりします。
こういう状況は非常にうっとおしいのです。
先ず第一の手段は、事細かに「今やっていること」を説明するという手です。
非常に大まかな「今xxをしてますよ」を、事細かに都度都度伝えるわけです。そうすると、見ているほうも「なにやら進展しているらしい」というのがわかって、その圧力も和らいだり、煙に巻いたりできるというモノです。
コレでもダメなら、「原因と対策、および処置にかかる所要時間の見積は、判明次第直ちにお知らせします。それまでコーヒーでも飲んでいてください。」と宣言してご退席願うことです。或いはもっと単刀直入に、「後ろで眺めていても治りませんよ。」と言ってしまうことです。
まず、デバックは-しかも偉い人が後ろで眺めるほどのデバックは-それ自体で大きな圧力になります。ですが、デバックでやらなければいけないことは、どれだけ圧力がかかっていようと同じです。
T.リスターが言うように、「圧力をかけられても思考は早くならない」のです。そして、デバックの大部分は論理的「思考」です。
そこらへんのわかった管理者は、暫時後ろに立って眺めた上で、「何かあったら呼んでくれ」と言って消えていきます。
わかっていない管理者は、延々と立ち続け、無用な圧力をかけ続けます。
その管理者がわかっているかわかっていないか、それが選べない以上、上手にあしらう術というのも、身に着けておいて損は無いと思います。

First Step Guide for Trouble Shooting

深刻な不具合ってヤツは起きるものです。
で、それを大急ぎで直さなければいけない場面というのも、これまた起きるものです。
・総合テスト用のビルドをぶっ壊したとか…
・総合テストのテストシナリオ止めたとか…
・受入テストでお客さんが激怒しちゃってとか…
・運用中に出ちゃって大騒ぎとか…
こういう事態に対処するための第一歩は、私の場合いつでもこれです
・ Don’t Panic. Relax.
深刻度が増せば増すほど、この第一歩が重要です。
問題を正確に把握して適切な解決策を見つけるために、まずは冷静になることです。
ワタワタと浮き足立ってコトに当たると、大抵はロクなコトになりません。

論理的に説明できること

トラブルシューティングに疲れてくると、ありがちな推測や、目先の結論に飛びつきたくなります。
先日も現場でトラブルシュートをしていた連中が「原因は多分コレだ!」と言ってきたのですが、それは私には全く説得的なものではありませんでした。それが本当に原因だとすると、現象が起きているいくつかの環境に対する説明がつかないからです。
(その現象、同じOSでも、発生する環境と発生しない環境がありました。)
それを指摘したものの、どうやら聞く耳を持たないようでしたので、敢えて放置してみた所、案の定不発に終わりました。
その後、別の方向からアプローチを開始。ふたつの環境のGAC(Global Assembly Cashe)から、プログラムフォルダ(一般的には C:¥Program Files )の “Common Files¥Microsoft Shared”内まで。ファイルの比較をして見ました。
(ちょい技:コマンドプロンプトからテキストファイルにリダイレクトさせて、diffの類でテキスト比較すると結構シアワセ)
今回は、そこまでしなくても、あっというまに原因がわかりましたが、問題はそこから。
「なぜ、その差が生まれたのか?」
これを説明できなくては、また同じ現象が発生してしまいます。同じ現象が発生したら、また同じトラブルシュートをやることになります。これは避けたい。
そのためにも、
・なぜこの現象が起きたのか
・どのような条件で再現するのか
・再現する条件としない条件の違いは何か
などを、キチンと論理的に説明できる必要があります。
現象が再現する条件と再現しない条件を、両方「新たに構築できる」ぐらいにできると、もはや理想です。
「多分コレ」では、同じ現象が起きて、あろうことか違う原因だった時に苦労することになります。ただでさえトラブルシュートは厄介なわけですから、もう一回同じ問題を解きたいとは思いません。
確かに、回避策が見つかって、それで十分な場合も、実務上は多くあります。しかし、そうもいかない場合には、きちんとトラブルシュートしておく必要があるということです。

Copy-Paste コードは何故良くないか

先ずはじめに、Copy-Pasteコードの全てが悪いというつもりはありません。
適切に使えば、そのお手軽さゆえに強力なツールであることは間違いありません。良く使うコードパターンなんだけどスニペットに登録するまでもない場合(例:引数の文字数チェック-Lengthを比較しておしまい)とか、そんな例ですね。
ここで言いたいのは、私的に「適切でない」場合の話です。
例えば「ボタン1」の処理と「ボタン2」の処理。
これをCopy-Pasteで済ますというのは、これは良くないと思うわけです。
この場合、全く同じであれば、関数を作って両方から呼べば済むだけの話です。確かに[Ctrl]+[C] – [Ctrl]+[V] より、関数を作る方が手数が多いですが、後々お釣りが来るぐらいのメリットがあります(これについては後述)。
じゃぁ、Copy-Pasteしてちょいと変更する場合は?
その「ちょいと」具合によりますが、多くの場合、関数にしてしまってパラメータで処理を分ける事ができるので、そうする方が多いですね。
これは処理を分けるパターンの数が多くなると破綻するので、そういう気配を感じたら、Factoryパターンから多態性(ポリモーフィズム)を利用するように展開すればよいでしょう。
で、なぜそうするのか?なぜ、この手数を補って余りあるメリットがあるのか。
これは、テスト時と保守フェーズで明らかになります。
特に、テストが修羅場を迎えている最中の修正ですね。
こういうときは少しでも早く直してしまいたいので、最初に目に付いた「患部」を直して、それで終わってしまうことが多々あります。
ところが、Copy-Pasteだと、同じようなコードがあちこちにあることになるので、それらを全部探し出して修正して…
さらに保守ともなると、「同じことをやっている」或いは「やっていそうな」場所を全部探すことになります。そのために、grepを駆けて…
そういう作業を手っ取り早く終わらせるためにも、Copy-Pasteでは無く、敢えて一手間かけた方が良いわけです。
確かに、コードブロックを切り出して関数にするのは若干面倒くさいですが、その辺りは慣れですし、或いは”Refactor!”等のコード作成支援ツールが大いに助けてくれます。

机上デバッグのススメ

YamaKenさんのblogの「雑感:机上デバッグ(VBScript)」に良いことが書いてあったので、インスパイアされてみました。
まず、印刷しての机上デバックは、全ての基本だと思います。
(画面ではなく)紙媒体という異なる環境で、画面に向かっているときとは違う状況でソースを眺めると、いろいろ見えてくるものです。
・意外と読みにくいんでやんの
・あれ?この関数何??
・なんかここおかしくねぇ??
とか、意外とイロイロ気づくものです。
こうして、「コードを客観的に眺める」習慣をつけておくのは、非常に良いことだと思います。
これに慣れてくると、同じ「思考の切り替え」が画面上でも出来るようになります。この習慣が、良いコードを生む基礎になるといっても良いでしょう。
私自身、非常に厄介なバグを退治するときには、まだ机上デバッグを多用します。確かに、今の開発環境では実行中デバッグは簡単に出来ますが、それも諸刃の剣で、あちこちにBreakPointを貼りすぎるとかえって問題が拡散して訳がわからなくなったりします。
ソース書いてナンボの商売をしている以上、自分の書いたソースを客観的に眺め直す習慣というのは身につけたいものです。
おまけ:
YamaKenさん、「SDK 見れば済む部分に余計なコメント入れてる」のは、私はアリですよ。だって私の主記憶ではSDK全記憶できないですから。

やっつけ仕事になる要因

世間では「年度末」と言われる季節です。
で、「年度末」と言うと、「納期」の季節でもあるわけです。
納期が迫ると-そしてお約束どおりリソース不足に陥るわけですが-「普通にやったらムリ」という状況になります。
で、どうするのか?まぁ普通の交渉では、初手は「納期延長」です。
しかし、よりにもよって年度末。売上げが今年度か次年度か。更に上のメンツの問題が加わると、到底勝てない勝負です。
増員も有り得ますが、ウッカリすると「ブルックスの法則」にやられますし、それ以前に納期ギリギリで増員って、普通に考えてもムリそうです。
機能を削るというのが、もっとも勝ち目のありそうな線ですが、これを納得させるのは大抵大仕事です。先方の体質や担当者のメンツ次第では、「まかりならん!」と瞬殺されることもあります。
で、ココまで手詰まりに落ちると、最後は力業です。「やっつけ仕事」に落ちて行きます。
『どうでもいいから、とりあえずカッコだけでもなんとかしろ!』という感じで、壮大なスパゲッティの山が出来上がります。
で、こうして出来上がったモノは、当然やっつけ仕事ですから、品質も保守性も何もあったものではありません。
確かにコードの品質は各作業者のスキルに追うところが大ですが、ここまでの状況を作っておいて、最後にトカゲの尻尾きり宜しく、「品質意識が…」「プロ意識が…」と文句を言うのはいかがなものかと思います。
まぁ、散々叩いておいて、不祥事を叩いた先の制作会社のせいにしている某テレビ局と同じコトですね。

コメントアウトから探るソースコード考古学

保守を行う際には、「ソースの理解」という段階が必須になります。
これを行わないと思わぬ悲劇の原因となります。
そういうわけで、最も重要な作業の一つであるわけです。
そんな作業の中で、コメントアウトされたソースの塊に出会うことがあります。
確かに、親切に『コメントアウトされた理由』が書いてあることがあります-如何に笑える理由であろうと、それは有難い事です。
そうでない場合-単にコメントアウトされている場合-には、コメントアウトされた理由は推測するしかない訳です。
その理由が明らかな場合もあります。
あからさまなデバック用コード(っていうか、#IF DEBUG つかえよ…)、あからさまな間違い、そういう場合が多いわけです。
しかしながら、そういう推測が成り立たないケースもあります。これが曲者です。
なぜコメントアウトされたのか。
仕様変更なのか?或いは、テストで悲劇が起きたためなのか。
さらに、そのコメントアウトと同様なコメントアウトが随所に見受けられるとなれば、『何かある』と感じるべきでしょう。
>新規開発な方へ
無意味なコメントアウトはおやめください。
せめて、その理由は記述してください。
或いは、ソース管理ツールに身を委ねて消してしまうのもアリです。
>保守な方へ
発掘作業が終わったら、そのコメントアウトは消してしまいましょう。
或いは、後から来る人のために、敢えて残して、その理由を記述するのも良いアイディアです。
まぁ、私に言えた立場か!というアレはありますが…

エラーを握りつぶすな!

内部でなにかエラーが発生したのなら、きちんと知らせましょう。
たとえユーザに知らせる必要が無くても、後々の為にどこかに痕跡を残しましょう。Traceでもログファイルでもイベントログでも、どこかに痕跡を残しましょう。
深刻なエラーが起きたときに、その痕跡を元に、原因を追究することになるわけですから、その手がかりは必要です。
また、あえて痕跡を残さないのなら、何故残さないのかをどこかに書いておきましょう。
こんな悲惨なコードからエラー追求すると思ってください。
手がかりが欲しくなりますよ。
[VB6]
‘—コードここから
On Error Resume Next
Dim strMessage as String
If DoSomething = False Then
 strMessage = SomeErrorMessage
End If
‘—しばらく後…
If DoAnotherThing = False Then
 strMessage = AnotherErrorMessage
EndIf
‘—コード終わり
最初の”DoSomething”で発生した「何か」は、完全に握りつぶされています。
エラーが起きたとき、”DoAnotherThing”で発生したのか、それとも他のところか、”DoSomething”なのか、さっぱり解らなくなります。

分割し、特定せよ

先のパフォーマンスネタパフォーマンスチューニング-測定に始まり、測定に終わるでは、「測定せよ」と書きました。
測定して、問題箇所がわかったらどうするか?
その問題箇所を更に細分化して、また測定するのです。
そして、「これ以上分解できない」あるいは「分解しても無意味」という段階になったとき、そこが「問題箇所」です。
そこまで、分割して、計測して…の繰り返しです。
バグ発生領域を特定するための手順と同じですね。