Home日記コラム書評HintsLinks自己紹介
 

フィンローダのあっぱれご意見番 第126回「リネーミング」

← 前のをみる | 「フィンローダのあっぱれご意見番」一覧 | 次のをみる →

コンピュータウィルスの感染報告が増えているという。 IPAの発表で1000件超えたとか。 なぜこういう冗談みたいに少ない数字が出てくるか、よく分からない。 多分、実態としては、 その何万倍もの被害が出ているのだろう。 私の所にも毎日のようにウィルス添付メールが来ていたが、 最近は何となく、 ウィルスよりもアダルト系のDMが多くなってきたような気がする。 慣れればどちらの場合もタイトルを見た瞬間に判断できるというのがありがたい。

 

※ IPA: http://www.ipa.go.jp/

何台か知人のマシンのインストールを手伝ったのだが、 素人だけに、ウィルス対策をしておかないと怖いので、 いずれも Norton AntiVirus を入れてある。 このソフト、1年間だけパターンが有効ということで、 有効期限切れが近付いてくると、 「もうすぐ切れます」というメッセージが出るようになる。 親切だという考え方もあるが、 これがどうも素人にはどうしていいのか分からないらしい。 という訳で「どうすればいいのか」という相談の電話がかかってくるのだ。 メールでなくて電話で連絡してくるのは、 パソコンが普段と違う動きをしているために、怖くて触れないのである。 ウィルス避けのために入れたソフトが原因でpcが使えないというのは興味ある現象だ。

 

※ 最近は更新の先延ばしが簡単になったが、 昔はややこしかったのだ。

たかが更新の確認作業、 そんなに難しい操作ではないと思うのだが、 つい最近も、 どう操作していいか分からないという相談があった。 そんなに難しかっただろうかと思ったが、 試しにやってみたら、これが見事にハマった。 自分では普通に操作したつもりなのだが、 なぜか最新版のパターンデータのダウンロードがキャンセルされてしまう。 数回繰り返して、やっと理解できたのは、 期間延長を今すぐ申し込みますか、というような質問にNoと答えたつもりなのに、 なぜかパターンデータのダウンロードをキャンセルしたことになる、 ということだった。

昔はこんな設計ではなかったような気もする。 この事例におけるポイントは、 途中で2つのダイアログが表示された状態になる所にある。 普段の処理とは違うメッセージなので別のダイアログを使う、 という気持ちは分かる。 しかし、エンドユーザーに提供する処理は一本道でないと、 しばしば混乱してしまうものである。 最初に「期限が切れますが、どうしますか」という選択をさせておいて、 その後に、通常時と同じようにパターンデータを更新させる画面になればいいだけの話で、 それを同時にやってしまうからトラブルの原因になったのだ。

§

  

プログラミングの作業の中に、 リファクタリングというものがある。 大雑把にいえば、 既に書かれているコードに対して、構造改革することを意味する。 俗には「動いているコードを触るな」とも言われているが、 リファクタリングの場合、動いているコードを積極的に触ることを推奨する。 慣れないとちょっと怖い。

 

※ 構造改革というのは政治的流行語。

リファクタリングには、 内部処理を変えても、 外からみた振る舞いは変えてはいけない、 という大原則がある。 つまり、リファクタリングの前と後で、 プログラム全体は同じように動作していなければならない。 機能改善ではなく、 構造を最適化して、readablityを向上させるとか、 再利用しやすくするとか、 効率を上げるとか、そのような目的で行う作業なのだ。

  

リファクタリングのテクニックはいろいろあるが、 実は一番重要なのは改名ではないかと思う。 大抵のプログラミング言語においては、 ラベルや変数の名前を変えただけでは、動作はもちろん、 構造すら何も変化しない。 もちろん、名前で型が決まるような言語もある訳だが、それはそうとして、 実際なぜだか、変わらないはずの動作が変わったりすることもある。 もちろん、論理的にはおかしな話だが、 要するに、これは何か間違ったことが起きているのだ。 一部分だけ名前を変え忘れたりした場合は、 大抵コンパイルエラーが発生したりするから、 あまり心配する必要はないのだが。

 

※ うっかり既にある名前に変更してしまったら戻すのが大変だ。

JavaBeansとかのコーディングに慣れている人なら、 is何々というような名前はおなじみだと思う。 このような安易なネーミングにも、実は技が光っている。 checkNewPage とか testNewPage という名前を付けてしまうと、 true を返したらどうだとか、false だと何だ、という話になってしまうのだ。 checkというのは行為であって、状態ではない、というのがポイントである。 経験的にも、NewPage の時に true になるだろうという予想もあれば、 C的な発想かもしれないが、 エラーが発生しないと0を戻すのが暗黙の了解なのでは、 のような先入観もあるからややこしい。 暗黙というのはどこまで行っても暗黙なのだ。 それに比べると、is何々とかhas何々という名前は、 true の時にどのような状態なのかという自己主張が明快であるから分かりやすい。

 

※ boolean の getter が is… という名前であることを言ってるのである。

ここでありがちな話を紹介したい。 プログラム全体の処理として、 ページの内容が NewPage でない場合に何かしたい、 というような状況が重なることがある。 否定的な場合に処理したい、ということだ。

この場合、 コーディング上は、 次のような書き方が増えてくる。

    if (! isNewPage()) ...

ここで少し欲が出るというか、 毎度「!」を付けて否定するのが気になり始めたりすると、 isNewPage() ではなくて、 isNotNewPage() のような名前のメソッドを作りたくなる。 実は、これが余計なお世話というか、 頭痛の種になってくることが多いような気がするのだ。

私の経験では、 is は is、全部肯定的な判定にすると割り切って書いた方がいい。 例えば、「メールが来ていないと中断する」のような処理がたくさんあるとする。 もしかしたら、 hasNoNewMail() のような処理を作って if (hasNoNeMail()) … と書きたくなるかもしれない。 しかし、それよりも if (! hasNewMail()) … とコーディングした方がいい。 意味は同じなんだけど、 結局、肝心のその hasNoNewMail のロジックを書く時に思わずバグってしまうのである。 常に判定は肯定的に書くという習慣を身につけておくと、 ボディブローのようにじわじわと効いてくるのだ。 多少の効率よりは決まりきったパターンにハメる方が得なのである。

§

それぞれの処理の内部も型にハメるのがよい。 例えば、判定処理を別関数にくくりだす、 という作業も、 リファクタリングでよく行われる。 どうまとめるかというと、 具体的には、 不成立になるような条件を一つずつ当てはめて、 一つずつふるい落して、 最後まで残れば true、というようなやり方が分かりやすい。 これは List 1 のような感じになる。

---- List 1 (ふるい落し系の判定) ----

bool isSomeCase()
{
    if (却下条件1)
        return false;

    if (却下条件2)
        return false;

    ...

    return true;
}

---- List 1 end ----

却下条件という言い方があるかどうかは知らないが、 このコードのコツは、 中断する条件が true、false 混ざらないようにすることだ。 少しでも混じると、分かりにくさが倍増します。 true / false を混ぜないというだけなら、 List 1 とは逆に、成立条件で少しずつ true を返して、 全部当てはまらない場合は false、という勝ち抜き系のコーディングもアリだ。 List 2 のようになる。

---- List 2 (勝ち抜き系の判定) ----

bool isSomeCase()
{
    if (成立条件1)
        return true;

    if (成立条件2)
        return true;

    ...

    return false;
}

---- List 2 end ----

経験的には、 何となく、ふるい落とすようなコーディングの方が多いような気がする。

効率を優先させるのであれば、 成立する確率が高い条件からテストするというのが基本である。 すると、true を返したり false を返したり、 という判断処理が混ざりやすくなる。 それが本当に効率的なのかという問題もあるし、 コーディング上の分かりやすさというのは、 結局のところ他にも影響して、 全体の品質向上に繋がったりするわけだから、 少なくとも最初のうちは、効率をあまり気にしないで明快にコーディングするのがよい。 という方針は一般にも支持されているはずだ。 ヘンな順序でテストして、予想外のバグを作ってしまったら、元も子もない。 最後に最適化する所で、最も重要な1割とか2割のコードを見直せば、 必要な性能は出るものである。

§

  

余談だが、名前に意味をもたせようとすると、 どんどん長くなるという傾向があったりして、 それを手で打っていると間違えたりするから、 copy&paste で変数名を指定したりする癖が付く。 そうなると、 最初に綴りを間違ったら永遠にそれが残ってしまって、直すに直せないというような奇妙な状態になったりする。 実は私のサイトも開設当時から calender.htm というページがあるのだが、 calendar じゃないのかという話があって、それはそうなのだが、 このページは perl で動的に生成して他から自動的にリンクさせたりしているので、 まあいいか、ということで。

 

※ Eclipse のりファクタリング機能を使って一度に名称変更するのは、 かなり気分がいいものだ。 関連ある名称なども全部一気に変更してくれる。 ただし、調子に乗ってこれをすると、 HQL の中の文字列が変更前のクラス名だった、 みたいな罠にハマることもあるので注意。

copy&pasteで思い出したが、 ある日、といってもつい最近の話だ。 ちょっとしたコードを書く必要があったので、 MSDNのリファレンスに出ていたサンプルをコピーしてコンパイルしてみたら、 そんな変数は定義されていない、というようなエラーが出た。 サンプルなのに妙だなと思った。 よく見ると、 どう見ても、 整数の0(ゼロ)を指定するべき所にアルファベットのO(オー)が入っている。 大文字のOという変数が定義されていないというエラーなのだ。

こういうサンプルを平気で配付するメーカーも凄いが、 そのサンプルが未だに直っていないというのが不思議である。 確かに、このサンプルを目で見ながら手で打ち込んだら、 こんな所に大文字のOが出てくるとは思わないからエラーは発生しない。 昔のタイプライターは数字の0を大文字アルファベットのOで代用したことがあったが、 まさか今頃そういう代役が出てくるとは思わなかった。

見た目も侮ってはいけないというのが教訓のようだ。

  

(C MAGAZINE 2002年12月号掲載)
内容は雑誌に掲載されたものと異なることがあります。

修正情報:
2006-03-02 裏ページに転載。

(C) Phinloda 2002-2006, All rights reserved.