私は他の答えによって示唆された何かを追加したいと思いますが、明示的に言及されているとは思わない:
@puckは、「関数名で最初に言及した引数が実際に最初のパラメーターであるという保証はまだありません」と述べています。
@cbojarは「曖昧な引数の代わりに型を使用する」と言っています
問題は、プログラミング言語が名前を理解しないということです。名前は不透明でアトミックなシンボルとして扱われます。したがって、コードのコメントのように、関数の名前と実際の動作との間には必ずしも相関関係はありません。
次のassertExpectedEqualsActual(foo, bar)
ようないくつかの選択肢(このページや他の場所から)と比較してください。
# Putting the arguments in a labelled structure
assertEquals({expected: foo, actual: bar})
# Using a keyword arguments language feature
assertEquals(expected=foo, actual=bar)
# Giving the arguments different types, forcing us to wrap them
assertEquals(Expected(foo), Actual(bar))
# Breaking the symmetry and attaching the code to one of the arguments
bar.Should().Be(foo)
これらはすべて、冗長な名前よりも多くの構造を持っているため、言語に不透明なものを見ることができます。関数の定義と使用法もこの構造に依存しているため、実装が実行していること(名前やコメントなど)と非同期になることはありません。
このような問題に遭遇したり予見したりするとき、イライラしてコンピューターに向かって叫ぶ前に、まず、そのコンピューターをまったく非難するのが「公平」かどうかを尋ねます。言い換えれば、マシンには、私が望んでいたものと私が求めたものを区別するのに十分な情報が与えられていましたか?
のような呼び出しassertEqual(expected, actual)
は理にかなっているassertEqual(actual, expected)
ので、それらを混同させたり、マシンが先に進んで間違ったことをしたりするのは簡単です。私たちが使用している場合assertExpectedEqualsActual
、代わりにそれはなるかもしれない、私たちは間違いを犯す可能性が低いが、それはマシンにこれ以上の情報を与えない(それは英語を理解することはできません、と名前の選択は意味論に影響を与えるべきではありません)。
キーワードの引数、ラベル付きフィールド、特殊タイプなど、「構造化」アプローチをより好ましいものにしているのは、余分な情報も機械可読であるため、機械が誤った使用法を見つけて、正しいことを行えるようにするためです。assertEqual
唯一の問題は、不正確なメッセージになりますので、場合には、あまりにも悪いことではありません。より不吉な例として、がありますがString replace(String old, String new, String content)
、これは混同しやすく、String replace(String content, String old, String new)
意味がまったく異なります。簡単な解決策は、ペアを取得することです[old, new]
。これにより、ミスが発生するとすぐにエラーがトリガーされます(型がなくても)。
型を使用しても、「必要なものをマシンに伝える」ことができない場合があります。たとえば、「stringly typed programming」と呼ばれるアンチパターンは、すべてのデータを文字列として扱います。これにより、引数の混同(この場合など)、ステップの実行の忘れ(エスケープなど)、誤って不変式の破壊(例えば解析不能なJSONの作成など)
これは「ブール盲目」とも関連しています。ブール盲点(または数値など)をコードの一部で計算しますが、別の部分で使用しようとすると、実際に何を表しているのかがわかりません。これらを混同している、など。これを、わかりやすい名前(たとえば)LOGGING_DISABLED
ではなく、混同するとfalse
エラーメッセージが発生する個別の列挙型と比較してください。