Wie defensiv sollten wir sein?

11

Wir haben Pex über einen Code ausgeführt und es wurden einige gute Dinge gezeigt (auch schlechte Dinge, aber sie wurden gezeigt, bevor es zur Produktion kommt!).

Eines der schönen Dinge an Pex ist jedoch, dass es nicht unbedingt aufhört, nach Problemen zu suchen.

Ein Bereich, den wir gefunden haben, ist, dass wir beim Übergeben einer Zeichenfolge nicht nach leeren Zeichenfolgen gesucht haben.

Also haben wir uns geändert:

if (inputString == null)

zu

if (string.IsNullOrEmpty(inputString)) // ***

Damit waren die anfänglichen Probleme behoben. Aber dann, als wir Pex wieder laufen ließen, entschied es, dass:

inputString = "\0";

verursachte Probleme. Und dann

inputString = "\u0001";

Wir haben entschieden, dass Standardeinstellungen verwendet werden können, wenn wir auf etwas stoßen, // ***und dass wir uns freuen, die Ausnahme zu sehen, die durch andere ungerade Eingaben verursacht wird (und damit umzugehen).

Ist das genug?

Peter K.
quelle
Haben Sie überprüft, ob Sie einige der Warnungen deaktivieren können? Ich weiß, dass JTest das auch tun würde, aber es war auch eine Option, einige seiner Empfehlungen auszuschalten. Es dauerte einige Zeit, bis die Einstellungen angepasst wurden, um ein Code-Testprofil zu erhalten, das uns gefiel.
FrustratedWithFormsDesigner
@Frustrated: Ja, es gibt sicherlich Verbesserungen an dem Profil, das wir machen können und machen. Pex ist übrigens ein großartiges Werkzeug. Die Ergebnisse zeigten nur die Frage.
Peter K.
Ich habe keine Antwort für Sie, aber ich wollte mich für diesen Link zu dieser Pex-Sache bedanken. Es sieht ziemlich ordentlich aus, wenn es das ist, was ich denke, und wird automatisch (?) Komponententests für vorhandenen Code erstellen. Der Code, an dem ich arbeite, ist riesig und enthält keine Tests und einen sehr eng gekoppelten Code, sodass es unmöglich ist, irgendetwas umzugestalten.
Wayne Molina
@ WayneM: Ja, es ist ziemlich gut, obwohl ich ein paar Beispiele durchgehen musste, um zu verstehen, was es tat. Für Legacy-Code ist es großartig. Es ist noch besser für neuen Code!
Peter K.

Antworten:

9

Drei Fragen sollen Ihnen dabei helfen, festzustellen, wie defensiv Ihre Codierung sein soll.

Erstens - Was sind die Konsequenzen eines schlechten Inputs? Wenn es sich um eine Fehlermeldung auf einem PC Ihres Entwicklers handelt, ist es möglicherweise nicht so wichtig, defensiv zu sein. Könnte dies zu finanziellen Störungen bei Kunden und zu Störungen der IE-Buchhaltungsinformationen führen? Ist es ein Echtzeitsystem, in dem Leben gefährdet sind? Im Lebens- / Todesszenario sollte es wahrscheinlich mehr Validierungs- und Fehlerbehandlungscode als den tatsächlichen Funktionscode geben.

Zweitens, wie viele Personen werden diese Funktion oder diesen Code wiederverwenden? Nur du? Ihre Abteilung? Ihre Firma? Ihre Kunden? Je weiter der Code verwendet wird, desto defensiver ist er.

Drittens - woher kommt die Eingabe, die ich validiere? Wenn es vom Benutzer oder von einer öffentlichen Website eingegeben wird, wäre ich super defensiv. Wenn die Eingabe immer von Ihrem Code stammt, seien Sie etwas defensiv, aber verbringen Sie keine übermäßige Zeit damit, Schecks einzulegen.

Es wird immer möglich sein, mehr Fehlerprüfungen und -validierungen in einem System hinzuzufügen. Der Punkt ist, dass die Kosten für das Schreiben und Verwalten dieses Codes die Kosten der Probleme überwiegen, die durch Fehler im Code verursacht werden.

Bork Blatt
quelle
6

Benutzer sind böse, und alles, was sie eingeben, sollte mit äußerster Sorgfalt überprüft werden.

Alles, was ohne Benutzereingabe oder aus vorbereinigten Daten generiert wird, sollte nicht auf derselben Ebene überprüft werden müssen. Das Problem hierbei ist, wenn Sie diese Methoden vergessen und für fehlerhafte Daten verwenden, weil Sie vergessen haben, dass der Code nicht gehärtet wurde.

Das einzige, was Sie immer überprüfen sollten, ist alles, was einen Überlauf oder einen Absturz verursachen kann. Es spielt keine Rolle, wie tief diese Methode vergraben ist und wie sicher Sie sind, dass dieser Zustand niemals auftreten kann. Sie müssen es trotzdem programmieren, nur um Murphy zu beruhigen.

Satanicpuppy
quelle
2

Ich wäre so defensiv wie du sein musst. Ein bisschen mehrdeutig, denke ich, aber ich werde versuchen zu erklären.

Wenn Sie eine Methode korrigieren und über Eingabeparameter verfügen, müssen Sie entscheiden, wie diese Parameter aussehen sollen. In Situationen und Orten innerhalb einer Anwendung ist dies unterschiedlich. Wenn beispielsweise eine Methode oder ein Code Daten von einer Benutzereingabe akzeptiert, möchten Sie die gesamte Codebasis abdecken und alle Eingaben entsprechend behandeln, sei es über eine Fehlermeldung oder eine nette Art der Anzeige nicht akzeptabler Daten.

Wenn die Methode eine exponierte API ist, ebenso. Sie können nicht steuern, was hereinkommt, daher sollten Sie damit rechnen, alle Aspekte abzudecken und entsprechend zu programmieren.

Für Methoden, die innerhalb der Kern-Engine Ihres Projekts erstellt werden, müssen Sie hier eine Entscheidung treffen. Nehme ich an, dass die eingehenden Daten vor dem Eintreffen vorab überprüft und validiert wurden, oder sollte ich die erforderlichen Überprüfungen durchführen? Ich denke, dies hängt von der konzeptionellen Ebene der Methode ab und davon, ob dies ein akzeptabler Ort ist, um dies zu überprüfen. Dinge, die ich in Betracht ziehen könnte, sind:

1) Ist dies der einzige Ort, an dem ich diese Prüfung durchführen muss? Muss diese Variable an vielen verschiedenen Stellen auf diese Bedingung überprüft werden? Wenn ja, kann ich die Prüfung einmal weiter oben in der Kette durchführen und anschließend die Gültigkeit übernehmen

2) Wird erwartet, dass andere Komponenten des Systems mit den von mir geschriebenen Methoden und Schnittstellen funktionieren? Wenn ja, können Sie durch Debug-Assert-Anweisungen, Debugging-Ausnahmen, Methodenkommentare und allgemeine Systemarchitektur das gewünschte Ergebnis steuern oder müssen die Daten überprüft werden.

3) Was sind die Ergebnisse eines Fehlers an dieser Stelle im Code? Wird es das Ganze zum Scheitern bringen? Wird ein Fehler an anderer Stelle abgefangen und wird dieser Fehler zumindest abgefangen?

4) Ist es sinnvoll, hier einen Scheck zu setzen? Manchmal hilft es, eine Überprüfung möglicher beschädigter Daten durchzuführen, obwohl es hilfreich ist, das Problem zu diesem Zeitpunkt zu lösen und keine Fehler zu beheben. Zu diesem Zeitpunkt könnten Sie Stunden damit verbringen, ein anderes Problem aufzuspüren, nur um das tatsächliche Problem zu finden. Dies lag an einer gültigen Überprüfung der Daten in der Ereigniskette, die an das vom Benutzer / Entwickler gemeldete Problem weitergegeben wurde.

Im Allgemeinen bin ich ein defensiver Programmierer, aber ich glaube auch, dass Sie mit gründlichen TDD- und geeigneten Unit-Tests die Code-Checks auf den erforderlichen Ebenen einfügen können und sicher sein können, dass es so funktioniert, wie es sollte, sobald es zu niedrigeren Abschnitten gelangt .

dreza
quelle
1

Ich habe Wochen zuvor an Fehlern gearbeitet, die mit 5 Minuten zusätzlicher Arbeit wie dieser im Vorfeld hätten entdeckt werden können. In meinen Augen lohnt sich diese Vorarbeit immer. Sie werden den Fehler irgendwann beheben. Die Frage ist nur, wie lange Sie brauchen werden.

Eine Sache, die diese Art von Analysewerkzeugen häufig aufdeckt, sind Dinge, die nicht unbedingt Fehler sind, sondern schlechte Programmiergewohnheiten, die das Auftreten von Fehlern wahrscheinlicher machen. Eine solche häufige Gewohnheit ist die variable Initialisierung. Manchmal ist eine leere Zeichenfolge ein vollkommen gültiger Wert für eine Variable. In diesem Fall möchten Sie Ihr Tool so konfigurieren, dass dies in dieser bestimmten Instanz nicht als Fehler angesehen wird. Doch oft eine leere Zeichenfolge ist nicht ein gültiger Wert für eine Variable, aber die Leute es trotzdem setzen, weil der Compiler beschwert sich, wenn es nicht ist etwas da drin, oder Ihre Sprache initialisiert automatisch auf die leere Zeichenfolge , ob das gültig ist oder nicht.

Dies frustriert die Leute, weil es wie ein Haken 22 ohne gültige Lösung erscheint, aber die Lösung besteht darin, Ihren Code umzugestalten, sodass die Variable erst initialisiert werden muss, wenn ein gültiger Wert zum Einfügen vorhanden ist. Das erfordert einige zusätzliche Überlegungen, macht Ihren Code jedoch viel robuster und ist auf lange Sicht einfacher zu schreiben und zu warten.

Karl Bielefeldt
quelle