5 Stimmen

Gemeinsame Bibliotheksfunktionen verbessern oder aufgeben?

Stellen Sie sich vor, ich habe eine Funktion, die einen Fehler enthält:

Pseudocode:

void Foo(LPVOID o)
{ 
   //implementation details omitted
}

Das Problem ist, dass der Benutzer die null :

Object bar = null;

...

Foo(bar);

Dann wird die Funktion könnte wegen einer Zugriffsverletzung abstürzen; es kann aber auch passieren, dass sie gut funktioniert. Der Fehler besteht darin, dass die Funktion debe auf den ungültigen Fall der Übergabe von null aber es hat einfach nicht geklappt. Es war nie ein Thema, weil man den Entwicklern zutraute, dass sie wussten, was sie taten.

Wenn ich nun die Funktion ändere in:

Pseudocode:

void Foo(LPVOID o)
{
   if (o == null) throw new EArgumentNullException("o");

   //implementation details omitted
}

dann werden Leute, die die Funktion gerne benutzt haben und zufällig keine Zugriffsverletzung erhalten haben, jetzt plötzlich eine EArgumentNullException .

Soll ich weiterhin zulassen, dass Leute die Funktion missbräuchlich verwenden, und eine neue Version der Funktion erstellen? Oder verbessere ich die Funktion so, dass sie das enthält, was sie ursprünglich hätte enthalten sollen?


Und nun das moralische Dilemma. Wollen Sie immer neue Plausibilitätsprüfungen, Sicherheitsprüfungen und Assertions zu bestehendem Code hinzufügen? Oder rufen Sie die alte Funktion auf, die aufgegeben wurde, und haben eine neue?


Nehmen wir einen Fehler, der so häufig auftritt, dass Microsoft ihn für Entwickler beheben musste:

 MessageBox(GetDesktopWindow, ...);

Nie und nimmer, immer ein Fenstermodell auf dem Desktop erstellen möchten. Sie werden das System sperren. Lassen Sie die Entwickler weiterhin den Computer des Benutzers sperren? Oder ändern Sie die Funktion in:

 MessageBox(HWND hWndParent, ...)
 {
    if (hWndParent == GetDesktopWindow)
       throw new Exception("hWndParent cannot be the desktop window. Use NULL instead.");

    ...
 }

In Wirklichkeit hat Microsoft den Fenstermanager so geändert, dass der fehlerhafte Parameter automatisch korrigiert wird:

 MessageBox(HWND hWndParent, ...)
 {
    if (hWndParent == GetDesktopWindow)
       hWndParent = 0;

    ...
 }

In meinem erfundenen Beispiel gibt es keine Möglichkeit, die Funktion zu patchen - wenn mir kein Objekt gegeben wurde, kann ich nicht tun, was ich an ihm tun muss.

Besteht die Gefahr, dass bestehender Code durch Hinzufügen einer Parametervalidierung beschädigt wird? Lassen Sie zu, dass der bestehende Code weiterhin falsch ist und falsche Ergebnisse liefert?

2voto

Christopher Oezbek Punkte 20239

Das Problem ist, dass Sie nicht nur einen Fehler beheben, sondern auch die semantische Signatur der Methode ändern, indem Sie einen Fehlerfall einführen.

Aus Sicht der Softwaretechnik würde ich dafür plädieren, dass man versucht, Methoden so gut wie möglich zu spezifizieren (z. B. mit Vor- und Nachbedingungen), aber wenn die Methode erst einmal da ist, sind Änderungen der Spezifikation ein No-Go (oder man müsste zumindest alle Vorkommen der Methode überprüfen), und eine neue Methode wäre besser.

1voto

Morfildur Punkte 12596

Ich würde die alte Funktion beibehalten und sie einfach eine Warnung erzeugen lassen, die einen über jede (möglicherweise) falsche Verwendung informiert, und dann würde ich den Entwickler, der sie falsch verwendet hat, einfach treten, bis er sie richtig verwendet.

Man kann nicht alles auffangen. Was wäre, wenn jemand schreiben würde: "MakeLocation("Ian Boyd", "is stupid");"? Würden Sie eine neue Funktion erstellen oder die Funktion ändern, um das abzufangen? Nein, Sie würden den Entwickler feuern (oder ihn zumindest bestrafen).

Dies erfordert natürlich, dass Sie Folgendes dokumentieren was die Ihre Funktion als Eingabe benötigt.

0voto

David Waters Punkte 11759

Hier sind automatisierte Tests [Unit-Tests, Integrationstests, automatisierte Funktionstests] von großem Vorteil, da sie Ihnen die Möglichkeit geben, bestehenden Code mit Sicherheit zu ändern.

Wenn Sie solche Änderungen vornehmen, würde ich vorschlagen, alle Verwendungen aufzuspüren und sicherzustellen, dass sie sich so verhalten, wie Sie es für richtig halten.

Ich selbst würde Fehlerbehebungen an bestehenden Funktionen vornehmen, anstatt sie in 99 % der Fälle zu duplizieren. Wenn sich das Verhalten stark ändert und es viele Aufrufe dieser Funktion gibt, müssen Sie sich Ihrer Änderung sehr sicher sein.

Nehmen Sie also Ihre Änderungen vor, führen Sie Ihre Unit-Tests und dann Ihre automatisierten Funktionstests durch. Beheben Sie etwaige Fehler und Sie haben gewonnen!

0voto

Wenn Ihr Code einen Fehler enthält, sollten Sie tun, was Sie normalerweise tun, wenn ein Fehler gemeldet wird. Ein Teil davon ist die Abschätzung der Auswirkungen der Behebung und der Nichtbehebung des Fehlers. Manchmal ist es das Richtige, einen Fehler nicht zu beheben, weil das Verhalten, das er zeigt, akzeptiert wurde. Manchmal halten die Kosten für die Behebung, oder die Unannehmlichkeiten, die mit der Veröffentlichung eines Fixes außerhalb des normalen Veröffentlichungszyklus verbunden sind, Sie für eine Weile davon ab, einen behobenen Fehler zu veröffentlichen. Dies ist kein moralisches Dilemma, sondern eine wirtschaftliche Frage von Kosten und Nutzen. Wenn Sie sich an dem Gedanken stören, bekannte Fehler in Ihrem veröffentlichten Code zu haben, veröffentlichen Sie einen bekannte Fehler Liste.

Eine Möglichkeit, die keiner der anderen Teilnehmer vorgeschlagen zu haben scheint, besteht darin, die fehlerhafte Funktion in eine andere Funktion zu verpacken, die das von Ihnen gewünschte neue Verhalten erzwingt. In einer Welt, in der Funktionen viele Zeilen lang sein können, ist es manchmal weniger wahrscheinlich, neue Fehler einzuführen, wenn man einen zu 99 % korrekten Code beibehält und die Änderung ohne Änderung des bestehenden Codes vornimmt. Natürlich ist dies nicht immer möglich

0voto

Zwei Möglichkeiten:

  • Geben Sie der Version zur Fehlerprüfung einen neuen Namen und verwerfen Sie die alte Version (eine Version später soll sie Warnungen ausgeben (Kompilierzeit, wenn möglich, Laufzeit, wenn nötig), zwei Versionen später soll sie entfernt werden).
  • [nicht immer möglich] Platzieren Sie die neu eingeführte Fehlerprüfung so, dass sie nur ausgelöst wird, wenn die unveränderte Version würde zum Absturz oder zu undefiniertem Verhalten führen. (Damit Benutzer, die in ihrem Code vorsichtig waren, keine bösen Überraschungen erleben).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X