しかし、クライアントのソフトウェアをクラッシュさせることはまだ良いことではありません
それは間違いなく良いことです。
未定義のシステムは、破損したデータなどの厄介なことを行い、ハードドライブをフォーマットし、大統領を脅かす電子メールを送信するため、システムを未定義の状態のままにするものが必要です。システムを回復して定義済みの状態に戻すことができない場合は、クラッシュが原因です。それがまさに、静かに分裂するのではなく、クラッシュするシステムを構築する理由です。確かに、私たちは皆、クラッシュしない安定したシステムを望んでいますが、システムが定義された予測可能な安全な状態にとどまっているときにのみ本当に望みます。
制御フローとしての例外は深刻なアンチパターンと見なされていると聞きました
それは絶対に真実ですが、それはしばしば誤解されます。彼らが例外システムを発明したとき、彼らは構造化プログラミングを壊しているのではないかと恐れていました。我々が持っている理由、構造化プログラミングがあるfor
、while
、until
、break
、およびcontinue
すべての私たちが必要とするとき、そのすべてを行うには、ですgoto
。
ダイクストラは、gotoを非公式に使用する(つまり、好きなところにジャンプする)と、コードの読み取りが悪夢になることを教えてくれました。彼らは私たちに例外システムを与えたとき、彼らはgotoを再発明しているのではないかと恐れていました。それで、彼らは私たちが理解することを期待して「フロー制御のためにそれを使用しない」と言った。残念ながら、私たちの多くはそうしませんでした。
奇妙なことに、gotoで使用していたように、スパゲッティコードを作成するために例外を悪用することはあまりありません。アドバイス自体がより多くのトラブルを引き起こしたようです。
基本的に例外とは、仮定を拒否することです。ファイルを保存するように依頼するとき、ファイルは保存可能であり、保存されると想定します。名前が違法であること、HDがいっぱいであること、またはラットがデータケーブルをかじったことが原因である可能性がない場合に発生する例外です。これらすべてのエラーを別々に処理したり、すべて同じ方法で処理したり、システムを停止させたりすることができます。コードには、前提が当てはまらなければならない幸せな道があります。何らかの方法で例外があれば、その幸福な道から外れます。厳密に言えば、それは一種の「フロー制御」ですが、それは彼らがあなたに警告していたことではありません。彼らはこのようなナンセンスについて話していました:
「例外は例外的であるべきです」。この小さなトートロジーは、例外システムの設計者がスタックトレースを作成する時間が必要なために生まれました。飛び回るのに比べて、これは遅いです。CPU時間を消費します。ただし、システムをログに記録して停止しようとしている場合、または少なくとも次の処理を開始する前に現在の時間を集中的に使用する処理を停止しようとしている場合は、しばらく時間を空けてください。「フロー制御」のために例外を使用し始めた場合、時間に関するこれらの仮定はすべて窓から消えます。そのため、パフォーマンスの考慮事項として「例外は例外的である必要があります」ということが実際に示されました。
それよりもはるかに重要なことは、私たちを混乱させないことです。上記のコードで無限ループを見つけるのにどれくらいかかりましたか?
エラーコードを返さないでください。
...通常エラーコードを使用しないコードベースを使用している場合は、良いアドバイスです。どうして?誰も戻り値を保存してエラーコードを確認することを忘れないからです。Cを使用しているときは、まだ良い規則です。
OneOf
さらに別の規則を使用しています。単に別の大会と戦うのではなく、大会を設定している限り、それは問題ありません。同じコードベースに2つのエラー規則があると混乱します。どういうわけか、他の規則を使用するすべてのコードを削除した場合は、先に進みます。
私はコンベンションが好きです。私がここで見つけた最高の説明の1つ*:
しかし、私はそれが好きなように、私はまだ他の慣習とそれを混ぜることはありません。1つを選んでそれを使い続けます。1
1:つまり、複数のコンベンションについて同時に考えさせないでください。
その後の考え:
この議論から、私が現在取り上げていることは次のとおりです。
- 即時の呼び出し元がほとんどの場合例外をキャッチして処理し、おそらく別のパスを介して作業を続行することを期待している場合、おそらく戻り値型の一部である必要があります。ここでは、オプションまたはOneOfが便利です。
- すぐに呼び出し元がほとんどの場合例外をキャッチしないと予想される場合は、例外をスローして、手動でスタックに渡す手間を省きます。
- 直接の呼び出し元が何をするのかわからない場合は、ParseやTryParseのように両方を提供することもできます。
これは本当に簡単なことではありません。理解する必要がある基本的なことの1つは、ゼロが何であるかです。
5月の残り日数は?0(5月ではないため。すでに6月です)。
例外は仮定を拒否する方法ですが、唯一の方法ではありません。例外を使用して仮定を拒否する場合、幸せな道を離れます。しかし、物事が想定されたほど単純ではないことを示す幸福なパスを送信する値を選択した場合、それらの値を処理できる限り、そのパスに留まることができます。時には0が何かを意味するためにすでに使用されているため、別の値を見つけて、アイデアを拒否する仮定をマッピングする必要があります。あなたは古き良き代数での使用からこの考えを認識するかもしれません。モナドはそれを助けることができますが、必ずしもモナドである必要はありません。
例2:
IList<int> ParseAllTheInts(String s) { ... }
これが意図的に何かを投げるように設計しなければならない理由を考えることができますか?intを解析できないときに何が得られると思いますか?私もあなたに言う必要はありません。
それは良い名前のしるしです。申し訳ありませんが、TryParseは良い名前の私の考えではありません。
答えが同時に複数のものになる可能性がある場合、何も得られない場合に例外をスローすることは避けますが、何らかの理由で答えが単一のものであるか、または何もない場合、私たちはそれが私たちに1つのものを与えるか投げることに執着します:
IList<Point> Intersection(Line a, Line b) { ... }
平行線は本当にここで例外を引き起こす必要がありますか?このリストに複数のポイントが含まれないのは本当に悪いことですか?
たぶん意味的には、あなたはそれを取ることができません。もしそうなら、それは残念です。しかし、Monadsのように任意のサイズがList
ない場合は、気分が良くなるかもしれません。
Maybe<Point> Intersection(Line a, Line b) { ... }
モナドは、それらをテストする必要を回避する特定の方法で使用されることを意図した小さな特別な目的のコレクションです。それらに含まれるものに関係なく、それらに対処する方法を見つけることになっています。そうすれば、幸せな道はシンプルなままです。あなたが触ってすべてのMonadをクラックしてテストすると、間違った使い方をしていることになります。
変だね。しかし、それは新しいツールです(まあ、私たちにとって)。少し時間をおいてください。ハンマーは、ネジでの使用を停止するとより意味があります。
あなたが私にふけるなら、私はこのコメントに対処したいと思います:
どちらのモナドもエラーコードではなく、OneOfでもないことを明確にする答えはありません。それらは根本的に異なっており、その結果、質問は誤解に基づいているようです。(修正された形式ではありますが、依然として有効な質問です。)– コンラッド・ルドルフ 18年6月4日14:08
これは絶対に真実です。モナドは、例外、フラグ、エラーコードよりもコレクションにはるかに近いです。それらは賢明に使用されるときそのような物のための良い容器を作ります。
Result
;-)