Morichan
@Morichan

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

変数名(特に真偽値変数の変数名)は「事象」を書くか「目的」を書くか

Discussion

変数名を指定する際、「事象」に倣って定めますか?それとも「目的」に倣って定めますか?
理由も合わせて教えてください。

「事象」および「目的」という単語の意味は、下記例を参考にしてください。
わからなければ随時聞いていただけると幸いです。

/**
 * 事象に倣って変数名を定める例
 */

// textがnullであることを表す
hasNullText = text === null

// 例えばoperatingEnvironmentが `:{uuid}-production` という文字列の場合
// ({uuid}にはUUID文字列が入るものとする)は本番環境であることを表す
isProduction = /:.{36}-production/.test(operatingEnvironment)



/**
 * 目的に倣って変数名を定める例
 */

// テキストがnullの場合はエラーデータとする判定時に使う変数
isErrorData = text === null

// 本番環境ではキャッシュを利用する判定時に使う変数
enabledCache = /:.{36}-production/.test(operatingEnvironment)

背景

「ちゃんと意味のある変数名を付けなさい!」
このように言われて育ってきたプログラマーの皆様におかれましては、常日頃から「意味のある変数名」を探して東奔西走しているかと存じ上げます。

しかし、「意味のある変数名」というのは、抽象的ではないでしょうか?
誰に何を伝えれば「意味のある変数名」と言えるのでしょうか?


その一例として、変数名は何を表しているべきか?という問題があります。
具体的には、誰に対して変数名が理解しやすい物であるべきか?と言い換えてもいいかもしれません。

例として挙げました、「事象」に倣って変数名を定める場合、および、「目的」に倣って変数名を定める場合とは、すなわち以下の通りです。

  • 「事象」に倣って変数名を定める
    • 変数の値を決定づける事象から変数名を定める
    • 変数の値を決定づける事象自体が複雑な場合に、何を
    • (どちらかといえば)変数定義者に優しい
  • 「目的」に倣って変数名を定める
    • 変数利用時の目的から変数名を定める
    • 変数定義箇所だけを参照して定義している理由を把握しやすい
    • (どちらかといえば)変数利用者に優しい

それぞれメリット/デメリットがあると考えています。
個人的に思いついた例としては、以下の通りですが、他にも様々な理由が挙げられるはずです。

事象に倣って変数名を定めた変数の活用例
// ✅ どのような事象が重要であるかわかりやすい
hasNullText = text === null
isProduction = /:.{36}-production/.test(operatingEnvironment)
isStaging = /:.{36}-staging/.test(operatingEnvironment)

// ❌ textがnullであることとTypeErrorの関係がわかりづらい
if (hasNullText) {
    throw new TypeError()
}

// ✅ 本番環境でのみキャッシュすることがわかりやすい
setCache(isProduction)

// ✅ 複数の目的で同じ変数を利用しやすい
addProbe(isProduction)

// ❌ 本番環境かつステージング環境といった、判定値が複数の場合にはデータ初期化することがわかりづらい
resetData(isProduction && isStaging)
目的に倣って変数名を定めた変数の活用例
// ✅ どのような目的で定義しているかわかりやすい == 変数が不要になった際に削除しやすい
isErrorData = text === null
enabledCache = /:.{36}-production/.test(operatingEnvironment)
// ❌ 同じ事象であったとしても、目的ごとに定義し直す必要がある
shouldAddProbe = /:.{36}-production/.test(operatingEnvironment)
shouldReset = /:.{36}-(production|staging)/.test(operatingEnvironment)

// ✅ 変数定義の時点に戻っても判定値の設定方法がわかりやすい場合には、目的とTypeErrorの関係がわかりやすい
if (isErrorData) {
    throw new TypeError()
}

// ❌ 変数だけ見ても「そりゃそうじゃ」としか言えない場合がある
setCache(enableCache)

addProbe(shouldAddProbe)

// ✅ 判定値が複数の場合でもデータ初期化することがわかりやすい
resetData(shouldReset)

皆様は、どのようにして以上を区別していますか?
それとも区別していないのであれば、どのように変数名を考えていますか?
また、混ざってもいいと考えられている場合は、どちらがどちらと意識していますか?

ご指導、ご鞭撻のほど、よろしくお願いいたします。

4

目的と手段の関係で整理できそうな気がします。

ここで、目的と手段の関係とは、

ある目的は1つ以上の手段によって構成される。
またその目的内の手段は、より詳細な手段の目的となる。
逆にある目的は、より上位の手段となりうる。

を意味し、
しばしば目的(=関数)と手段(=手続き)を再帰的な関係で捉えています。

これを踏まえると、関数の中でそのまま使う場合は、事象ベース、
より下位の目的に引き渡す場合は、目的ベースとなる感じでしょうか。

ただ、目的ベース、すなわち下位の関数への引数とする場合、
(privateで実装の詳細の深遠でない限り)Enumとしてしまうことが多いです。

例えば、本文の実行環境の例であれば、

enum RunAs {
    Develop,
    Staging,
    Production
}

のような。

2Like

オブジェクト指向に沿った考え方であれば、基本的には「事象」だと考えます。

例として、リンゴが赤くなったら収穫するという処理を考えます。
リンゴ(クラス)は「赤い」という情報(フィールド/メンバ変数)を公開するだけで、それを収穫するかどうかは外部で判断します。
リンゴは、自分の外側で何が行われるかを知る必要はありません。自分で「収穫して!」とは言わないということです。
良く会社で上司が言う「事実だけを報告しろ。お前の感想はいらない」と同じです。 判断するのは上司です。

これは、クラス外部への公開についての例ですが、内部でも同じだと考えます。

「理由」とした方が良いと思うのは、分岐処理の判定式が「異様に長く可読性が下がる」という場合です。
その際は、判定式を抜き出し「目的名前」の変数に代入して、それで判定します。 物理的にも近くにある必要があると思います。

メソッド間通信としての変数に関しては、@ktz_aliasさんと同じです。

1Like

@Rui_K さんのご意見

オブジェクト指向に沿った考え方であれば、基本的には「事象」だと考えます。

は、確かにごもっともですが、それはメンバ(フィールド/プロパティ)の場合ですね。

ローカル変数の場合は、基本的には目的があってそのために変数を定義しているので、目的を書くのがよいように思います。
ただし大きく異なる複数の目的に使われる場合や、メンバの値をコピーしただけの場合は「事象」の方がよさそうです。

1Like

確かに、クラス内部(ローカル変数)の場合は「目的」変数とした方が良さそうですね。これは「こっちで決まり!」というルールを決めるのは難しそうです。
その変数を何に使うか、というところで判断するしかない…つまりケースバイケースという、あいまいな結論になってしまいそうです。

0Like

Your answer might help someone💌