2013年02月11日

TB: check_xxx がなんでダメなのか

check_xxx がなんでダメなのか - Yamashiro0217の日記

"check_xxx"みたいなメソッド名は避けようという意見には賛成。

だけど、流石にそれは例が悪い。

はてブのコメントでid:r-westが指摘しているように、いろいろな問題を詰め込んでしまってるから、「なぜその命名が拙いのか」という本題がかすんでしまっている印象。
"check_xxx の理由最初のだけ"ならば、それに絞って書くべき。例え、"check_xxx 書くやつ、絶対他のこともそのメソッドでやるんだ"としても。

以下、"check_xxx がなんでダメなのか"を自分流に解説し直してみる。
元記事に則って、"check_user"というメソッド名を例に説明する。
元記事のコードは……Perl? PHP? どっちにしろ忘却の彼方なので、以下Cのコードという事で。

例えば、以下のコード片、一体何をやっているのだろうか?

enum User_Kind {
	USER_KIND_UNKNOWN,
	USER_KIND_NORMAL,
	USER_KIND_SUPER,
	USER_KIND_ADMINISTRATOR
};

struct User {
	char *name;
	unsigned int age;
	enum User_Kind kind;
} user;

/*
 * なんかいろいろ
 * ながったるい処理が
 * 在ったり無かったり
 */

if(check_user(&user)) {
	/*
	 * なんかいろいろ
	 * ながったるい処理が
	 * 在ったり無かったり
	 */

	 // (1)
} else {
	/*
	 * なんかいろいろ
	 * ながったるい処理が
	 * 在ったり無かったり
	 */
}

うん、User型オブジェクトの「何か」をチェックして、それで処理を切り分けている……でも、何をチェックしてるの?

パッと思いつくのは次の2つか。

  • userの各メンバが「正しい形式に基づいているか」をチェックする。
    (nameに使われている文字種や最大長、ageの値が想定内の範囲か、kindの値が不正ではないか、等)
  • userの各メンバに設定した値に合致するユーザーが居るかどうかを(DB等から)チェックする。

他にも考えられる処理があるかも知れない。

仮に(1)の位置に"removeUser(&user)"とでも書かれていれば、後者の意味だったのだろうと予想(あくまで予想)出来るけれど、そこまで読み進めないと意味が読み取れないというのは、どうよ。可読性高いだろうか?
更に、1つだけならばまだしも二重三重と"check_xxx"な条件分岐がネストされていたらと考えたら……

え? 定義元を読めばいいじゃんって?

確かに定義元を読めばその関数が何やってるのかは分かる。理屈の上では。

でもさ、その定義元(この例の場合では"check_user")内に、更に"check_xxx"が在ったら? その定義も読むの? 更に更に"check_xxx"が在ったら? そうすると、どんどん読む必要が有る場所が増えていくよ?

で、読み終わって何やるメソッドか把握出来たら元の場所に戻って続きを……あれ?元の場所って何処だっけ?


// (各関数プロトタイプは省略)

// 略
	if(check_user(&user)) {	// 今読んでいる場所
		// 略
	}
// 略

_Bool check_user(const User *user) {
	// 略
	check_puyo(user);
	// 略
}

Something check_puyo(const User *user) {
	// 略
	check_piyo(something);
	// 略
}

Something check_piyo(const Something something) {
	// 略
	check_huga(something);
	// 略
}

Something check_huga(const Something something) {
	// 略
	check_hoge(something);
	// 略
}

Something check_hoge(const Something something) {
	// 略
	// ここまで読んで、やっとcheck_userが何やってたか分かる
}

え? コメント書けばいいじゃんって?

// 各メンバと同じ値を持つユーザーデータが有るか調べる
if(check_user(&user)) {
	// 以下略

それってつまりは、以下の「明らかな事をわざわざコメントに書く」のと一緒だよね。

// fooが0未満の時
if(foo < 0) {
	// 以下略

明らかに無駄。
そんな無駄なコメント書くぐらいならば、分かり易い名前付けようよ、と。

if(exists_user(&user)) {
	// 以下略

これならば、「ユーザーの何について調べたいのか」は自明だよね(もっと良い名前はあるかも知れないけれど)。

posted by 天井冴太 at 02:19 | Comment(0) | TrackBack(0) | Other | このブログの読者になる | 更新情報をチェックする
投票お願いします 人気blogランキング - 投票する
2013年02月06日

GVimの起動時には幾つかの関数が使用出来ない

ここで言う"起動時"というのは、GVim起動直後の.vimrc処理時で、多分、"has('vim_starting')==1"な時の事。

なお、GVim――つまりGUI用のVimでの話であって、コンソールで使う普通の(?)Vimでは問題ない。

:help input()曰く。

NOTE: This function must not be used in a startup file, for
the versions that only run in GUI mode (e.g., the Win32 GUI).

しかしどうもinput()だけの話じゃ無いようで、以下の関数が使えなかった。

  • input()
  • inputdialog()
  • inputlist()
  • confirm()

ユーザーに何か問い合わせる系統かな……そういう関数って他にも在る?

inputで始まる関数群はまともに動かない(空文字列とか0が帰ってきている模様)だけだけど、confirm()が曲者で、Linux(Crunchbang)だとGVimの起動さえしない。

因みにWindows XPだと、第1引数と第2引数を改行で連結した内容がダイアログボックスで表示された。例えば、

call confirm('prompt', "Yes\nNo")

とだけ書いたファイル(%HOMEDRIVE%%HOMEPATH%\test.vim)を用意して、以下のように実行すると、

Windows XPの

gvim -u "%HOMEDRIVE%%HOMEPATH%\test.vim" -U NONE

以下のダイアログボックスが表示される。

1行目に

:autocmdにするとよさげ。やや意味合いが変わってくるけれど、影響は無いんじゃないかなぁ?

autocmd VimEnter * call confirm('prompt', "Yes\nNo")

どうも、--cmdオプションで使った時も同様の問題が発生する模様(あまりきちんと調べていない)。

バージョン7.3で確認。

タグ:Vim_script Gvim vim
posted by 天井冴太 at 00:35 | Comment(0) | TrackBack(0) | Tool | このブログの読者になる | 更新情報をチェックする
投票お願いします 人気blogランキング - 投票する

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。