Sollte der Debug-Code immer bestehen bleiben oder nur beim Debuggen hinzugefügt und entfernt werden, wenn der Fehler gefunden wurde?

35

Zum einen füge ich nur Debug-Code hinzu (z. B. print-Anweisungen), wenn ich versuche, einen Fehler zu finden. Und sobald ich es gefunden habe, entferne ich den Debug-Code (und füge einen Testfall hinzu, der speziell auf diesen Fehler hin testet). Ich fühle, dass es den realen Code überfüllt und daher keinen Platz dort hat, es sei denn, ich debugge.

Wie machst du das? Behalten Sie den Debug-Code bei oder entfernen Sie ihn, wenn er veraltet ist (was schwierig zu beurteilen sein kann, wenn dies der Fall ist)?

gablin
quelle

Antworten:

30

Debug-Druckanweisungen sollten entfernt werden. Wenn Sie sie jedoch hinzufügen müssen, um ein Produktionsproblem zu beheben, sollten Sie in Betracht ziehen, ob in Ihrem Protokollierungsframework genügend Informationen vorhanden sind. Informationen zu Parametern, Fehlerbedingungen usw. können später nützlich sein, wenn der nächste Fehler auftritt. Die Verwendung eines guten Protokollierungsframeworks, in dem Debug- oder Tracing-Protokollnachrichten dynamisch aktiviert werden können, kann in der Praxis sehr nützlich sein.

Alaric
quelle
5
+1 Vor allem, um zu erwähnen, dass ein vernünftiges Debuggerüst vorhanden ist. Wenn dies anfänglich vorhanden ist und es verschiedene Debug-Ebenen gibt, kann der Produktionscode hoffentlich ohne Aufrufen teurer Debug-Routinen ausgeführt werden, und der Entwicklungscode kann mit jedem erforderlichen Grad an Überprüfung ausgeführt werden, hoffentlich auf jede gewünschte Weise protokolliert.
Orbling
1
Stimmen Sie mit Orbling überein. Außerdem für einen anderen Debug-Code als die reine Anzeige von Informationen, die Auswirkungen auf die Leistung hatten oder aus anderen Gründen nicht für die Produktion geeignet sind. (z. B. ein Assert-on-Ergebnis der Funktion, z. B. Überprüfen des Ergebnisses einer Sortierung), können Sie zwei Modi für das Erstellungsziel in Betracht ziehen. Debug-Modus und Release-Modus.
Zekta Chan
16

Speziell für das Debuggen hinzugefügter Code sollte aus der Produktionssoftware entfernt werden.

Ob dies eine vollständige Entfernung ist oder in bedingte Kompilierungsabschnitte (wie in C / C ++ / C #) gestellt wird, liegt bei Ihnen und Ihrem Codierungsstandard.

Dafür gibt es eine Reihe von Gründen:

  1. Es kann Sicherheitsrisiken geben, wenn dieser Code ausgeführt wird oder jemand auf seine Ausgabe zugreifen kann.
  2. Dies kann die Anwendung verlangsamen.
  3. Es kann verwirrend sein, wenn andere Entwickler den Code (oder sich selbst) 6 Monate später ansehen.
ChrisF
quelle
+1 für die bedingte Kompilierung, aber Kommentarblöcke funktionieren in Sprachen, die sie nicht unterstützen. Sie sollten es niemals in einem Produkt-Release kompilieren lassen, aber manchmal ist es übermäßig ineffizient, es jedes Mal, wenn Sie einen Release-Build löschen möchten, vollständig zu löschen.
Bill
1
Ich habe in Umgebungen gearbeitet, in denen C / C ++ - Code immer mit Debug-Optionen kompiliert wurde, falls Produktionscode debuggt oder ein Coredump untersucht werden musste. Manchmal erforderte dieses immer bereit zum Debuggen befindliche Mandat, dass Debug-Anweisungen beibehalten wurden, damit sie mit einem Flag aktiviert werden konnten, ohne den Code neu zu kompilieren. Java ermöglicht immer das Debuggen, wenn Ihre JVM-Optionen dafür festgelegt sind, sodass für das spätere Debuggen relativ wenig Vorarbeit erforderlich ist.
Michael Shopsin
16

ChrisF und Alaric haben beide gültige Punkte; +1 für sie. Ich kann mindestens 5 verschiedene Arten von Debug-Code identifizieren, die ich verwende.

  1. Verwenden von Protokollen, um den Systemstatus zu einem bestimmten Zeitpunkt zu sichern.

    void function(...)
    {
        ...dump everything i know about.
    }
    
  2. Verwenden von Protokollen für Ausführungsprüfpunkte

    void function(...)
    {
        ...got here 1
        ...got here 2
    }
    
  3. Code, der tatsächlich erzwingt, dass eine bestimmte Bedingung erfüllt ist, aber das normale Verhalten bricht. Beispiel:

    • Angenommen, Sie haben einige Protokolle zu einem Fehler, können das Problem jedoch nicht reproduzieren. Sie könnten versuchen, Code zu schreiben, der bestimmte Variablen dazu zwingt, bestimmte Werte zu haben, die mit den Informationen im Protokoll übereinstimmen.
  4. Überprüfungsprotokollierung - Ich würde dies als ausführliche Protokollierung klassifizieren, mit der die Richtigkeit der Software überprüft werden kann, die nicht in die Produktion einbezogen werden sollte, wie zum Beispiel die Überprüfung der einzelnen Schritte eines Algorithmus.

  5. Vorgangsprotokollierung - siehe Beitrag von Alaric . Das ist so ziemlich das, was ich unter "Operationsprotokollierung" verstehe.

1, 2 und 3 sollten komplett herausgenommen werden. Sowas wie 4 würde ich wohl bedingt aus dem Code kompilieren. Für 5 hatte Alaric einen guten Grund, die Protokolle dynamisch ausschalten zu können. Das mag in den meisten Fällen den Punkt von ChrisF in seiner zweiten Kugel ansprechen .

Pemdas
quelle
1
Dies ist eine gute Zusammenfassung. Es wäre jedoch besser, wenn Sie es richtig formatieren könnten, indem Sie 1)... durch 1.... ersetzen (damit die Markdown-Formatierung es als Liste aufnimmt) und den Beispielcode um 8 Stellen einrücken (erneut, damit Markdown es als Beispiel aufnimmt) Code innerhalb einer Liste).
Konrad Rudolph
@Konrad Rudolph: Fertig.
Gablin
3

Es hängt davon ab, was der Code tut. Einige Codes, die zum Debuggen verwendet werden, können unverändert bleiben, andere sollten entfernt werden.

Code, der die Richtigkeit der Parameter in einer Methode überprüft, ist nicht immer nützlich, wenn der Code ordnungsgemäß funktioniert, wird jedoch häufig beibehalten, um sicherzustellen, dass der Code weiterhin ordnungsgemäß funktioniert.

Manchmal schreiben Sie Code anders, um das Debuggen des Codes zu vereinfachen, z. B. indem Sie einen Wert berechnen und in eine lokale Variable einfügen. Anschließend verwenden Sie die Variable in der nächsten Zeile, um das Ergebnis der Berechnung bei Einzelschritten leichter überprüfen zu können durch den Code. Sie könnten den Code so umschreiben, dass der berechnete Wert direkt verwendet wird. Die Kosten für die Verwendung der lokalen Variablen sind jedoch so gering (wenn überhaupt), dass es kaum einen Grund gibt, den Code umzuschreiben. Es ist auch sinnvoll, den Code nach dem Testen unverändert zu lassen. Es besteht immer ein geringes Risiko, dass beim Ändern ein Fehler auftritt.

Code, den Sie nur hinzufügen, um einen bestimmten Fehler aufzuspüren, kann häufig entfernt werden, nachdem Sie den Fehler gefunden haben.

Guffa
quelle
2

Es war einmal eine Menge Debugging-Code. Ich war fast ausschließlich auf Windows ausgerichtet, daher gab es viele dieser Debug-Ausgabefunktionen für Zeichenfolgen, bei denen ich mich nicht mehr daran erinnere, wie man buchstabiert, sodass ich die Ablaufverfolgung mit einem bestimmten Programm erfassen konnte.

Einige Debug-Codes, insbesondere solche, die das Verschachteln von Aufrufen ermöglichen sollten, blieben erhalten. Obwohl das Debug-String-Ding auf einem Produktionssystem zumeist nicht sichtbar war, wurde es dennoch unter bestimmten Bedingungen kompiliert.

Die Realität ist jedoch, dass all dieser Debug-Code eine Menge Aufwand für etwas war, das idealerweise anders gehandhabt wird - natürlich mit einem Debugger. Zu der Zeit war ich vom Borland C ++ - Debugger nicht so beeindruckt. Die Tools waren vorhanden, führten jedoch zu häufig zu irreführenden Ergebnissen. Die Verwendung des Debuggers ohne IDE (häufig erforderlich) bedeutete, dass Tastenkombinationen gespeichert wurden, was eine Ablenkung vom eigentlichen Job bedeutete.

Die einzige Debugging-Erfahrung, die ich als schlimmer empfunden habe, ist die Befehlszeilen-GDB.

Ein Experte für die Tools zu sein, die Sie jeden Tag verwenden, ist natürlich wichtig - aber das Debuggen sollte eigentlich nicht etwas sein, das Sie jeden Tag tun. Wenn Sie den Debugger so oft verwenden, dass Sie Dutzende von Befehlen und / oder Tastaturkürzeln lernen können, scheint mir das ein bisschen rot zu sein.

Als ich in Visual Studio 7 arbeitete, war mir jedoch klar, dass das Debuggen sehr praktisch und effektiv sein kann. Wenn Sie das Debuggen in Visual Studio durchführen können (Express-Editionen inbegriffen), ist das Debuggen ein Kinderspiel. Ohne Zweifel, wenn Sie das richtige GUI / IDE-Frontend finden, ist GDB auch einfach und effektiv, obwohl ich diese Suche noch nicht durchgeführt habe.

Es gibt auch etwas zu sagen für Unit-Tests mit Coverage-Analyse mit gcov. Je sicherer Sie mit dem Verhalten Ihrer Bibliotheken sind, desto weniger tief muss Ihr Debugging sein - und desto seltener benötigen Sie den Debugger. Und Unit-Tests zu schreiben, ist ziemlich vernünftig, was Sie an den meisten Tagen tun sollten.

Unerwartet wichtiges Tool = cmake, ein Build-Tool, mit dem ich unter anderem problemlos zwischen GCC- und VC ++ -Erstellung wechseln kann. So kann ich meine Unit-Tests und gcov-basierte Berichterstattung mit GCC durchführen, aber einfach zu VC ++ wechseln, um den Debugger zu verwenden.

Steve314
quelle
Ein Debugger kann ziemlich nutzlos sein, wenn er in Multithread-Anwendungen nicht gefährlich ist.
Pemdas
@Pemdas - Ich hatte noch kein ernstes Problem in dieser Richtung, obwohl Multithreading offensichtlich nicht Debugger-freundlich ist. Trotzdem halte ich die richtigen Tools im Prinzip für eine bessere Lösung als Debug-Code. Ein statisches Analyse-Tool, das Race-Bedingungen, Deadlocks, Bedingungen, unter denen zwei Threads gleichzeitig um denselben Speicher / dieselbe Ressource kämpfen können, usw. erkennen kann, wäre schön. Ich habe keine Ahnung, was in dieser Hinsicht verfügbar ist, obwohl ich weiß, dass es einige clevere Tools gibt. klee zum beispiel - ich verstehe das nicht, aber die grundbeschreibung klingt sehr beeindruckend.
Steve314
"Ich denke, die richtigen Tools sind im Prinzip wahrscheinlich eine bessere Lösung als Debug-Code." Das ist eine gefährliche Aussage;). Tools zu haben, die einen Teil der Analyse vorbereiten, mag nett sein, aber ich mache mir Sorgen, dass Entwickler, insbesondere neue, zu stark von den Tools abhängig werden, wie jemand, der einen Taschenrechner verwenden muss, um herauszufinden, was 15% von 100 sind.
Pemdas
Zu abhängig von Tools zu werden, die ich noch nicht einmal erforscht habe, scheint unwahrscheinlich. Ja, in Ihrem Taschenrechnerbeispiel, aber ich verwende weiterhin OpenOffice Calc, anstatt meine eigene einfache Tabelle zu schreiben. Es gibt eine gewisse Zeit für das Debuggen von Code (auch mit einem Debugger - z. B. Ihrem eigenen Fall, der bizarre Bedingungen erzeugt), aber wenn dieser über einen bestimmten Punkt hinausgeht, gewinnen vorhandene Tools. Und wenn es darum geht, 15% von 115 zu subtrahieren, verwende ich auch diesen Rechner - was viele Leute als offensichtliche Antwort (100) angeben würden, ist falsch. Offensichtlich sind richtige Antworten beim Multithreading berüchtigt dafür, dass sie sich manchmal als falsch herausstellen.
Steve314
1

Meine Meinung dazu: Debug-Code, der verwendet wird, um einen Fehler innerhalb des fraglichen Codes zu beseitigen, den ich im Allgemeinen vollständig entferne. Debug-Code, der verwendet wird, um einen Fehler zu beseitigen, der von externen Kräften herrührt.

Loren Pechtel
quelle
-1

Wenn der Fehler vom Unit-Test oder vom internen stammt, könnte der Debug-Code komplett entfernt werden. Wenn der Fehler jedoch aus der Produktion stammt, sollte der Debug-Code in den Compile-Tags enthalten sein. Das Einfügen in Compile-Tags hilft den anderen Entwicklern zu verstehen, dass dieser Code nur zu Debug-Zwecken dient.

Manoj R
quelle
-1

Verwenden Sie TDD , damit Ihr Testcode immer einen Ort hat, an dem er auch verwaltet wird.

dukeofgaming
quelle
Wie beantwortet dies die gestellte Frage?
gnat
Denn TDD führt Sie zum "Debuggen" oder Testen von Code, den Sie nicht entfernen müssen.
Dukeofgaming
Ich folge leider nicht. Wie ist das?
gnat