Ganz allgemein mache ich:
Versuchen Sie, das Problem einzugrenzen. Denken Sie daran, was sich geändert hat, als der Fehler zum ersten Mal auftrat. An was arbeitest du? Welchen Teil des Codes haben Sie geändert? 99% meiner Fehler werden auf diese Weise behoben. Es ist normalerweise etwas Dummes.
Wenn ich weiß, wo das Problem liegt, schauen Sie sich den Code an, der die Ursache zu sein scheint. Lies es. Lies es sogar vor. Fragen Sie sich: "Was versuche ich zu erreichen?" Für einige Arten von Problemen: Könnte es einige Nebenwirkungen haben oder könnte es durch Code an einer anderen Stelle auf eine Weise beeinflusst werden, an die ich nicht gedacht hatte?
Versuchen Sie auf verschiedene Arten zu analysieren, was wo und wann schief geht (siehe unten).
Wenn ich immer noch keine Ahnung habe, überprüfe ich, ob eine ältere Version meiner Quelle das gleiche Problem aufweist. Versuchen Sie herauszufinden, wann das Problem in meiner Entwicklungszeitleiste zum ersten Mal aufgetreten ist. Um dies zu tun, müssen Sie mit einem guten Versionskontrollsystem wie git arbeiten (git hat eine Funktion namens bisect, die genau für diese Art von Debugging geeignet ist).
Wenn Sie immer noch keine Ahnung haben, machen Sie eine Pause ... es hilft tatsächlich oft.
Kehren Sie zum Zeichenbrett zurück und überprüfen Sie, wie Ihr Programm funktionieren soll und ob dies tatsächlich Sinn macht.
Es hängt wirklich von der Art des Problems ab, aber wenn ich eine allgemeine Vorstellung davon habe, wo das Problem sein könnte, dann:
Wenn ich den Verdacht habe, dass das Problem in einem Teil des Codes / der letzten Änderung liegt, versuche ich zuerst, den Fehler durch Vereinfachung des Codes zu beseitigen / zu kommentieren / zu ändern oder was auch immer, und bringe dann den problematischen Code zurück und nehme a schau es dir gut an
Führen Sie einen Debugger mit Haltepunkten aus (falls überhaupt möglich) und überprüfen Sie, wie meine Daten aussehen, wenn sie sich schlecht verhalten, um eine bessere Vorstellung davon zu bekommen, wo etwas schief läuft.
bzr qdiff
Befehl leicht zu sehen .Ich versuche, testgetriebene Entwicklung ( TDD ) zu verwenden. Ich schreibe einen Test, der den Fehler reproduziert, und versuche dann, den Test zum Bestehen zu bringen. Manchmal hilft das Schreiben des Tests, den Fehler zu finden.
Das hält mich die meiste Zeit vom Debugger fern und bietet Regressionstests, um zu verhindern, dass der Fehler erneut auftritt.
Einige Links:
quelle
Es gibt eine Reihe von Definitionen für das Wort Wissenschaft, aber es hört sich so an, als würden Sie sich möglicherweise auf das beziehen, was man genauer als " wissenschaftliche Methode " bezeichnen könnte. Die wissenschaftliche Methode kann zusammengefasst werden, indem einige Phänomene beobachtet werden (vermutlich ein Fehler oder ein unerwartetes Programmverhalten), eine Hypothese oder Hypothesen formuliert werden, um das Verhalten zu erklären, und am wahrscheinlichsten experimentiert wird, um es zu beweisen (Schreiben eines Tests, der das Problem zuverlässig reproduziert).
Die Arten von Fehlern (Phänomenen), die auftreten können, sind praktisch endlos und einige erfordern nicht unbedingt einen genau definierten Prozess. Zum Beispiel beobachten Sie manchmal einen Fehler und wissen sofort, was ihn verursacht hat, einfach weil Sie mit dem Code sehr vertraut sind. In anderen Fällen wissen Sie, dass bei bestimmten Eingaben (Aktionen, Abfolgen von Schritten usw.) ein falsches Ergebnis auftritt (Absturz, schlechte Ausgabe usw.). In diesen Fällen erfordert es oft nicht viel "wissenschaftliches" Denken. Einige Überlegungen können helfen, den Suchraum zu verkleinern. Eine übliche Methode besteht jedoch darin, den Code in einem Debugger schrittweise durchzugehen und festzustellen, wo Fehler aufgetreten sind.
Die für mich interessantesten und möglicherweise eines wissenschaftlichen Prozesses würdigen Situationen sind jedoch die, in denen Ihnen ein Endergebnis ausgehändigt und Sie gebeten werden, zu erklären, wie es passiert ist. Ein offensichtliches Beispiel hierfür ist ein Crash-Dump. Sie können den Crash-Dump laden und den Status des Systems beobachten. Ihre Aufgabe besteht darin, zu erklären, wie es in diesen Status gelangt ist. Der Absturz- (oder Kern-) Speicherauszug kann eine Ausnahme, einen Deadlock, einen internen Fehler oder einen vom Benutzer definierten "unerwünschten" Zustand (z. B. Trägheit) anzeigen. In diesen Situationen folge ich im Allgemeinen den folgenden Schritten:
Eingeschränkte Beobachtung : Studieninformationen, die sich direkt auf das spezifische Problem beziehen, falls zutreffend. Die offensichtlichen Dinge hier sind der Aufrufstapel, die lokalen Variablen, wenn Sie sie sehen können, die Codezeilen, die das Problem umgeben. Diese Art der spezifischen Standortstudie ist nicht immer anwendbar. Zum Beispiel hat das Studium eines "langsamen" Systems möglicherweise keinen offensichtlichen Startort wie diesen, aber eine Absturz- oder interne Fehlersituation wird wahrscheinlich einen unmittelbaren und offensichtlichen Punkt von Interesse haben. Ein konkreter Schritt könnte darin bestehen, Tools wie windbg zu verwenden (führen Sie! Analyse -v auf einem geladenen Crash-Dump aus und sehen Sie sich an, was es Ihnen sagt).
Breite Beobachtung : Studieren Sie andere Teile des Systems. Überprüfen Sie den Status aller Threads im System, und überprüfen Sie alle globalen Informationen (Anzahl der Benutzer / Vorgänge / Elemente, aktive Transaktionen / Prozesse / Widgets usw.), Systeminformationen (Betriebssystem) usw. Wenn der Benutzer externe Details angegeben hat Denken Sie über die Zusammenhänge nach, die Sie beobachtet haben. Wenn Ihnen beispielsweise mitgeteilt wird, dass das Problem jeden Dienstagnachmittag auftritt, fragen Sie sich, was dies bedeuten könnte.
Hypothese: Dies ist der wirklich lustige Teil (und ich bin nicht scherzhaft darüber, dass es Spaß macht). Es erfordert oft viel logisches Umdenken. Es kann sehr unterhaltsam sein, darüber nachzudenken, wie das System in den aktuellen Zustand gelangt ist. Ich vermute, dass dies der Teil ist, den viele Leute für eine Kunst halten. Und ich nehme an, es könnte sein, dass der Programmierer nur zufällig Dinge darauf wirft, um zu sehen, was steckt. Aber mit der Erfahrung kann dies ein ziemlich gut definierter Prozess sein. Wenn Sie an dieser Stelle sehr logisch denken, ist es oft möglich, mögliche Sätze von Pfaden zu definieren, die zu dem gegebenen Zustand führten. Ich weiß, dass wir uns im Zustand S5 befinden. Damit dies geschehen konnte, musste S4a oder S4b auftreten und möglicherweise S3 vor S4a usw. Oftmals kann es mehrere Elemente geben, die zu einem bestimmten Zustand führen könnten. Manchmal kann es hilfreich sein, ein einfaches Ablauf- oder Zustandsdiagramm oder eine Reihe von zeitbezogenen Schritten auf ein Notizbuch zu schreiben. Die tatsächlichen Abläufe variieren in Abhängigkeit von der jeweiligen Situation erheblich, aber ernsthafte Überlegungen (und eine erneute Prüfung in den vorherigen Schritten) zu diesem Zeitpunkt liefern häufig eine oder mehrere plausible Antworten. Beachten Sie auch, dass ein äußerst wichtiger Teil dieses Schritts darin besteht, Dinge zu beseitigen, die unmöglich sind. Das Entfernen des Unmöglichen kann dazu beitragen, den Lösungsraum zu verkleinern (denken Sie daran, was Sherlock Holmes über die Überreste gesagt hat, nachdem Sie das Unmögliche beseitigt haben). Beachten Sie auch, dass ein äußerst wichtiger Teil dieses Schritts darin besteht, Dinge zu beseitigen, die unmöglich sind. Das Entfernen des Unmöglichen kann dazu beitragen, den Lösungsraum zu verkleinern (denken Sie daran, was Sherlock Holmes über die Überreste gesagt hat, nachdem Sie das Unmögliche beseitigt haben). Beachten Sie auch, dass ein äußerst wichtiger Teil dieses Schritts darin besteht, Dinge zu beseitigen, die unmöglich sind. Das Entfernen des Unmöglichen kann dazu beitragen, den Lösungsraum zu verkleinern (denken Sie daran, was Sherlock Holmes über die Überreste gesagt hat, nachdem Sie das Unmögliche beseitigt haben).
Experiment : Versuchen Sie in dieser Phase, das Problem auf der Grundlage der im vorherigen Schritt abgeleiteten Hypothesen zu reproduzieren. Wenn Sie im vorherigen Schritt ernsthaft darüber nachgedacht haben, sollte dies sehr einfach sein. Manchmal "betrüge" ich und ändere die Codebasis, um einen gegebenen Test zu unterstützen. Ich habe zum Beispiel kürzlich einen Sturz untersucht, von dem ich schlussfolgerte, dass er von einem Rennzustand herrührt. Um dies zu verifizieren, setze ich einfach einen Sleep (500) zwischen ein paar Codezeilen, damit ein anderer Thread zur "richtigen" Zeit seine schlechten Sachen erledigen kann. Ich weiß nicht, ob dies in der "echten" Wissenschaft erlaubt ist, aber es ist in Code, den Sie besitzen, durchaus vernünftig.
Wenn es Ihnen gelingt, es zu reproduzieren, sind Sie wahrscheinlich fast fertig (alles, was noch übrig ist, ist der einfache Schritt, es zu reparieren ... aber das ist für einen anderen Tag). Stellen Sie sicher, dass der neue Test in das Regressionstestsystem eingegeben wird. Und ich sollte darauf hinweisen, dass ich diese frühere Aussage darüber beabsichtigt habe, wie man es einfach macht, humorvoll zu sein. Das Finden und Implementieren einer Lösung kann umfangreiche Arbeiten erfordern. Ich bin der Meinung, dass das Beheben eines Fehlers nicht Teil des Debugging-Prozesses ist, sondern vielmehr eine Weiterentwicklung. Und wenn das Update überhaupt beteiligt ist, sollte es einige Design- und Überprüfungsarbeiten erfordern.
quelle
Versuchen Sie, den Testfall zu reduzieren. Wenn es klein genug ist, ist es normalerweise einfacher, den entsprechenden Code zu finden, der das Problem verursacht.
Es ist wahrscheinlich, dass ein neuer Check-in das Problem verursacht und der vorherige tägliche Build in Ordnung war. In diesem Fall sollte Ihnen Ihr Änderungsprotokoll aus der Quellcodeverwaltung bei der Entscheidung helfen, wen Sie fangen möchten.
Wenn Sie mit C / C ++ arbeiten, sollten Sie erwägen, valgrind oder purify auszuführen, um speicherbezogene Probleme zu isolieren.
quelle
Der schwierigste Teil des Debuggens besteht darin, das Problem zu isolieren, insbesondere, wenn das Problem unter mehreren Ebenen vergraben ist. Am College habe ich Musikaufnahmen studiert und seltsamerweise gab es eine Studio-Elektronik-Klasse, die sich hier direkt bewirbt. Ich werde das Debuggen einer Studioumgebung als Beispiel für den systematischen Debugging-Prozess verwenden.
Das Debuggen von Code ist wirklich nicht so unterschiedlich. Das Debuggen ist viel einfacher, wenn der Code eine Ausnahme auslöst. Sie können von der Stapelverfolgung dieser Ausnahme aus rückwärts verfolgen und Haltepunkte an Schlüsselpositionen festlegen. Normalerweise direkt nach dem Festlegen einer Variablen oder in der Zeile, die die Methode aufruft, die die Ausnahme auslöst. Möglicherweise stimmen einer oder mehrere der Werte nicht. Wenn es nicht richtig ist (eine Null, wenn es nicht sein sollte, oder der Wert außerhalb des Bereichs liegt), müssen Sie herausfinden, warum es nicht richtig ist. Die Unterbrechungspunkte in einer IDE entsprechen elektronischen Testpunkten (die für die Prüfung des Stromkreises durch eine Messsonde ausgelegt sind).
Wenn ich erst einmal herausgefunden habe, wo mein eigentliches Problem liegt, schreibe ich einige Komponententests, um dies in Zukunft zu überprüfen.
quelle
Angesichts der üblen Wanzen, die ich am späten Nachmittag nicht ausfindig machen kann, ist es meine effektivste Strategie, aufzustehen und ein paar Minuten wegzulaufen. In der Regel fließen bereits nach 30 Sekunden neue Ideen zu möglichen Fehlerquellen ein.
quelle
Für einen praktischeren Ansatz:
Wenn der Fehler mit einer nicht behandelten Ausnahme zusammenhängt, sehen Sie sich den Stack-Trace an. NULL-Verweise, Index außerhalb der Grenzen usw. und Ihre eigenen definierten Ausnahmen sind die häufigsten. Sie können diesen Fehler einem Junior-Entwickler zuweisen, es ist wahrscheinlich einfach und eine gute Lernerfahrung.
Wenn dies nicht auf allen Maschinen der Fall ist, liegt wahrscheinlich eine Art Race Condition / Threading-Problem vor. Es macht riesigen Spaß, diese aufzuspüren und Ihren gelangweilten Senior-Programmierer darauf abzustellen. Viel Protokollierung, gute Kenntnisse und gute Werkzeuge erledigen dies.
Eine weitere große Klasse von Fehlern ist, wenn das Testteam oder die Kunden ein bestimmtes Verhalten nicht mögen. Sie mögen es beispielsweise nicht, dass Sie Benutzer-IDs anzeigen oder dass Sie bei der Suche keine automatische Vervollständigung erhalten. Dies sind echte Fehler, die ein besseres Produktmanagement und Entwickler mit einer breiteren Sichtweise in Betracht ziehen. Es sollte relativ kurze Zeit dauern, bis ein Entwickler dieses Problem behoben hat, wenn er das System unter Berücksichtigung der Erweiterung erstellt.
80% aller anderen Fehler werden behoben, indem ein gutes Protokollierungssystem vorhanden ist und genügend Informationen gesammelt werden, um sie zu beheben. Verwenden Sie die integrierte Ablaufverfolgung mit mehreren Ebenen komplexer Protokollierungssysteme wie Log4Net / Log4J
Performance-Fehler sind eine eigene Kategorie. Die Regel lautet hier: "Erst messen, später beheben!" später nur 3-4% weniger Reaktionszeit.
quelle
Ich habe zwei Ansätze:
Divide and Conquer
Paradigma folgen .Diese Ansätze haben mir die meiste Zeit geholfen.
quelle