(jp) =
簡単な関数を想像してください: rgbToHex
. 3 つの引数を取ります。 0 と 255; 16 進数の文字列に変換します。
この関数の定義は、動的で弱い型付けの言語では次のようになります。
rgbToHex(red, green, blue)
// …
「プログラムの正しさ」が不可欠であることは誰もが認めるところだと思います。 私たちはバグを作りたくないので、テストを書きます。
assert(rgbToHex(0, 0, 0) == '000000')
assert(rgbToHex(255, 255, 255) == 'ffffff')
assert(rgbToHex(238, 66, 244) == 'ee42f4')
テストのおかげで、実装が期待どおりに機能することを確認できます。 右?
ええと…私たちは実際に3つだけをテストしています 16,777,216 可能な色の組み合わせ。 しかし、人間の推論によると、これら 3 つのケースが機能する場合、おそらくすべてが機能します。
整数の代わりに double を渡すとどうなりますか?
rgbToHex(1.5, 20.2, 100.1)
または、許容範囲外の数値ですか?
rgbToHex(-504, 305, -59)
どうですか null
?
rgbToHex(null, null, null)
それとも弦?
rgbToHex("red", "green", "blue")
それとも、引数の量が間違っていますか?
rgbToHex()
rgbToHex(1, 2)
rgbToHex(1, 2, 3, 4)
それとも上記の組み合わせ?
プログラムが必要なことを実行することを比較的確実にする前に、テストする必要がある 5 つのエッジ ケースを簡単に思いつくことができます。 これで、少なくとも 8 つのテストを作成する必要があります。時間があれば、他のいくつかのテストを思い付くことができると思います。
これらは、型システムが目指す種類の問題です 部分的に 解決する。 そして、その言葉に注意してください 部分的に、私たちはそれに戻ります。
入力をタイプでフィルタリングすると (それは利用可能なすべての入力のサブカテゴリと考えることができます)、テストの多くは時代遅れになります。
整数のみを許可するとします。
rgbToHex(Int red, Int green, Int blue)
// …
のおかげで不要になったテストを見てみましょう。 Int
タイプ:
- 入力が数値かどうか
- 入力が整数かどうか
- 入力が null でないかどうか
正直なところ、これよりもうまくやることができます: 入力された数値が 0 と 255.
残念ながら、現時点では、多くの型システムの制限に直面しています。 確かに使える Int
ただし、多くの場合 (私たちの場合と同様)、この型によって記述されるカテゴリは、ビジネス ロジックにはまだ大きすぎます。 一部の言語には UInt
または「符号なし整数」タイプ。 それでも、これは「数値データ」のサブセットが大きすぎます。
幸いなことに、この問題に対処する方法があります。
1つのアプローチは、「構成可能な」またはジェネリック型を使用することです。たとえば、 Int
. ジェネリックの概念は多くのプログラミング言語で知られていますが、整数などのスカラー型を構成できる言語は知りません。
編集:私の読者の一人が私にこれを知らせました は エイダで可能。 ありがとう、アダム!
それにもかかわらず、理論的には、ビジネス ロジックを十分に理解できるように型を事前に構成することができます。
これらの種類のジェネリック型がない言語では、多くの場合、カスタム型を構築する必要があります。 私自身オブジェクト指向プログラマーなので、クラスを使用してこれを行います。
class MinMaxInt
public MinMaxInt(Int min, Int max, Int value)
assert(min <= value <= max)
this.value = value
のインスタンスを使用している場合 MinMaxInt
、その値が整数のサブセット内に制限されていることを確認できます。
それにしてもこれ MinMaxInt
クラスは私たちの場合には一般的すぎます。 入力する場合 rgbToHex
それでは、正確な境界が何であるかはまだわかりません。
rgbToHex(MinMaxInt red, MinMaxInt green, MinMaxInt blue)
// …
より具体的なタイプが必要です。 RgbValue
. それを追加するかどうかは、プログラミング言語と個人的な好みによって異なります。 私は延長します MinMaxInt
、しかし、あなたに最も適したものを自由にやってください.
class RgbValue extends MinMaxInt
public RgbValue(Int value)
parent(0, 255, value)
これで、実用的なソリューションに到達しました。 を使用することにより、 RgbValue
タイプ、私たちのテストのほとんどは冗長になります。
rgbToHex(RgbValue red, RgbValue green, RgbValue blue)
// …
これで、ビジネス ロジックをテストするためのテストを 1 つ持つことができます。 RGB-有効な色、この関数は正しい色を返しますか 16 進数 値?」 — 大幅な改善です!
# 注意事項
詳しい読者は、すでに 1 つまたは 2 つの反論を考えることができます。 それらに対処しましょう。
# テストは移動しただけ
カスタム型を構築している場合でも、それらをテストする必要があります。 これは、私が使用している言語の影響を受ける私の例に当てはまります。
ただし、言語の機能に依存します。 これを可能にする言語を考えると:
rgbToHex(
Int<0, 255> red,
Int<0, 255> green,
Int<0, 255> blue
)
// …
機能は言語自体に組み込まれているため、追加のテストは必要ありません。
しかし、カスタム型を作成してテストする必要に迫られたとしても、それらがコード ベース全体で再利用可能であることを忘れないでください。
作成している型のほとんどを再利用できる可能性があります。 これらのカスタム カテゴリは、お客様のビジネスに適用される可能性が高く、全体で使用されているためです。
# 冗長性
次に、実際に使用すると、多くの人が私のソリューションが冗長すぎると考えるでしょう。
rgbToHex(
new RgbValue(60),
new RgbValue(102),
new RgbValue(79)
);
個人的には、この冗長性は気にしませんが (より強力な型システムの利点は知っています)、少しの間、既成概念にとらわれずに考えてみてください。 この議論はより強力な型に反対するものではなく、プログラミング言語に反対するものです。
冗長性は、言語によって提供される適切な構文がないために発生します。 幸いなことに、問題を解決する方法を思いつくことができます。
1 つの解決策は型ジャグリングです。 実際、動的言語はそれが得意です。 単純な整数を入力として渡すと、コンパイラはその整数をオブジェクトにキャストしてキャストできます RgbValue
. キャストできる可能性のある型を認識することさえできます RgbValue
、したがって、コンパイル時のエラー検出がまだあります。
# 単独の例
もう 1 つの反論として、実際のコード ベースは単純なコード ベースとは明らかに異なるということがあります。 rgbToHex
関数。
ただし、反対のことを主張したいと思います。この例の背後にある理由は、コードのどの部分にも適用できます。 実際の問題は、使用する言語とフレームワークにあります。強い型が最初から組み込まれていないと、それらを最大限に活用するのに苦労することになります。
ここで、Gary Bernhardt によるこのトークを視聴することをお勧めします。長さは 30 分未満です。 その中で、彼は型システムの話題を取り上げ、型システムに対する私たち自身の偏見とイデオロギーに立ち向かいます。
その後、現在使用しているフレームワークと言語にこの考え方を適用できます。
私の例は孤立した例ですが、より強力な型によって解決される根本的な問題は簡単にスケーリングできます。
もしも インフラストラクチャがそれをサポートします。
では、スタック全体を捨てるべきだと言っているのでしょうか、それとも弱い型付け言語を使用するのが下手なプログラマーだと言っているのでしょうか? 絶対にありません!
私自身がプログラムします PHP 毎日、以前ほど悪くはありません。
PHP はオプトイン型システムを導入したため、言語がもともとそのために構築されていなかったとしても、かなり強く型付けされたコードを書くことができます。 頭に浮かぶ別の例は、TypeScript を使用した JavaScript です。
そのため、もともと型システム用に作成されていない多くの言語でも、型システムを活用することができます。 しかし、それにはあなたの側からのマインドシフトが必要になります。 私の経験では、努力する価値があります。
# 制限事項
最後に、型システムに関して部屋の中の象に対処しましょう。 強力な型システムのおかげで多くのテストが省略される可能性がありますが、いくつかはまだ作成する必要があることが明らかであることを願っています。
強く型付けされた言語でテストを書く必要がないと主張する人々は間違っています。
覚えておいてください 部分的に さっき言った?
理想的な世界では、完璧な型システムは、ビジネスに必要なすべての特定のカテゴリを説明できます。 ただし、コンピューターとプログラミング言語では使用できるリソースが限られているため、これは不可能です。
したがって、厳密な型はプログラムの正確性を保証するのに役立ちますが、ビジネス上の正確性を保証するためには常にいくつかのテストが必要になります。 「どちらか」ではなく「両方」の問題です。
この投稿ではいくつかの概念について言及しましたが、説明した概念のいくつかを使用するプログラミング言語については知らなかったとも述べました。 とはいえ、具体的な例をいくつか挙げたいと思います。
したがって、この投稿で言及すべき言語で作業している場合は、次の方法でお知らせください。 ツイッター、電子メール、またはソーシャルメディアでこの投稿を読んだ場所。
もちろん、このトピックに関する他の考えを共有するために手を差し伸べることもできます。ぜひお聞かせください!