コーディング時にバグの数を減らす方法は?


30

完璧な人はいませんし、私たちが何をしようとも、時々バグを含むコードを作成します。新しいソフトウェアの作成時と既存のコードの変更/保守時の両方で、発生するバグの数を減らすためのいくつかの方法/手法は何ですか?


良い方法は、より多くの事前設計を行うことです(多すぎず、コードをより構造化して理解しやすくするのに十分です)。
ジョルジオ

回答:


58

派手なコーディングは避けてください。コードが複雑になるほど、バグが発生する可能性が高くなります。通常、現代のシステムでは、明確に記述されたコードは高速で十分に小さくなります。

利用可能なライブラリを使用します。ユーティリティルーチンを記述するバグを持たない最も簡単な方法は、それを記述しないことです。

より複雑なもののためのいくつかの正式なテクニックを学びます。複雑な条件がある場合は、ペンと紙でそれらを釘付けにします。理想的には、いくつかの証明技術を知ってください。コードが正しいことを証明できれば、修正するのが簡単で、大きくて愚かで明白なバグを除いて、ほとんど常に良いことです。明らかに、これはこれまでのところに過ぎませんが、時には小さいながら複雑なものについて正式に推論することができます。

既存のコードについては、リファクタリングの方法を学びます。多くの場合、自動化ツールを使用して、動作を変更せずにコードを読みやすくする、コードに小さな変更を加える方法を学びます。

急ぎすぎないでください。少し時間をかけて正しいことをして、自分のやったことを確認し、自分のやっていることを考えると、後で大きな成果を上げることができます。

コードを作成したら、それを使用して適切なコードを作成します。単体テストは素晴らしいです。多くの場合、事前にテストを書くことができます。これは素晴らしいフィードバックになる可能性があります(一貫して行われる場合、これはテスト駆動開発です)。警告オプションを使用してコンパイルし、警告に注意してください。

他の人にコードを見てもらう。正式なコードレビューは良いのですが、都合の良いタイミングではないかもしれません。プルリクエスト、またはscmがそれらをサポートしていない場合は、非同期のレビューを許可する同様のリクエスト。バディチェックは、あまり形式的なレビューではありません。ペアプログラミングにより、2組の目ですべてを確認できます。


x2-ライアンが言ったこと。
JBRウィルキンソン

2
また、ほとんどの言語は多かれ少なかれ気難しいかもしれません。できるだけうるさいものにしたい。

1
「より複雑なもののためのいくつかの正式なテクニックを学んでください。」...例えば?
ダンローゼンスターク

1
@Yar:この本で説明されているシステムのようなものを期待しています:amazon.com/Verification-Sequential-Concurrent-Programs-Computer/… ; 特定の本は非常に乾燥して鈍いと言わざるを得ないので、おそらくもっと良い本があるでしょう(しかし、私が読んだ唯一の本です)。
ジョーリSebrechts 14

30

単体テストを使用すると、2回目に現れるバグの数を減らすことができます。コードにバグが見つかった場合、単体テストを作成すると、後でバグが再発しないことを確認できます。(さらに、すべてのケースを考え、何千ものユニットテストを前もって書くことは時々やることが難しいです)


3
「すべてのケースを前もって考える」ことは、きれいで完全に指定されたインターフェースにつながります。単体テストは、テストを念頭に置いて設計されていないコードにユニットテストを組み込む場合にのみ作成するのが困難です。
マイクシーモア

1
可能であれば、そうすべきです。残念ながら、ユニットテストのほとんどの場所では、「バグをすばやく修正する」以上のコストがかかります。そのため、可能であればテストを前もって作成する必要がありますが、「費用対効果の高い」と見なされない場合は、バグ修正と一緒にそれらを書くことで、ユニットテストを書くだけの予算をかけずに時間をかけて構築することができます。
ライアンヘイズ

4
「テストにより、バグの有無ではなく、存在が示されます。」-E.ダイクストラ。そうは言っても、自動化されたテストは、ソフトウェアの品質を維持および向上させるための非常に便利な方法です。
リミスト

9

両方の単体テストコメントで+1。

さらに、コンパイラが提供する最高の警告レベルを設定し、警告がエラーとして扱われるようにします。多くの場合、バグはこれらの「誤った」エラーに隠れています。

同様に、コンパイル時に実行される静的解析ツールに投資します(これらをコンパイラ警告の追加レベルと見なします)。


静的分析コメントの場合は+1。すべての情報を無料で入手することは非常に貴重です:)
モーテンジェンセン

9

言及されていることに加えて:

  • エラーコードを無視しないでください。たとえば、有効な結果が得られた、ファイルが正常に作成されたなどとは思わないでください。
  • コードが何らかの条件を入力しないと仮定しないでください。したがって、「その条件を無視しても安全です」。
  • コードをテストしてから、他の人にテストしてもらってください。私は自分のコードをテストするのが最悪だと思います。
  • ひと休みしてからコードを読み直し、「明らかなことを逃した」かどうかを確認してください。私によく起こります。

私が現時点で忘れている他の多くのことですが、他の人は確かにそれらについて考えるでしょう。:)


7
条件Xが絶対に発生しないことが確実な場合は、アサートを使用して条件Xが発生したときに(例外、ロギング、その他何でも)がわかるようにします。
フランクシェラー

@MetalMikester:単体テストは良いです。しかし、高レベルの言語と優れたライブラリを使用すると、ほとんどのハードバグを解決するには統合テストと回帰テストが必要です。
ベクトル

9

私の主要言語はC ++とPythonですが、かなり機能的なプログラミングスタイルを開発しました。すべてのコンテキストを関数(またはメソッド)に渡して、その関数が処理を行う必要がある関数(またはメソッド)を返し、探している意味のあるデータを返すと、コードがより堅牢になりました。

暗黙の状態は敵であり、私の経験ではバグの一番の原因です。この状態はグローバル変数またはメンバー変数の場合がありますが、結果が関数に渡されない何かに依存している場合は、トラブルを求めています。明らかに、状態を排除することは実行可能ではありませんが、それを最小化するとプログラムの信頼性に大きなプラスの効果があります。

また、すべてのブランチ(もし、for、while 、? :)がバグである可能性があることを同僚に伝えたいです。バグの発現がどうなるか言うことはできませんが、コードの条件付き動作が少ないほど、実行中のコードカバレッジがより一貫しているという事実だけでバグが発生する可能性が高くなります。

図を見てください。これらのことはすべて、パフォーマンスにもプラスの効果があります。勝つ!


私の経験では、メソッドが必要なだけ小さい場合、呼び出しごとにすべての状態を渡すのはすぐに退屈になります。この問題は、オブジェクトの寿命が短い多くの小さな不変クラスを使用することで解決できます。これにより、一時的な状態をフィールドとして保存し、状態が不要になったときにオブジェクトを破棄できます。:-)
ヨルゲンフォー14

退屈になる場合のもう1つの考慮事項は、おそらくあなたがあまりにも多くの状態をやり取りしようとしているということです。:)
ダッシュトムバン14

多くの場合、それは真実ですが、多くの場合そうではありません。いくつかのドメイン内では、多くの可変状態がなくても、多くの状態にアクセスする必要があります。現在、いくつかのシンボルテーブルにアクセスする必要があるコードジェネレーターに取り組んでいます。それらをすべてのメソッドに渡したくありません。
ヨルゲンフォー14

8
  • より多くのことを行うより少ないコードを記述します。
  • 低レベルの影響と高レベルの影響について考えます
  • コードで作成している抽象化を熟考します。
  • 可能であれば、本質的な複雑さのみを記述してください。

私は、「より少なく、より多くのことを行う」と要約する大きな記事を書くつもりでした(IOWは利用可能なツールを知って使用しています)。代わりにこれに+1するだけです。
カズドラゴン

1
しかし、より少ないコードを達成しようとするとき、派手なコードを取得しないように注意してください。
ギャブリン

1
@gablin:多くの点でファンシーは見る人の目にあります。私は、4年前には困惑していたであろうコードを今日書いて読むことができます。Haskellは今日、私にとって空想的です。:)
ポールネイサン

8

技術的な答えは少し少なくなります。疲れている(1日9時間で十分)、酔っ払っている、または「焼いた」ときにプログラミングしないでください。疲れているときは、きれいなコードを書くのに必要な忍耐力がありません。


2
通常、ほとんどのプログラマーはこれを実現するのに数年かかります。重要なポイントです。
ジェフデイビス


5

ここで、単体テストとツールに関するいくつかの素晴らしい回答。追加できるのはこれだけです。

できるだけ早くテスターを参加させる

テストチームがある場合、コード品質のゲートキーパーとしてそれらを扱い、あなたの欠陥をキャッチするというtrapに陥らないでください。代わりに、できるだけ早くそれらと協力し、それらを関与させます(アジャイルプロジェクトでは、これはプロジェクトの最初から行われますが、実際に試してみると、いつでも早期に関与させる方法を見つけることができます)。

  • テスト計画が何であるかを調べてください。彼らと一緒に彼らのテストケースをレビューしてください-あなたはそれらをすべてあなたのコードでカバーしていますか?
  • 要件を理解してもらうよう依頼してください。それはあなたのものと同じですか?
  • 早期にテストビルドを行うための早期ビルドを提供します。彼らが提案する改善に驚くでしょう。

テスターと良好な関係を築くということは、彼らが損害を与える前に、本当に早い段階で、貧弱な仮定や欠陥をキャッチできることを意味します。また、テスターは、製品設計を支援し、それらを修正する時間があるときにユーザビリティの問題をキャッチする権限を与えられていると感じることも意味します。


4

静的解析ツール

FindBugsなどのプラグインとアプリはコードをクロールし、潜在的なバグがある場所を見つけます。変数が初期化されておらず、使用されていない場所、または10のうち9倍の狂ったものは、バグが発生しやすくします。このようなツールは、たとえバグではない場合でも、ボーンヘッドが道を移動するのを防ぐのに役立ちます。

PS:ツールが何か悪いことを伝える理由を常に研究することを忘れないでください。学ぶことを傷つけないでください(すべての状況ですべてが正しいわけではありません)。


3

コード検査またはペアプログラミングなどの他の形式のピアレビュー。

Fagan検査などの構造化コードレビューは、少なくとも単体テストと同じくらい効果的かつ効率的であり、場合によっては単体テストよりも優れていることさえ証明されています。検査は、ソフトウェアライフサイクルの初期段階で、コード以外のアーティファクトでも使用できます。

Karl WiegersによるPeer Reviews in Softwareは、このテーマに関するすばらしい本です。


2

ここにある他のすべての提案に加えて、考えられるすべての警告を最高レベルの感度で有効にし、それらをエラーとして扱います。また、言語に含まれるリンティングツールも使用します。

警告によってどれだけ多くの単純なミスをキャッチできるか、そしてそれらの単純なものがコード内の実際のバグにどれだけ変換されるかに驚くでしょう。


2

ここには多くの良い答えがありますが、いくつか追加したいことがあります。要件を実際に理解していることを確認してください。ユーザーが要件はXを意味し、プログラマーはそれがYを意味すると思ったときに多くのバグを見てきました。貧弱または曖昧な要件についての明確化を押し戻します。私たちは皆、飛び込んでコーディングするのが好きであることを知っていますが、理解を確保するために前もって時間を費やすほど、手戻りとバグ修正は少なくなります。

サポートしているビジネスを知ると、要件に欠けているものや詳細な説明が必要なものがよく表示されます。前述のようにタスクYを実行すると、既存の機能Zが破損することに注意してください。

データベース構造を理解します。多くのバグは、構文的には正しいが間違った結果を返すクエリの結果です。結果がおかしく見えるときを認識する方法を学びます。複雑なレポートクエリを作成している場合、いつでも準備ができているとマークする前に、技術専門家に結果を確認してもらいます。次に、彼らがキャッチしなかったことを自分自身にメモし、次に似たようなことをするときに覚えておいてください。


1

最も重要なテクニックは時間をかけることだと思います。新しいモジュールをコーディングするのに2日間必要だと感じたが、上司が1日だけでコーディングすることを強制した場合、コードはバグが発生する可能性が高くなります。

私は、あなたが持つライブべきではないと述べたいくつかの時間前に読んだ本の一つ壊れた窓 anotheroneが壊れてしまった場合は...コーディングの人は気にしませんので、は、同じである、誰もが何かを行う際に最初にあることを気にします悪いですしかし、高速ですが、多くのバグと非常に貧弱なデザインとスタイルで、1つの地獄コードを気にしません。


1

Code-test-code-testの代わりにTest-Code-Testのプラクティスに従います。これは、ユースケースを考え、ロジックを適切に組み立てるのに役立ちます


1

使用コード検査ツールのようなReSharperのなどのIDE のIntelliJ IDEA「に書かれていますが、読まれることはありません」という変数を指摘等により、多くのコピー&ペーストのバグなどについて警告。時間を大幅に節約できました。


1

驚くべきことに、次の3つの非常に重要な点はまだ言及されていません。

  • アサーションを多用します。あなたが常に自問すべき質問は、「これを主張すべきか?」ではありません。しかし、「断言するのを忘れたものはありますか?」

  • 不変性を選択します。(最終/読み取り専用を自由に使用してください。)可変状態が少ないほど、問題が発生する可能性が少なくなります。

  • 時期尚早に最適化しないでください。多くのプログラマーは、パフォーマンスの問題を傍観しているため、パフォーマンスが問題になるかどうかを事前に知ることなく、コードを不必要に畳み込み、設計を粗悪化します。最初に、パフォーマンスを無視してアカデミックな方法でソフトウェア製品を構築します。次に、パフォーマンスが低いかどうかを確認します。(おそらくそうはなりません。)パフォーマンスの問題がある場合は、コードベース全体を微調整してハッキングするのではなく、製品がパフォーマンス要件を満たすようにすてきで正式なアルゴリズム最適化を提供できる1つか2つの場所を見つけてください。あちこちでクロックサイクルを絞ります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.