Wenn Sie in C, Objective-C oder C ++ codieren, können Sie den statischen Analysator von CLang verwenden , um Ihre Quelle zu kritisieren, ohne sie tatsächlich auszuführen .
Es sind einige Tools zum Debuggen des Speichers verfügbar: ValGrind, Guard Malloc unter Mac OS X, Electric Fence unter * NIX.
Einige Entwicklungsumgebungen bieten die Möglichkeit, einen Debugging-Speicherzuweiser zu verwenden, der beispielsweise neu zugewiesene Seiten und neu freigegebene Seiten mit Müll füllt, die Freigabe nicht zugewiesener Zeiger erkennt und vor und nach jedem Heap-Block einige Daten schreibt, wobei der Debugger aktiv ist wird aufgerufen, wenn sich das bekannte Muster dieser Daten ändert.
Ein Typ von Slashdot sagte, er habe viel Wert darauf gelegt, in einem Debugger immer neue Quellen zu erschließen. "Das war's", sagte er. Ich folge nicht immer seinem Rat, aber wenn ich ihn habe, war er mir sehr hilfreich. Selbst wenn Sie keinen Testfall haben, der einen ungewöhnlichen Codepfad stimuliert, können Sie eine Variable in Ihrem Debugger so verändern, dass sie solche Pfade verwendet, indem Sie beispielsweise etwas Speicher zuweisen und dann mit dem Debugger den neuen Zeiger auf NULL anstelle von setzen Speicheradresse, dann schrittweise durch den Allokationsfehler-Handler.
Verwenden Sie Assertions - das assert () -Makro in C, C ++ und Objective-C. Wenn Ihre Sprache keine Assert-Funktion bietet, schreiben Sie selbst eine.
Verwenden Sie Asserts großzügig und lassen Sie sie dann in Ihrem Code. Ich nenne assert () "Der Test, der weiter testet". Ich benutze sie am häufigsten, um die Voraussetzungen am Einstiegspunkt der meisten meiner Funktionen zu überprüfen. Das ist ein Teil von "Programming by Contract", das in die Programmiersprache Eiffel integriert ist. Der andere Teil sind Nachbedingungen, dh die Verwendung von assert () an Funktionsrückgabepunkten, aber ich stelle fest, dass ich nicht so viele Meilen davon bekomme wie die Vorbedingungen.
Sie können assert auch verwenden, um Klasseninvarianten zu überprüfen. Während keine Klasse unbedingt eine Invariante haben muss, haben die vernünftigsten entworfenen Klassen diese. Eine Klasseninvariante ist eine Bedingung, die immer wahr ist, außer innerhalb von Elementfunktionen, die Ihr Objekt vorübergehend in einen inkonsistenten Zustand versetzen können. Solche Funktionen müssen immer die Konsistenz wiederherstellen, bevor sie zurückkehren.
Auf diese Weise kann jede Mitgliedsfunktion die Invariante beim Ein- und Ausstieg überprüfen und die Klasse kann eine Funktion namens CheckInvariant definieren, die jeder andere Code jederzeit aufrufen kann.
Verwenden Sie ein Tool zur Codeabdeckung, um zu überprüfen, welche Zeilen Ihrer Quelle tatsächlich getestet werden, und entwerfen Sie dann Tests, die die nicht getesteten Zeilen stimulieren. Zum Beispiel könnten Sie Handler für wenig Arbeitsspeicher überprüfen, indem Sie Ihre App in einer VM ausführen, die mit wenig physischem Arbeitsspeicher und entweder keiner oder einer sehr kleinen Auslagerungsdatei konfiguriert ist.
(Aus irgendeinem Grund war ich nie mit BeOS vertraut, obwohl das BeOS ohne Auslagerungsdatei ausgeführt werden konnte, war es auf diese Weise äußerst instabil. Dominic Giampaolo, der das BFS-Dateisystem schrieb, forderte mich auf, das BeOS niemals ohne Auslagerungsdatei auszuführen. Ich nicht sehen, warum das wichtig sein sollte, aber es muss eine Art Implementierungsartefakt gewesen sein.)
Sie sollten auch die Antwort Ihres Codes auf E / A-Fehler testen. Versuchen Sie, alle Ihre Dateien auf einer Netzwerkfreigabe zu speichern, und trennen Sie dann das Netzwerkkabel, während Ihre App stark ausgelastet ist. Trennen Sie in ähnlicher Weise das Kabel oder schalten Sie das WLAN aus, wenn Sie über ein Netzwerk kommunizieren.
Besonders ärgerlich finde ich Websites, die keinen robusten Javascript-Code haben. Facebooks Seiten laden Dutzende kleiner Javascript-Dateien, aber wenn eine davon nicht heruntergeladen werden kann, bricht die ganze Seite. Es muss nur eine Möglichkeit geben, um eine Fehlertoleranz zu gewährleisten, beispielsweise durch einen erneuten Download, oder um einen angemessenen Fallback bereitzustellen, wenn einige Ihrer Skripte nicht heruntergeladen wurden.
Versuchen Sie, Ihre App mit dem Debugger oder mit "kill -9" auf * NIX zu beenden, während gerade eine große, wichtige Datei geschrieben wird. Wenn Ihre App über eine gute Architektur verfügt, wird die gesamte Datei geschrieben oder gar nicht, oder wenn sie nur teilweise geschrieben wird, wird das, was geschrieben wird, nicht beschädigt, und die gespeicherten Daten können vollständig verwendet werden die App beim erneuten Lesen der Datei.
Datenbanken haben immer fehlertolerante Festplatten-E / A, aber kaum eine andere Art von App. Aufgezeichnete Dateisysteme verhindern zwar eine Beschädigung des Dateisystems bei Stromausfall oder Abstürzen, verhindern jedoch keinesfalls die Beschädigung oder den Verlust von Endbenutzerdaten. Dies liegt in der Verantwortung der Benutzeranwendungen, aber kaum eine andere als Datenbanken implementieren Fehlertoleranz.