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

フィンローダのあっぱれご意見番 第135回「問い合わせ先」

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

私は基本的に IE ではなく Netscape をWebブラウズに使っているのだが、 もはや IE でないと見ることができないサイトも結構あったりして、 Netscape だと不便な世の中になってしまったようだ。 勘違いされては困るが、別にIEがイヤな訳ではない。 単に怖いのである。

 

※ IE の欠陥を狙った悪質なサイトやウィルスは、 Netscape には影響しないことが多い。 なお、2006年現在、Netscape は封印してしまった。 専ら使うのは Firefox である。

じゃあ Netscape は安全ですかといいますと、そこはそれ、 いろいろ何となくスリルはあるわけだが。 最近 Netscape がバージョンアップして 7.1 になった。 ジャンクメールの判別機能が追加されたりしていたが、 そういった細かい気配りはおいといて、 かなり気になったのがメニューの項目の順番である。 バージョンアップ後しばらくの間、 誤操作しまくり状態になってしまった。

  

今見ているページを保持したままでリンクを開きたいことがある。 このようなとき、私は基本的に「新しいタブを開く」という操作をする。 同じウィンドウに類似の話題のページを集めたいからだ。 もっとも、実際は、一度保留したページをもう一度見ることはあまりないのだが。

 

※ タブを使わないとすれば、 別のウィンドウで開く、という方法がある。 その場合、一連のウィンドウだけ閉じる、ということができなくなるのが不便。

例えば新しいウィンドウでリンクを開くというメニューと、 新しいタブでリンクを開くメニューが、 7.02 の時と逆になっているのだ。 その結果、新しいタブを開いたつもりなのに、 ドカドカと新しいウィンドウが開くという結果になる。 まあどうでもいいか、程度のことかもしれないが、 このような設定は ユーザーインターフェースとしては重要だと思う。 あまり気軽に変更しないで欲しいものだが。 何かの罠なのだろうか。

§

それよりも重大な問題が発生した。 バージョンアップ後、 株式取引に使っている某サイトにアクセスできなくなったのだ。 こういう時のために 4.78 という古いバージョンがインストールしてあるのだが、 試しにそれでアクセスしてみると、アクセスできる。 7.02 にバージョンダウンするのは面倒だし、どうしようか。

ありふれたトレーディングサイトにアクセスできなくなるなんて障害があったら、 Netscape ユーザーが大騒ぎしそうなものだが、 何の騒ぎにもなっていないようだ。 実はこのトラブルは、発生条件がかなり厳しいのである。 症状は、IDとパスワードを指定して「ログイン」ボタンを押すと、 また同じページに戻ってしまうというものだ。 つまり、ひたすらログインページの表示を繰り返すのである。 ちなみに発生条件だが。

(1) Air H" で接続した時に発生する。 自宅から Bフレッツで接続すれば、 他は全て同じ環境でも、 問題なく接続できる。 Air H" の問題なのか、 特定のネットワーク接続の設定に依存するのか、定かではない。

(2) 別のプロフィールからだと接続できる。 Netscape には、複数ユーザーが使うことを想定して、 ユーザーを切り替える機能がついている。 試しに、他のユーザーのプロフィールでログインしてみると、 何事もないように普通に使うことができた。

他に条件になっていそうなことは、 7.02 から上書きインストールしたとか。 インストール時の指定したのは殆どデフォルトである。 もちろん、キャッシュのクリア、パスワード記憶サイトの設定など、 古い情報が残っていて悪さをしそうな所はチェックしたが、分からない。

こりゃ困ったなあ、と思ったが、 異常終了するわけじゃないから、 自動的にエラー送信もできない。 問い合わせ先もよく分からなかいし、 とりあえず認証が必要な他のサイトは全て問題なくアクセスできるので、 どうしたものかと、しばらく考えていた。

  

さて、偶然なのだが、 その後このトレーディングのサイトが全面リニューアルしたのである。 これは Netscape とは全然関係ない話で、 以前から、サイトをリニューアルすると宣言されていたのである。 その結果、ラッキーなことに、 Air H" からも、何の問題もなく接続できるようになった。 これにて一件落着ですか。 気分的には一見落着って感じだが、もはやどうでもいい気になっていたりする。

 

※ 結局原因は迷宮入りした。 なお、この種のトラブルで多いのは、 ポップアップウィンドウがブロックされて処理が続行できないとか…。

§

ある処理から別の処理に情報を渡したい場合。 やり方はいくつかあるが、 例えば引数や、パラメータを使ったりする。 List 1 のような感じで、呼ばれた側が値を受け取ればいい。

---- List 1 (引数を使った値の受け渡し) ----

    doSomething(int value) {

        // value を使った処理
    }

---- List 1 end ----

複数の値を渡したい場合はどうするか。 単純な発想としては、 必要なものを全部渡せばいい。 List 2 のような感じになる。

---- List 2 (引数が多い場合) ----

    doSomething(int value1, int value2, int value3, …) {

        // value1, value2, value3, … を使った処理
    }

---- List 2 end ----
  

「…」と書いてしまったが、 実際のプログラムでは全部書かなければならない。 このような書き方のメリットは、 どんな値を受け取るのか、ある意味明快であるということだ。 ネーミングとコメントさえ間違わなければ、 どの値を渡せばどういうふるまいをするのか想像しやすくなる。 逆からみれば、 渡されなかった情報には動作が左右されないように作られていたら、 なおよい。 また、できればそのように作るべきである。

 

※ 配列とか、ポインタ渡せば…ということには気付かなかったことにする。

ところが欠点もある。 まず、渡す値が多くなれば書くのが面倒になる。 読むのも大変だ。 これは可読性の問題である。

もう一つの問題は、保守性である。 渡す値を一つ増やしたい、というように仕様を変更したいことはよくある。 この場合、最後に引数を追加するのが一番簡単だが、 増やす値の意味として、最後ではなくて最初に入れたい、 といったことも結構ある。 処理を宣言、定義している所の修正はそんなに大した作業ではない。 問題は、この処理を呼び出している所をもれなく探し出して、 適切に変更する、という作業で、 呼び出し箇所が多いと、これは大変なことになる。 もっとも、 これは機械的な作業だから、 この種のリファクタリングは開発ツール側でサポートしてもいいと思うのだが。

トラブルの原因の一つは、 引数の名前ではなく順序に意味があるという所にある。 List 3 は2つの引数を与えて点を描画する処理のつもり。

---- List 3 (引数の順序) ----

    drawPixel(int h, int v) {
        // (h, v) に点を描画する
    }

---- List 3 end ----

こういう処理は非常に単純なのだが、 うっかり List 4 のような呼び出しをしてしまうと、どうだろう。

---- List 4 (呼び出す側の順序) ----

    valueX = 100;
    valueY = 50;
    drawPixel(valueY, valueX);

---- List 4 end ----

drawPixel の処理が引数を引き取る時には、 それが呼び出す側で何と呼ばれていたかなんてことは知ったことではない。 まして、何と呼ぶかなんてことは人間様が勝手にやっていることで、 プログラムの立場からみれば、 型さえ一致していれば、文法上は全然問題ないろのである。 もし List 4 に書いた処理がおかしいと思うとしたら、 それは読む人に「Xやhは水平、Yやvは垂直だよな?」という暗黙の了解があるからだ。 しかし、 もしかすると、このコードを書いた人は、 あえて Y の値を h 側に引渡したいのかもしれない。 そんなことはコンピュータには分からないのである。

このような問題を避ける手として、 例えばグローバル変数を使う方法があるが、 その話は以前書いたような気がするので今回は省略する。 とにかく、この種の問題は、引数を増減させたときに、 しばしば発生しがちなのだ。

根本的にこの問題を避けるにはどうすればいいか。 オブジェクト指向系で見かける書き方だが、 呼び出す時に、問合せ先を指定するという方法がある。 List 5 は、呼ばれる側の処理である。 一応Java。

---- List 5 (尋ね先だけを教える) ----

public class WorkerClass {
    public void doSomething(ClientClass callMe) {
        int value1 = callMe.getValue1();
        int value2 = callMe.getValue2();

        // value1, value2, … を使った処理
    }
}

---- List 5 end ----

もちろん、ClientClass はこんな感じで、 getter となるメソッドを用意しておく。

---- List 6 (質問される側の構造) ----

public class ClientClass {
    private int value1;
    private int value2;
    public int getValue1() { return value1; }
    public int getValue2() { return value2; }
    // setter は省略
}

---- List 6 end ----

callMe よりも askMe の方がよかったか? 要するに、 詳しい人を紹介するから、 分からないことがあったら聞いてくれ、というやり方である。 実生活でもよくある方法だ。 この方法だと、 呼び出す時には問い合わせ先だけを指定するため、 見た感じは簡潔になる。 getter のネーミングをきっちり考えておけば、 可読性も問題ない。 値を引数で呼ぶのではなく、関数を呼び出すという構造になるので、 呼び出されてから値を計算するといった、遅延処理が可能になる。 複数の値を呼び出し側に戻すのが簡単になる。 などなど、特徴は多々あるのだが、 一番助かるのは、 受け取る値が getter の名前で決まるということである。 引数のように、順序に意味を持たせるのではないから、 呼び出し時に順序を間違って、予期していない値を与えてしまった、 というようなバグから開放されるのだ。

  

デメリットは何かというと、 たかが引数を渡すのにクラスを使うというのが面倒だとか? 多分、一番気になると思うのは、 極めて頻繁に値をやりとりしたい場合のオーバーヘッドだろう。 もっとも、そういうのは仕上げの最適化の時に考えればいい、 というのが最近の流行かもしれない。

 

※ もっと大きな問題は、 仕様変更があったときに、 1つのクラス変更だけで済まないということだが、 それは多かれ少なかれ、他の手法でも同じことだと思われる。

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

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

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