web-dev-qa-db-ja.com

デバッグに時間をかけすぎている

昨日、Webプロジェクトのv1.0リリースを約6週間(オンとオフで)作業してきました。時間を正確に記録したことはありませんが、私の経験によれば、プログラミングに費やした時間のうち、半分はデバッグに費やされたと推定しています。デバッグには15〜20時間ほどかかると思います。これは、新しいコードの作成やプロジェクトの早期終了に費やしたほうがいい貴重な時間です。それは特に、私が5週間で大学の新入生になることにも役立ちません。

問題は、デバッグに時間を費やすことに不満を感じることです。デバッグに費やしたすべての時間は、プロジェクトの開発中にかなり愚かな間違いを犯したことに気づき、間違いを修正するにはかなりの時間を費やしました。

これが将来発生しないようにするにはどうすればよいですか?デバッグに50%の時間を費やしたくないので、10%のデバッグと残りを新しいコードの作成に費やしたいと思います。この目標を達成するために役立つテクニックは何ですか?

24
Ryan

あなたはソフトウェアエンジニアリングの聖杯を求めていますが、この質問に対する答えはまだ誰もいません。

重要なことは、発生しているエラーのタイプを追跡し、それらのエラーを分析して、共通の傾向があるかどうかを判断することです。根本原因分析は、このタイプのイントロスペクションの正式な名前であり、Webにはそれに関する多くの資料があります。

専門家はバグ追跡システムを使用して、(1)修正が必要なものを知るだけでなく、(2)事後修正が必要なものを分析することもできます。あなたはそれほど正式である必要はありません-ノートブックに集計を保持するだけで十分かもしれません。

設計段階の欠陥

ほとんどのエラーが問題のステートメントの誤解に起因していることがわかった場合、または問題の解決に使用する間違ったアルゴリズムまたはパスを選択し続けていることがわかった場合、設計段階で問題があります。

プロジェクトの最初により多くの時間をかけて、何を行う必要があるか、どのように行うべきかを正確に書き出す必要があります。この作業を注意深く確認し、元の問題に戻って、本当に正しい方法で取り組んでいるかどうかを判断してください。開始時にさらに1〜3時間かかると、道のりで何時間も節約できます。

コーディングエラー

デザインがしっかりしているが、コーディングの対象となる言語と絶えず対戦している場合は、コードを分析し、間違いを犯していることを警告するツールをいくつか入手してください。

Cでプログラミングしている場合は、すべてのコンパイラ警告をオンにし、lintなどのセマンティックチェッカーを使用し、valgrindなどのツールを使用して、動的メモリ関連の一般的な問題を検出します。

Perlをプログラミングしている場合は、strictおよびwarningsをオンにして、その内容に注意してください。

使用している言語に関係なく、デバッグ段階に到達するずっと前から、よくある間違いを見つけるのに役立つツールが数多く存在します。

統合ステージの欠陥

優れたモジュール性の実践に従ってコードを開発するとき、別々の部分を一緒に接着し始める必要があります。たとえば、コードのさまざまなセクションは、ユーザー入力、データベースの相互作用、データ表示、アルゴリズム/ロジックに関係している可能性があり、これらはそれぞれ比較的独立して構築されています(つまり、手元のセクションに集中する傾向があります)他のすべてとの統合について心配するのではなく)。

ここで、テスト駆動開発(TDD)が非常に役立ちます。コードの各モジュールには、設計どおりに機能することを確認するテストを含めることができます。これらのテストは、最初か、プロセスの非常に早い段階で作成する必要があります。これにより、正直に保つための一連の「ヘルパー」を作成できます。すべてを一緒に動作させ始め、これを実装する方法、または別のサブシステムと相互作用する方法を変更する必要があることに気付いたら、テストにフォールバックして、実行したことを確認できます。すべてが連携して動作するため、コードの正確さが損なわれることはありません。

その他...

ソフトウェアエンジニアリングと実用的なコーディングテクニックに関する本をいくつか読んでください。そうすれば、開発の混乱を減らし、信頼性を高めるためのさまざまな方法を学ぶことができます。また、単純な昔ながらの経験-ハードノックの学校から学位を取得-も、あなたを形にしてくれることがわかります。

結局のところ、結局のところ、少しの時間と事前の作業が、開発/リリースプロセスの後半で大きな利益を生むということです。

キャリアの早い段階でこれらの問題に気付いたという事実は、あなたの将来をよく物語っています。幸運をお祈りします。

35
unpythonic

ユニットテストの記述

コードの単体テストを作成すると、アーキテクチャについて考える必要が生じ、慎重に制御された小さなテスト可能な部分でコードを作成することが推奨されます。これにより、デバッグの労力が大幅に削減され、実行する少量のデバッグは、小さくて焦点が絞られたコードに限定されます。

さらに、作成したテストはコードを「カバー」します。 1つ以上の既存のテストが失敗するため、コードに加えた変更が何かを壊すときを知ることができます。これにより、デバッグ作業の全体的な複雑さが軽減され、コードが機能するという確信が高まります。

もちろん、問題は、デバッグに費やした時間がテストの作成に費やされていることです。 しかし、それらを一度書くだけでよく、それらを書き込んだ後、必要なだけ何度でも実行できます。

37
Robert Harvey

(広義の)デバッグ用の50%は、それほど悪くはありません。通常、実際のコードを書くよりも、設計、テスト、バグの修正、リファクタリング、ユニットテストの作成に多くの時間を費やします。それは仕事の一部です。

正直に言うと、メンテナンスプログラミングの方がはるかに悪いです-よくあることですが、正確に何が問題なのかを1時間かけて調査し、5分でコードを記述して修正し、その後30分で全体をテストします。これは、コーディングが5%を超えているのに対し、ほぼ95%がコーディングされていません。

ただし、デバッグ時間を短縮するためにできることがいくつかあります。

  • デバッグ可能なコードを記述。これは、適切なエラー処理(考慮に入れられたもの)、追跡しやすいようにコードを構造化すること、アサート、トレース、およびデバッガーの使用を容易にするその他のものを使用することを意味します。複雑な線を避けてください。複数のことを行う行は、個別にステップ実行できるように分割する必要があります。
  • テスト可能なコードを書く。コードを単純な関数(または選択した言語がサポートするその他の機能)に分割します。単体テストでこれらをキャプチャするのは難しいため、副作用は避けてください。関数を分離して実行できるように関数を設計します。多目的機能を使用しないでください。 Edgeケースを回避します。関数が何をすべきかを文書化します。
  • テストを書く。単体テストがあるということは、関数が少なくとも入力のサブセットで機能することを知っているということです。また、変更が何も壊さないことを確認するための健全性チェックがあることも意味します。コードカバレッジと入力カバレッジの概念、および単体テストの制限を必ず理解してください。
  • 「ワークベンチ」をセットアップ。これをどの程度正確に行うかは、問題の言語によって異なります。 PythonやHaskellなど)の一部の言語にはインタラクティブインタープリターが付属しており、既存のコードを読み込んで遊んでみることができます。これは、どのようなコンテキストでも関数を呼び出すことができるので最適です最小限の労力で、好きなように-バグを見つけて隔離するための非常に貴重なツールです他の言語にはこの贅沢はなく、小さなインタラクティブなテストプログラムを書くことに頼らなければなりません。
  • 読み取り可能なコードを記述。意図をできるだけ明確に表すコードを書くことを習慣にしてください。完全に明白でないすべてのものを文書化します。
  • 簡単なコードを書く。自分の脳がコードベース全体を理解できない場合、それは単純ではなく、他の誰かが完全に理解できる可能性はほとんどありません。コードが何をすべきか理解していないと、コードを効果的にデバッグできません。
  • 「削除」ボタンで簡単にできます。現在必要のないコードはすべてゴミ箱に含まれています。後で必要になった場合は、ソース管理から復活させてください(これは非常にまれであることを経験で示しています)。処理するコードが多いほど、デバッグサーフェイスは小さくなります。
  • リファクタリング早期かつ頻繁に。リファクタリングを行わないと、新しい機能を追加している間、コードをデバッグ可能な状態に保つことができません。
26
tdammers

詳細な計画

デバッグにかなりの時間を費やすことは避けられません。10%はかなり野心的な目標です。ただし、デバッグと開発に費やす時間を削減する最善の方法の1つは、計画フェーズでより多くの時間を費やすことです。

これは、ダイアグラムからプランニングパッドの疑似コードまでさまざまです。どちらの場合も、開発中にミスを犯すのではなく、何を計画するかを考える時間を増やすことができます。

5

より慎重に作業してください

これは、「2回測定して1回測定」に相当するソフトウェアです。

  • 気が散ったり疲れたりしている場合はコーディングしないでください。
  • 十分に時間をかけて問題について考え、クリーンでエレガントなソリューションを用意してください。単純な解決策は、問題が発生する可能性が低くなります。
  • タスクにすべての注意を払ってください。フォーカス。
  • コーディング後すぐにコードを読んで、間違いを探してみてください。セルフコードレビュー。
  • コーディングとテストの間であまり長く待たないでください。改善のためには、即時のフィードバックが重要です。
  • 一般的にエラーにつながるようなことはしないでください。 コードのにおい を読んでください。
  • 仕事に適したツールを選択してください。

とはいえ、欠陥を完全になくすことはできません。これを人生の事実として受け入れる必要があります。この事実を考慮して、欠陥の計画を立てます。単体テスト。また、これを「永遠に取る」(別名、分析-麻痺)と解釈しないでください。それはバランスを見つけることです。

5
Guy Sirton

他の答えはすでに私が言いたいことのほとんどをカバーしていますが、とにかく私はあなたに私の(残酷に正直な)意見を伝えたいと思います:

基本的に、重要なソフトウェア作業の場合、メンテナンスとデバッグに大部分の時間を費やすことを期待してください。成熟した実稼働ソフトウェアシステムで作業しており、メンテナンスとデバッグに費やす時間の80〜90%は、順調です。

明らかに、「メンテナンス」と「デバッグ」の違いは少し主観的です。 「バグ」は、コードがリリースされ、ユーザーがそれらについて不満を言った後に見つかったコードの問題であるとのみ考えますか?または、何かを追加した後(ご自身のプレリリーステストフェーズで見つかりました)、コードで少しずつ問題が発生しますか?重要なソフトウェアシステム(使用パターンによって異なります)では、一方が他方よりはるかに大きくなる可能性があります。しかし、いずれにせよ、これはおもちゃの「Hello world」プログラムよりも大きなプログラミングに必要なものであり、多くのメンテナンスとデバッグが必要です。一部の人々は、「コードの最初の行の後のすべてが「メンテナンスモード」であると期待されるべきで、新しいコードをまっすぐ書くよりもリファクタリングとデバッグの労力が必要です "。

TL; DR:単純ではないソフトウェアシステムのプログラミングが何であるかについて、少し非現実的な絵を持っているように聞こえるかもしれません。作業の大部分は、微調整、保守、リファクタリング、バグの修正、そして一般に、「非常に一般的な意味で」、まったく新しい作業を行うのではなく、「デバッグ」(保守)の対象となるものを行うことです。新しいコードを書きます。

4
Bobby Tables

継続的な統合(CI)がその答えです。

継続的統合=構成管理システム(つまり、Git、Mercurial、SVNなど)+ CIツール+ユニットテスト+煙テスト

その式は、継続的インテグレーション(CI)の詳細を読むように促すはずです。以下は、この分野のリソースの一部です。

2
karthiks

何をしているのか、どのテクノロジーを使用しているのかについての詳細なしに、特定のテクニックを提供することは困難です。しかし、本当に優れたプログラマーでも、テストとデバッグに多くの時間を費やしています。

たくさんのバグのない良いコードを書くのは経験です。あなたは間違いを犯し、それを修正し、間違いが何であったか、そして間違いを正すために代わりに何をしなければならなかったかを思い出し、次回は同じ間違いを犯しません。そして、あなたがまだ大学にいなくて、間違いを少なくする方法について真剣に考え始めているなら、私はあなたが間違いなくゲームの前にいると言います。

2
Mason Wheeler

本当に、デバッグを減らすために、より深く計画することで、それをフロントロードできます。まだ大学に行ってないの?大学の授業の半ばから後半に、ソフトウェア開発のライフサイクルの詳細を説明します。これは、非常によくあなたの愚行を照らす可能性があります。

雇用主に説明しようとしていますが、コードのメンテナンスとテクニカルサポートを減らす最善の方法は、時間をかけてコードを事前に包括的に計画することです。

1
Rig

他の人はテストとコードレビューに言及しました。これらはどちらも非常に便利ですが、重要な違いがあります。テストは、最初にコードを作成する直前に行うのが最善です。そのため、なぜ特定の方法で行ったのかを簡単に思い出すことができ、テストが失敗したときに問題をすばやく見つけることができます。一方、コードレビューは少し後で行う方がよいでしょう。完全に思い出せずにコードを見て、考えたことを覚えていても入れなかった詳細につまずかないようにする必要があります。コードが明確ではない場所を認識したいとします。あなたはコードが何をしているかを理解しなければならないという少し余分な努力が必要です。問題、または他のコードとの相互作用や新しい技術について取得した新しい知識を適用できるようにしたい。基本的には、コードの見方を変える必要があります。

ただし、これらすべてはまだあなたの質問に接しています。デバッグに費やす時間を短縮するには、まずデバッグする必要があった理由を理解する必要があります。問題の誤解、ツールとテクノロジーの不完全な知識、および「実際のデータがサンプルデータと一致しなかった」という単純な問題のタイプはすべて、さまざまな方法で明らかになり、回避するためにさまざまな手法とタイプの練習が必要になります将来は。

私が作る最後のポイントは経験です。これを取得する簡単な方法はありません。時間を入力するだけです。経験を積むと、最初により良いコードを書き、問題に早く気づき、問題の原因が何であるかについてより良い直感を開発するため、デバッグに費やす時間が減ります。それを維持し、あなたはあなたのキャリアにわたってこれを着実に成長させます。

1
CPhelps

テスト駆動開発 は、デバッグ時間を短縮するのに役立ちます。

  • 小さな集中的なテストがたくさんあるということは、テストが失敗した場合、問題を引き起こした可能性のあるコードがほんのわずかしかないことを意味します。
  • 小さなステップで作業する(失敗したテストを作成して合格にする)ことは、一度に1つのタスクに集中できることを意味します。つまり、現在のテストを過去のものにします。
  • テストパスを作成した後でリファクタリングを行うと、コードを明確でわかりやすい状態に保つことができ、問題が発生した場合の追跡が容易になります。

TDDを使用する場合でも、デバッガーを使用する必要がある場合があります。これが発生した場合は、ユニットテストを記述して、デバッグセッションの原因となったシナリオを再現する必要があります。これにより、その問題が再び発生した場合、テストが失敗したときにすぐに検出され、テストは問題の原因となったコード領域のマーカーとして機能するため、デバッグの必要性が減少します。

1
Jason

プログラミングではデバッグは避けられませんが、ここで重要なのは、コードのデバッグが簡単かどうかです。単純なものをデバッグするだけで何時間も費やす必要がある場合は、コードアーキテクチャに本当に問題があるはずです。

クリーンなコードを書くことに慣れ、コードの貼り付けや長いメソッドの作成などの悪い習慣を取り除く必要があります。

加えて、コードは時々リファクタリングする必要があります。 Martin Fowlerの本を読むことをお勧めします: リファクタリング:既存のコードのデザインの改善

1
dresden

上記の素晴らしい答えですが、直接言及された人はいません(ほとんどの人がこれを示唆していますが)。

読む読む読む読む読むet nauseam ...

あなたが知っているほど、あなたは知らないほど少なくなります。少し決まり文句ですが、それでも基本的な真実です。

上記のヒントに従い、バグを分析的に文書化したら、それらを分類してから、関連する文献を読みます。

設計決定の問題でしたか?デザインパターンについて読んでください。

それはフレームワークや言語の知識の欠如でしたか?骨を折る!

(ライブの)開発者が逃れることのできない2つの事柄があります:変更(ITにおける唯一の定数)とRTFMing ...

0

単体テストとアサート

可能であれば、コードを小さな要素に分解して、個別にテストできます。ただし、これが常に実用的であるとは限りません。一部の機能は、非常に複雑な入力に依存しています。画面にデータを描画するなど、自動化された方法では簡単に確認できない処理を行うものもあります。時々非決定論が含まれるなど.

適切な単体テストを記述できない場合、次善の策はアサートです。ユニットテストでは、所定の入力で正しい答えが得られるかどうかを確認しますが、アサートでは、実際の入力で中間ステップの健全性を確認します。コードにバグがある場合、コードはすぐに失敗し、問題の根源に近く、明確なエラーメッセージが表示されます。あいまいなエラーメッセージの問題から遠く離れているわけではありません。さらに、ドキュメントの前提を表明し、コードを読みやすくします。

0
dsimcha

プロジェクトを開始するとき、いくつの代替アプローチを特定しますか?

それぞれに長所と短所がある2つから4つの異なるアプローチがありますか?その後、それらの中から合理的な選択をしますか?

次に、最も重要なのは、単純性を非常に重要なものとして重み付けしていますか?

私が尋ねる理由は、私の経験では、コード量、したがってバグの数(パフォーマンスは言うまでもありません)は、1つの設計手法と別の手法との間で1桁以上異なる場合があるためです。経験豊富な人々がやっているのは、必要以上のコードを使わずに仕事を終えることです。

彼らは完全に有能であり、すべてのデータ構造アルゴリズム、オブジェクト指向言語の機能などを認識していますが、コードはそうではないように見えます、問題がそれらを必要としない場合、それらはそれらのものを使用するためまばらに、またはまったく使用されません。

0
Mike Dunlavey

バグを修正するたびに、同じ間違いを繰り返さないようにする必要があります。これを行うには、次の操作を実行できます。

  • 欠陥記録ログ に書き留めます。

    • 欠陥タイプ
    • 欠陥が注入されたフェーズ
    • 削除されたフェーズ
    • 修正時間
    • 問題の説明と修正
  • 作成したコードのスタイルを正規化するためにスタイルガイドを採用する

  • 安全なコーディングルールをコードレビュープロセスに統合する

  • 制御フローdata を視覚化する

参照

0
Paul Sweatte