有害な文字列

10124 ワード

aを示すために空の文字列の使用null 値または値の不足は、使用している言語がその意志をサポートするためのより良い方法を持っている場合、バグにつながるし、コードを維持するのは難しいでしょう.ごくわずかな例外で、空の文字列はすべてのコストで避けるべきです.
私のキャリアの数回、私は同僚に空の文字列を使用することの問題を実証しているので、私はそれがうまくいけば学ぶためにあなたのためにそれをすべての時間を書いていると思った.
簡単な例を挙げましょう.私はこの記事のためにtypescriptを使うつもりです、しかし、それはtypescript記事でありません:それはタイプシステムを持っているどんな言語にでも適用されます、そして、その型システムは値が「ストリング」または「未定義の」/「NULL」/「NIL」/「オプションである」/「多分」であることを表すことができます.
そこで、ニックネームを持つ人をサポートする名前を返すメソッドを見てみましょう.考えるDwayne "THE ROCK" Johnson .
function printName1(firstName: string, lastName: string, nickName: string) {
    return `${firstName} "${nickName.toUpperCase()}" ${lastName}`;
}
簡単な呼び出しのために、これはうまくいきます.以下のように呼びます.
printName1('Dwayne', 'Johnson', 'The Rock')
そして、私は私が予想する出力を得ます.Dwayne "THE ROCK" Johnsonさて、コードを変更してニックネームをサポートしたい.誰もがニックネームを持っているので、十分に公正.
私の最初の本能はミドルネームを送らないことかもしれない.
printName1('Dwayne', 'Johnson')
しかし、コンパイラはキックインし、私のIDEは、予想される3つの代わりに2つの引数を呼び出していると私に言います.十分に公平.しかし、私は急いでいます、そして、私はちょうどこれをする必要があります.それで、私はちょうどこれのまわりで働くことができます.
printName1('Dwayne', 'Johnson', '')
私は空の文字列は何も表示されません知っているので、私はそれをテストする気にしないでください.私は生産にそれをロールバックし、私のユーザーは文句を言い始める.
突然、我々は見ているFirst "" Last において- huh?
オーム空文字列をチェックしなかった.うーん.さて、このまれで特権的な状況では、私は両方の著者とコードの消費者です.私はコンパイラが私にそれを扱うように言うことができたが、alas、それはそうではないが、私はスマートであり、私はこれを修正することができます.
function printName2(firstName: string, lastName: string, nickName: string) {
    if (nickName.length > 0) {
        return `${firstName} "${nickName.toUpperCase()}" ${lastName}`;
    }
    return `${firstName} ${lastName}`;
}
良い作品今.私は、私が関数実装とコードの呼び出し元の両方を制御する幸運な位置にいるという事実を利用しました.
しかし、あなたがそうでないならば、どうですか?ほとんどの時間ではない.
我々はより良いことを行うことができますし、私たちを助けるために我々の言語のコンパイラに頼る.
代わりに、より正確なタイプで機能を正確に表現することを選んだとしましょう.
function printName3(firstName: string, lastName: string, nickName?: string) {
    return `${firstName} "${nickName.toUpperCase()}" ${lastName}`;
}
ここでは両方の方法を呼び出すことができます.
printName3('Dwayne', 'Johnson', 'The Rock')
printName3('Dwayne', 'Johnson')
コンパイラは最初のように文句を言わない.いいえ仕事は、ハッキングなし.関数の呼び出し元にとってより簡単です.
そして、機能の著者として、我々も簡単に時間があります.我々は、余分なドキュメントやコミュニケーションのいずれかの種類の呼び出しをすることができます(これは、将来のあなたかもしれない、同僚、または世界の反対側の人…).このメソッドは何を期待しています.
そして第二に、我々がそれを書いているように、コンパイラはパーティーに来て、我々が行方不明のニックネームの可能性を扱っていないと我々に警告します.

恐ろしい.我々はそれを修正することができます.
function printName3(firstName: string, lastName: string, nickName?: string) {
    if (nickName) {
        return `${firstName} "${nickName.toUpperCase()}" ${lastName}`;
    }
    return `${firstName} ${lastName}`;
}

ここでのより広いポイントは、タイプ・システムが信じられないほど強力で、あなたのために潜在的論理的エラーの多くをチェックすることができるということです.しかし、それはあなたがそれを助ける限り、あなたを助けることができます.この文字列が省略可能な言語を使ってコンパイラに適切に表現することで、コンパイラは私たちのコードを通してずっと私たちを助けてくれます.オプションの文字列のための独自のインジケータを発明することによって-空の文字列-私たちはそのような助けを得る、とバグは非常に迅速に、ドキュメントのようなガードでも自分の道を見つける.
だから、私は空の文字列harmful これらの機能を持つ言語で.これは、言語とその能力についての理解の欠如は、コードへの要件の誤訳と将来のバグの可能性の誤訳を示しています.
しかし、この規則にはいくつかの例外があります.一般的には、これらのコードベースの「エントリポイント」と「終了点」にのみ発生します.たとえば、これらのコントラクトを持つAPI、データベースまたはVisualフロントエンドを処理している場合、意味的に異なる何かを意味する場合があります.
EG :
drawHeading(article.heading, article.subtitle ?? '')
最後のステップでこれを実行することが奨励され、これらの「Exit」と「Entrances」との間のコードを、できるだけ正確にタイプされたコードにして、上記の利点を最大にします.
私は、これが助けたことを望みます.もちろん、このアドバイスはほとんどすべてのプリミティブに一般化します使用number | undefined の代わりに0 . 使用boolean | undefined の代わりにfalse また、プリミティブの組み合わせを使用しても複雑な型.
最後に、ここで何か悪いことがありますか?空の文字列の正当なケースが見つかりませんか?聞いてみたいのですが——