回答:
「いいえバグ:CおよびCでお届けするエラーフリーのコード++」ほぼ20年前、私はデビッドThielenの優秀な本から本への洞察の多くを得たとして利用できるようになりました、無料のPDF。
彼は私に2つの素晴らしいアイデアを教えてくれました...
バグはどこからも発生しません。私たちプログラマーは皆、座って自分の指でコードに書き込みます。
「バグ」は、外部の機関がプログラムにバグを蔓延させることを決定したこと、およびクリーンな生活を送って、コンピュータの足元で小さな毛皮で覆われた動物を犠牲にすると、彼らは消え去ることを意味します...この概念は重要ですコードをデバッグするためのアプローチ。間違いを「バグ」と見なした場合、間違いが見つからないことを望みます。(あなたは、良い妖精がやって来て、ピクシーダストを振りかけ、バグが残っていることを望みます。)
バグはバグと呼ばれるのではなく、Massive Fuck-Ups [MFU]と呼ばれるべきです。MFUは、プログラムが人によって書かれ、人がミスをするために存在します... MFUを作成します。あなたは座って、先見の明の完全な悪意を持ってMFUをコードに入れます。それについて考えてください-あなたはそこにバグを置いているのがあなただということを知っています。したがって、コードに腰を下ろすと、いくつかのバグが挿入されます。
バグを書くのはすべてプログラマーの避けられない運命なので、バグを検出したときにジャンプし、悲鳴を上げ、赤旗を振るようなものを含めて、防御的にコーディングする必要があります。
90年代初頭に書かれたため、ティーレンの本の詳細はかなり古くなっています。たとえば、LinuxおよびMac OS Xでは、C ++ new演算子用の独自のラッパーを作成する必要がなくなりました。そのためにvalgrindを使用できます。
しかし、C / C ++ / ObjCに対して日常的に行うことはいくつかあります。
もちろん、新しい言語やテクノロジーに対して何をするかは、細部で異なります。しかし、バグがバグであり、自分の指で書いた大規模な性交であるという考えを心に留めると、あなたのコードは馬鹿の軍隊から絶え間なく攻撃され、頭に将軍がいるので、きっと適切な防御技術を理解します。
まあ、あなたがそれを知っているなら、それらは「既知の未知のバグ」のカテゴリーに陥ります(つまり、「この」性質の何かが発生することを知っています)。単体テストの量は、それらをキャッチするつもりはありません。それらは、既知のケースでのみ本当に役立ちます。
これに対処する方法は、実行中のアプリケーションにエラーログサービスを配置し、エラー発生時にベースに報告し、起動したらそれを処理することです。それ以外の場合は、何年も費やしても何もカバーできません...ある時点で、現実の世界で何が起こっているかを見て、急速に進化するのを待つだけです。
設計面では、重要な要素の1つとして保守性を考慮して設計します。
そして重要なのは...以前にすべてのミスを犯したメンターを見つけるか、何が機能し何が機能しないかを見つけるまで、いくつかのミスを台無しにします。
上記のすべてが良い点です。しかし、言及されていないものがあります。あなたはあなたのモジュールと関数を偏執狂にする必要があります。すべての関数パラメーターの範囲テスト。先頭または末尾が空白の文字列、または文字列が短すぎたり長すぎたりしないように注意してください。偽ではなく真であるブール値に注意してください。PHPのような型なし言語では、予期しない変数の型に注意してください。NULLに注意してください。
多くの場合、この偏執狂的なコードは、プロダクションビルドで無効にしてスピードアップできるアサートとしてエンコードされます。しかし、それは間違いなく直前のパニックバグを防ぎます。
ユニットテストは未知のバグからあなたを救わないとロブは正しいですが、ユニットテストは未知のバグを修正するときにバグを導入することからあなたを助け、誤って古いバグを再導入することからあなたを救います。TDDはまた、最初からテスト可能なようにソフトウェアを設計することを余儀なくさせ、それは大きな継続的な価値をもたらします。
ステータス/「副作用」は可能な限り避けてください。コンピュータは確定的であり、同じ入力に対して同じ出力を提供しますが、入力に関する概要は常に不完全です。悲しいことに、ほとんどの場合、それがどれほど不完全であるかを理解していません。
Webアプリケーション、データベース全体、現在のリクエスト、ユーザーのセッション、インストールされているサードパーティのライブラリなどについて話すときは、入力の一部です。スレッドについて言えば、それはさらに悪いことです。オペレーティングシステム全体が同じスケジューラによって管理されている他のすべてのプロセスは「入力の一部」です。
バグは、入力の処理方法を誤って判断したり、入力を誤って判断したりすることによって発生します。後者は、私の経験では難しいものです。「ライブ」でしか観察できず、多くの場合、もう入力がありません。
新しいテクノロジー、インフラストラクチャなどを学ぶときは、概要、どのコンポーネントが入力に寄与しているかを把握し、それらのできるだけ多くを回避することをお勧めします。
ソフトウェアが複雑になるにつれて、いくつかのバグが発生することは避けられません。それを完全に回避する唯一の方法は、ささいなソフトウェアを開発することです-そしてそれでも、あなたは時々重大な間違いを犯すことになります。
あなたができる唯一の実用的なことは、不必要な複雑さを回避することです-ソフトウェアをできるだけ単純にすることですが、それ以上に単純ではありません。
それが基本的に、より具体的な設計原則とパターンのすべてです。物事をできるだけシンプルにすることです。問題は、「どのように単純であるか」が主観的である可能性があることです。つまり、現在の要件に対して最も単純な設計を意味するのか、将来の要件に合わせて変更するのが単純なのかを意味します。そして、そのための原則もあります。
ユニットテストはこの不確実性の例です。一方で、これらは不必要な複雑さです。コードは開発と保守が必要ですが、それでは仕事が完了しません。一方、これらはテストを自動化する簡単な方法であり、実行する必要のあるはるかに困難な手動テストの量を減らします。
どれほど多くの設計理論を学び、どれだけ多くの経験を積んでも、最優先の原則(そして、場合によっては唯一のガイド)は単純さを目指すことです。
ソフトウェアのバグについてはランダムなことは何もありません。根本的な原因は本質的に完全に決定論的であり、コンピュータに対する誤った指示です。
スレッド化のバグは実行の動作が非決定的である可能性がありますが、根本的な原因ではランダムではありません。
それらはまったく同じ理由で一見予測できない瞬間に発生しますが、根本的な原因がわかったら、それらがいつ発生するかを決定論的に予測できれば、それらがランダムに明らかに予測不可能になるわけではありません。
私はどうやら言って、理由で区別をしました。ランダムとは、方法や意識的な決定なしに、作られる、行われる、起こる、または選択されるという1つのことを意味します。つまり、コンピューター側で独立した意思決定が行われることを意味します。いくつかの非常に確定的なケースでは正しいことをするように言わなかっただけです。
言葉の意味論には理由があります。ランダムは、誰かが誤ってそれを使用したからといって、何か違うことを意味するのではなく、常に同じことを意味します。より適切な用語は、意図的ではない、または明白ではない論理エラーです。
バグをランダムであると見なすことは、コンピューターへの入力とは独立して動作することが完全には理解されていない、理解できない力が働いていることを受け入れるのとほとんど同じであり、あまり科学的ではありません。つまり、神々は怒っていて、気まぐれにあなたのアプリケーションを送信していますか?