Ist es möglich, für umfangreiche Software den absoluten Null-Fehlerstatus zu erreichen?

71

Ich spreche zum Beispiel von 20 bis 30 Millionen Codezeilen, Software in der Größenordnung und Komplexität von Autodesk Maya.

Wenn Sie die Entwicklung so lange einfrieren, wie es sein muss, können Sie dann tatsächlich alle Fehler beheben, bis es einfach keinen einzigen Fehler mehr gibt, wenn dies durch Computer überprüft werden könnte? Was sind die Argumente für und gegen die Existenz eines fehlerfreien Systems?

Weil es eine Vorstellung gibt, dass jede Korrektur, die Sie vornehmen, mehr Fehler verursacht, aber ich denke nicht, dass das wahr ist.

Mit Fehlern meine ich von den einfachsten Tippfehlern in der Benutzeroberfläche bis hin zu schwerwiegenderen vorbeugenden Fehlern, für die es keine Problemumgehung gibt. Beispielsweise berechnet eine bestimmte Skriptfunktion Normalen falsch. Auch wenn es Workarounds gibt, muss das Problem noch behoben werden. Sie können also sagen, dass Sie diese bestimmte Sache manuell ausführen können, anstatt die bereitgestellte Funktion zu verwenden, diese Funktion muss jedoch noch behoben werden.

Joan Venge
quelle
11
"Wurde von ein paar Top-Programmierern erzählt" - sie klingen für mich nicht nach Top-Programmierern. Sie klingen wie Top-Hacker. Eine der PRIMÄREN VERANTWORTLICHKEITEN eines Programmierers besteht darin, zu verstehen, was sein Code tut und wie er sich auf das gesamte System auswirkt. Aus diesem Grund gibt es TDD, Entwurfsmuster usw. Wenn dies nicht möglich ist, handelt es sich bei dem System um Junk - der Entwicklungsprozess verlief chaotisch, willkürlich, undiszipliniert und unwissenschaftlich.
Vector
51
Wenn Sie noch nicht wissen, dass ein Fehler vorliegt, handelt es sich dann noch um einen Fehler?
Blrfl
5
@Blrf: Was noch wichtiger ist: Wenn der Endbenutzer keinen Fehler kennt, gibt es ihn dann?
Mattnz
40
„Es gibt zwei Möglichkeiten, ein Software-Design zu erstellen. Eine Möglichkeit besteht darin, es so einfach zu gestalten, dass es offensichtlich keine Mängel gibt. Und der andere Weg ist, es so kompliziert zu machen, dass es keine offensichtlichen Mängel gibt. ”- CAR Hoare
Andrew Lewis
5
Es ist so, aber viele Menschen wollen nicht, dass ihre Grundüberzeugungen in Frage gestellt werden.
Joan Venge

Antworten:

92

Wie Mikey sagte, ist das Schreiben von fehlerfreiem Code nicht das Ziel. Wenn Sie das anstreben, dann habe ich eine sehr schlechte Nachricht für Sie.

Der entscheidende Punkt ist, dass Sie die Komplexität von Software bei weitem unterschätzen.

Das Wichtigste zuerst - Sie ignorieren das Gesamtbild der Programmausführung. Es läuft nicht isoliert auf einem perfekten System. Selbst das grundlegendste "Hello World" -Programm läuft auf einem Betriebssystem, und daher ist auch das einfachste Programm anfällig für Fehler, die im Betriebssystem auftreten können.

Die Existenz von Bibliotheken macht dies komplexer. Während Betriebssysteme in der Regel ziemlich stabil sind, sind Bibliotheken in Bezug auf die Stabilität eine gemischte Sache. Einige sind wundervoll. Andere ... nicht so sehr ... Wenn Sie möchten, dass Ihr Code zu 100% fehlerfrei ist, müssen Sie auch sicherstellen, dass jede Bibliothek, auf die Sie stoßen, vollständig fehlerfrei ist Möglicherweise haben Sie den Quellcode nicht.

Dann gibt es Themen, über die man nachdenken muss. Die meisten großen Programme verwenden überall Threads. Wir versuchen vorsichtig zu sein und Threads so zu schreiben, dass keine Race-Bedingungen und Deadlocks auftreten, aber es ist einfach nicht möglich, jede mögliche Codekombination zu testen. Um dies effektiv zu testen, müssten Sie jede mögliche Reihenfolge von Befehlen prüfen, die durch die CPU gehen. Ich habe noch nicht nachgerechnet, aber ich vermute, dass es einfacher wäre, alle möglichen Schachpartien aufzulisten.

Die Dinge gehen von schwer bis unmöglich, wenn wir uns die Maschine selbst ansehen. CPUs sind nicht perfekt. RAM ist nicht perfekt. Festplatten sind nicht perfekt. Keine der Komponenten in einer Maschine ist perfekt - sie sind "gut genug". Selbst ein perfektes Programm scheitert irgendwann an einem Schluckauf der Maschine. Sie können nichts dagegen tun.

Fazit: Können Sie "Fehlerfreie Software" schreiben?

NEIN

Wer dir etwas anderes sagt, ist ahnungslos.

Versuchen Sie einfach, eine Software zu schreiben, die einfach zu verstehen und zu warten ist. Sobald Sie das getan haben, können Sie es einen Tag nennen.


EDIT: Einige Leute kommentierten einen ausgezeichneten Punkt, den ich völlig übersehen hatte: den Compiler.

Wenn Sie nicht in Assembly schreiben, ist es durchaus möglich, dass der Compiler Ihren Code durcheinander bringt (auch wenn Sie nachweisen, dass Ihr Code "perfekt" ist).

Eine Liste der Fehler in GCC, einem der am häufigsten verwendeten Compiler: http://gcc.gnu.org/bugzilla/buglist.cgi?product=gcc&component=c%2B%2B&resolution=---

riwalk
quelle
8
Die Antwort lautet immer noch "Nein", denn es wird immer "Bugs" geben, bei denen etwas funktioniert - nur nicht so, wie es ein Kunde oder Produktbesitzer gerne hätte. Einige von uns nennen diese Feature-Requests oder Requests, um das Verhalten zu ändern oder Funktionen hinzuzufügen - aber für die Person, die jeden Tag von einem "Bug" gestört wird, ist das, was sie stört, ein Bug. (Das ist ein langer Weg zu sagen, dass einige Bugs im Auge des Betrachters sind.) BUG FREE CODE ist unmöglich. Streben Sie nach Code, der gut genug ist, um den beabsichtigten Zweck zu erfüllen.
quick_now
6
Ich gehe noch einen Schritt weiter: Code kann latente Fehler aufweisen. Beispielsweise kann Code vorhanden sein, der eine Eingabe nicht ordnungsgemäß überprüft. Wenn die Eingabe aus irgendeinem glücklichen Grund niemals außerhalb der Reichweite liegt, tritt der Fehler niemals auf. Dann wird eines Tages während Wartungsarbeiten oder Funktionsänderungen dieser Code von einer anderen Stelle aufgerufen, die ihn gelegentlich mit einem Wert außerhalb des gültigen Bereichs ausführt. Der Bug manifestiert sich jetzt - aber er war die ganze Zeit da. Sie können in all dem Grade des Wahnsinns haben - aber es ist immer noch unmöglich, jede Möglichkeit von Unrecht auszuschließen.
quick_now
11
@ JohnR.Strohm Ich bin mir nicht sicher, warum Sie glauben, dass das Programm "Nachrichtenflussmodulator", ein Programm mit 556 Codezeilen, etwas mit einer Frage zu einem theoretischen 20-Millionen-Zeilen-System zu tun hat. Außer vielleicht, um zu beweisen, dass es so schwierig es war, die Richtigkeit des winzigen Programms zu beweisen, wäre es astronomisch schwieriger, die Richtigkeit eines massiven Programms zu beweisen.
Eric King
9
Während die ursprüngliche Frage dies nicht tat, möchte ich darauf hinweisen, dass es einen riesigen Unterschied zwischen "theoretisch möglich" und "praktisch möglich" gibt. Während eine fehlerfreie Codebasis von 20 Millionen Zeilen theoretisch möglich ist, ist dies auf dem heutigen Markt mit ziemlicher Sicherheit eine praktische Unmöglichkeit. Wer weiß, was die Zukunft bringt.
Eric King
4
@ JohnR.Strohm Du solltest die Zeitung genauer lesen. Sie sagen sich selbst: It is important to note, however, that even all of these steps provide no guarantee of absolute security. It is tempting to believe that a formally specified and proved program should be absolutely correct, but there are several reasons why a proved program may not behave exactly as expected.- Das heißt, es kann nicht bewiesen werden, dass es fehlerfrei ist, sondern es ist weniger wahrscheinlich, dass es Fehler gibt. Eher wie TDD.
Izkata
27

Mathematisch ist es MÖGLICH , "fehlerfreie" Software von solcher Komplexität zu schreiben, abhängig davon, wie Sie "Fehler" definieren. Dies zu beweisen , KANN auch mathematisch möglich sein, indem ein Testsystem entworfen wird, das jede Codezeile auf jede mögliche Art und Weise ausübt - jeden möglichen Anwendungsfall. Aber ich bin mir nicht sicher - wenn Sie es mit einem System zu tun haben, das komplexe Berechnungen durchführt, könnten Sie auf ein "Unendlichkeitsproblem" stoßen ...

In der Praxis ist dies in einem System von der Größe und dem Umfang, von dem Sie sprechen, UNMÖGLICH . Es könnte 1000 Jahre dauern, ein solches "fehlerfreies" System zu schreiben, und das Schreiben eines Systems, um zu beweisen, dass es exponentiell länger dauert: Sie müssten sich jeden möglichen Anwendungsfall ausdenken und ein System schreiben, das jeden einzelnen testet Eins - und ich glaube nicht, dass es eine Möglichkeit gibt, festzustellen, ob Sie tatsächlich jeden Anwendungsfall in einem System der Größe und des Umfangs, von dem Sie sprechen, in einer angemessenen Zeitspanne behandelt haben.

IMO Ihre Frage ist ein bisschen fehlgeleitet: Unser Ziel als Entwickler ist es nicht, "fehlerfreie" Software zu schreiben. Unser Ziel ist es, benutzerfreundliche, flexible und einfach zu wartende Software zu schreiben .

Verwendbar: Das System erfüllt die grundlegenden Anforderungen, für die es konzipiert wurde. Es kann Bugs geben - aber sie werden in "Randfällen" - Ausreißer oder Ärger sein, keine Bugs, die die Grundlagen des Systems gefährden - robust.

Wartungsfähig: Bugs können einfach isoliert und behoben werden und erzeugen KEINE neuen Bugs.

Flexibel: Ihr System lässt sich leicht ändern und erweitern, ohne dass erhebliche Änderungen und Ausfallzeiten erforderlich sind. Die meisten Änderungen erfordern lediglich das Hinzufügen einer neuen Klasse oder eines neuen Moduls, die bzw. das zu Ihren bereits gut gestalteten Mustern und Frameworks passt.

Gute Designpraktiken, gute Kontrollpraktiken, gute Teamarbeit, gewissenhafte Entwickler - das ist die Formel für GUTE SOFTWARE . (nicht perfekt - aber gut )

Vektor
quelle
3
"Es KÖNNTE auch mathematisch möglich sein, indem ein Testsystem entworfen wird, das jede Codezeile auf jede mögliche Art und Weise ausübt - jeden möglichen Anwendungsfall.": Ein solches Programm gibt es im Allgemeinen nicht (und das kann bewiesen werden!). Ein allgemeiner Algorithmus zum Nachweis der Korrektheit existiert also nicht.
Giorgio
3
Korrektur: Fehlerfreie Software, KOMPLETT MIT FORMALEM MATHEMATISCHEN NACHWEIS DER RICHTIGKEIT, wurde erreicht. Es wurde 1982 gemacht. Google "Message Flow Modulator".
John R. Strohm
6
@ JohnR.Strohm: Stimmt nicht. Hier ist nur ein Zitat: Es gibt mehrere Artikel und Stellen, an denen ähnliche Bedenken angesprochen werden: „Eine häufig gestellte Frage lautet: Haben Sie den Prüfer überprüft?“ Diese metamathematische Frage wird möglicherweise überraschenderweise häufig von Ingenieuren gestellt, nicht nur von spitzen Köpfen Akademiker: Wenn eine Maschine jemals die Frage "Lügst du jemals?" beantwortet, ist die Antwort nicht informativer als wenn ein Mensch die Frage beantwortet.
Vector
1
Ich meinte, es gibt keinen allgemeinen Algorithmus, der für jedes Eingabeprogramm und jede Eingabespezifikation funktioniert. Sie können nur bestimmte Fälle behandeln (z. B. Ihr Beispiel).
Giorgio
1
@Giorgio - IMO ist das Befolgen guter Entwurfspraktiken viel wichtiger als sich selbst mit mathematischer Korrektheit zu befassen: Entwerfen Sie Ihren Code, um sicherzustellen, dass er gut integriert werden kann und mit dem kompatibel ist, was bereits vorhanden ist kommt ans Licht (was sie werden).
Vector
27

Laut diesem Artikel kam die On-Board - Software für das Space Shuttle ganz in der Nähe - die letzten drei Versionen des 420.000 Zeilenprogramm hatte nur einen Fehler je. Die Software wurde von einer Gruppe von 260 Männern und Frauen gepflegt. Eine große Anzahl dieser Personen waren Prüfer, deren einziger Zweck darin bestand, Fehler zu finden.

Die Aktualisierung der Software, damit das Shuttle mit Global Positioning Satellites navigieren kann, wirkte sich nur auf 1,5% des Programms oder 6.366 Codezeilen aus. Die Spezifikationen für diese eine Änderung umfassten 2.500 Seiten. Die Spezifikationen für das Gesamtprogramm füllten 30 Bände und umfassten 40.000 Seiten oder durchschnittlich zehn Codezeilen pro Seite der Spezifikation.

Das Budget war kein Problem - bei 35 Mio. USD pro Jahr konnten sie es sich leisten, die Dinge richtig zu machen.

Tcrosley
quelle
25
Jeweils ein erkannter Fehler. Wer weiß wie viele unerkannte Fehler? :)
Andres F.
8
Dieser "eine Fehler" war ein Sonderfall. Das Shuttle wurde ursprünglich für zwei Roboterarme entwickelt und die Software spezifiziert. Der "Fehler" war, dass immer noch Code zur Unterstützung des zweiten Arms vorhanden war.
John R. Strohm
4
+1 Lief ohne Fehler für 135 Missionen von 1981 bis 2011
MarkJ
5
@MarkJ: Wir würden wahrscheinlich nicht wissen, ob das Space Shuttle tatsächlich keine Fehler hatte. Jede Space-Shuttle-Mission wird ständig von Hunderten von Personen überwacht, und alle Fehler in der Codierung wären manuell korrigiert / überschrieben worden.
Lie Ryan
2
@LieRyan Das zeigt eine großartige Eigenschaft robuster Systeme: Wenn sie nicht katastrophal ausfallen und immer manuelle Anpassungen zulassen, können Sie stattdessen redundante Systeme (wie die im Kontrollzentrum) verwenden, um die Arbeit zu erledigen. Dies ist natürlich nur dann sinnvoll, wenn Sie über solche redundanten Systeme verfügen und tatsächlich auf Korrektheit und Konsistenz achten können. In einer typischen Geschäftsanwendung wird ein Absturz häufig einem inkonsistenten Zustand vorgezogen - es ist der Unterschied zwischen einem Ärger und dem Senden von Geld an den Falschen. Oder Geld empfangen, ohne dass es gesendet wird ...
Luaan
15

Im Grunde genommen nein, aber du solltest trotzdem dein Bestes geben. Ich werde erklären, warum (oder einfach zum Schluss kommen, wenn Sie nicht genug Geduld haben)

Betrachten Sie ein so einfaches Problem wie die Implementierung der binären Suche. Eine sehr beliebte Implementierung hatte einen Fehler , der rund zwei Jahrzehnte lang unentdeckt blieb. Wenn zwanzig Zeilen zwanzig Jahre brauchen, um fehlerfrei zu werden, können wir wirklich erwarten, dass ein riesiges Programm fehlerfrei ist?

Wie viele Bugs können wir überhaupt von einem riesigen Programm erwarten? Eine Zahl, die ich gefunden habe, war "10 Fehler pro 1000 Zeilen" (Code Complete, 2. Ausgabe, Seite 517 - nur ein Beispiel ohne Angabe von Daten). Dies führt zu etwa 200.000 bis 300.000 Fehlern in Ihrer Software. Glücklicherweise haben wir Möglichkeiten, die Qualität des Programms zu verbessern. Unit-Tests, Code-Reviews und gewöhnliche manuelle Tests reduzieren bekanntermaßen die Anzahl der Fehler. Trotzdem wird die Anzahl immer noch hoch sein.

Wenn wir 95% aller Fehler lösen könnten, wäre das unglaublich. Und doch hätten wir immer noch 10 000 bis 15 000 Fehler in der Software.

Glücklicherweise werden, da die Software weit verbreitet ist (und daher häufig getestet wird), Fehler gefunden. So werden wir nach und nach weniger Bugs bekommen. Weniger Fehler bedeuten jedoch auch, dass die verbleibenden schwerer zu finden sind. Erwarten Sie also keine lineare Kurve bei der Fehlerbehebung. Die letzten paar Bugs werden sehr schwierig zu finden sein und könnten sich für einige Jahre der Erkennung entziehen (vorausgesetzt, sie werden jemals gefunden).

Sie gehen fälschlicherweise davon aus, dass keine neuen Fehler auftreten werden, wenn sich die Software nicht ändert. Wenn die Software von Bibliotheken von Drittanbietern abhängt, können neue Versionen einige Funktionen beeinträchtigen und neue Fehler verursachen, obwohl der Code der Anwendung immer noch derselbe ist. Neue Betriebssysteme können auch eine Anwendung beschädigen, die zuvor einwandfrei funktioniert hat (siehe Windows Vista für ein beliebtes Beispiel). Berücksichtigen Sie auch Compiler-Fehler usw.

Es ist unklar, ob Code-Proof-Tools das Problem fehlerhafter Software wirklich lösen können. Es ist sicherlich nicht möglich, das Problem des Anhaltens für ein Programm zu lösen , aber es kann möglicherweise nachgewiesen werden, dass sich ein Programm wie angegeben verhält ... Aber was dann? Vielleicht hat das Proof-Programm einen Fehler. Vielleicht hat die Spezifikation selbst einen Fehler.

Wir können also die Anzahl der Fehler deutlich reduzieren, aber es ist sehr unwahrscheinlich, dass wir jemals auf Null kommen.

Weil es eine Vorstellung gibt, dass jede Korrektur, die Sie vornehmen, mehr Fehler verursacht, aber ich denke nicht, dass das wahr ist.

(Betonung hinzugefügt)

Du hast Recht. Diese Aussage ist falsch. Hier ist ein Beispiel:

int main() {
    int x[10];
    x[10] = 8; //Buffer overflow here
    return 0;
}

Beheben wir nun diesen Fehler:

int main() {
    int x[11];
    x[10] = 8; //No buffer overflow here
    return 0;
}

Sehen? Wir haben einen Fehler behoben und keine neuen eingeführt.

Es ist jedoch sicher richtig, dass Sie jedes Mal, wenn Sie einen Fehler beheben, das Risiko eingehen, einen neuen zu erstellen, obwohl dieses Risiko gemindert werden kann (z. B. durch Unit-Tests).

Nehmen wir an, dass ich versehentlich für jeweils 100 Fehler, die ich behebe, einen neuen einführe. Wenn ich also 10 000 Fehler behebe, füge ich 100 neue Fehler hinzu. Und wenn ich diese neuen Fehler behebe, füge ich einen Fehler hinzu. Na und? Das Programm hat jetzt 9.999 Fehler weniger, daher ist es wahrscheinlich besser als es war (vorausgesetzt, der neue Fehler ist nicht 10.000-mal schlimmer als der vorherige).

Außerdem kann ein Fehler behebt aussetzen neue. Aber diese Fehler können auch behoben werden. Wenn Sie die Dinge richtig machen, wird die Software irgendwann in einem besseren Zustand sein, als sie begonnen hat.

Ich war von ein paar Top-Programmierern alt, dass es besser ist, nicht viele Fehler zu beheben, weil ich dies im OP erwähnt habe.

Dieses Verhalten ist fahrlässig. Wenn es einen Fehler gibt und Sie ihn beheben können. Tu es. Natürlich sollten Sie Ihr Bestes tun, um das Hinzufügen neuer Fehler zu verhindern, aber wenn ich für 10 schwerwiegende Fehler, die ich behebe, einen kleinen Fehler einführe, ist dies kein gültiger Grund, um das Beheben von Fehlern zu beenden. Tatsächlich ist es ein guter Grund, weiterhin Fehler zu beheben .

Sie beheben also weniger Fehler, und in Zukunft werden weniger Fehler auf Sie zurückkommen

Je weniger Fehler Sie beheben, desto mehr Fehler verbleiben in Ihrer Software und nerven Ihre Benutzer. In der Tat werden sie "in Zukunft nicht mehr auf dich zurückkommen". Sie werden nicht wiederkommen, weil sie überhaupt nicht gegangen sind. Der Begriff "zurückkommen" ist mit Regressionen verbunden. Auch hier ist es möglich, das Risiko von Regressionen zu verringern.

Einige Fehler können nicht behoben werden, da sie so weit verbreitet sind, dass die Menschen sich auf sie verlassen und das Beheben des Fehlers das Programm für diese Benutzer zum Erliegen bringen würde. Es passiert. Können sie in diesem Fall jedoch wirklich als Bugs betrachtet werden?

Die Mentalität "Fehler beheben, Fehler machen" hängt möglicherweise mit diesem schrecklichen Monster zusammen - Code, der so unlesbar und nicht mehr zu pflegen ist, dass nur durch Berühren Fehler entstehen. Wenn Sie ein Monster in Ihrer Codebasis haben, müssen Sie es möglicherweise zuerst entmonsterisieren, bevor Sie etwas erledigen können.

Wenn Sie ein schrecklicher Programmierer sind, besteht die Gefahr, dass alles, was Sie anfassen, neue Fehler verursacht. Dies würde ältere Programmierer offensichtlich nervös machen. Sagen Sie jedoch: "Tun Sie nichts. Berühren Sie nichts. Atmen Sie nicht einmal." ist wahrscheinlich nicht der richtige Weg, um ein gesundes Arbeitsumfeld zu schaffen. Bildung ist besser.

Fazit:

  • Software, die immer wieder neue Funktionen, aber keine Fehlerkorrekturen bietet, wird unweigerlich nerven.
  • Software, die eine mäßige Anzahl neuer Funktionen erhält, deren Fehler jedoch behoben wurden, hat eine bessere Chance, verwendbar zu sein.
  • Diejenigen, die versuchen, wenige Fehler zu haben, haben (im Durchschnitt) weniger Fehler als diejenigen, die sich nicht darum kümmern.
  • Es ist nicht zu erwarten, dass ein Programm irgendwann fehlerfrei wird.
  • Erfahrene Programmierer sind nicht unbedingt kompetent.
  • Beheben Sie Ihre Fehler.
  • Wenden Sie Methoden an, die die Qualität Ihrer Software verbessern.
Luiscubal
quelle
+1: Ich habe selbst nach dem binären Suchbeispiel gesucht und es wurde übertroffen;) Wenn 20 Zeilen viel diskutierten und in Umlauf gebrachten Codes 20 Jahre lang einen Fehler aufwiesen, wie viel Zeit würden Sie für eine 20-Millionen-Zeilen-Codebasis benötigen, die bei Die meisten Dutzend beschäftigten Leute werden sich jemals umschauen.
Scrwtp
Vielen Dank. Ich frage mich, ob dieser Fehler bei der binären Suche (den ich noch nie gehört habe) damit zusammenhängt, dass Leute viel Code kopieren, ohne viel nachzudenken. Auch wenn wir so viele Fehler haben, die sogar aufgezählt werden können, sind die von uns verwendeten Tools und Methoden möglicherweise nicht optimal?
Joan Venge
1
@JoanVenge Ich habe dieses Beispiel zitiert, um zu zeigen, wie schwierig es sein kann, Fehler zu finden. In diesem Fall war das Einfügen von Kopien genau das Richtige, da es sich als richtig erwiesen hat und eine von Grund auf neu geschriebene Implementierung höchstwahrscheinlich mehr Fehler aufweisen würde. Die Werkzeuge und Praktiken, die wir - als Branche im Allgemeinen - einsetzen, sind sicherlich nicht optimal. Best Practices sind leicht zu ignorieren und schlechte Gewohnheiten sind leicht beizubehalten. Letztendlich wird es immer Bugs geben, weil Menschen nicht perfekt sind. Aber wir können die Anzahl der Fehler reduzieren, indem wir unser Bestes geben und auf qualitativ hochwertiger Ausbildung bestehen.
Luiscubal
7
Ich denke, der Fehler im binären Suchcode zeigt, wie komplex diese Frage ist. Der zugrunde liegende Fehler bei der Suche war ein potenzieller Ganzzahlüberlauf in einer Addition. Solche "Fehler" sind allgegenwärtig, da die meisten Leute auf einer impliziten (und gelegentlich falschen) Annahme beruhen, dass Eingaben nicht groß genug sind, um einen Überlauf zu verursachen. Ist es wirklich ein Fehler oder nur ein schlecht dokumentierter Schnittstellenvertrag? Wann haben Sie das letzte Mal die Summanden in einer Ganzzahladdition überprüft oder nachträglich auf Überlauf überprüft?
Charles E. Grant
4
Ihre Beispielserver heben eine ziemlich offensichtliche Beobachtung über Programmiersprache und Werkzeugqualität hervor. Ein Compiler in Produktionsqualität für eine robuste Sprache hätte sich geweigert, Ihr erstes Beispiel zu kompilieren, und stattdessen einen schwerwiegenden Kompilierungsfehler zurückgegeben. Dass es sogar MÖGLICH ist, einen solchen Gräuel zu kompilieren, sagt Ihnen alles, was Sie über die Qualität dieser Tools und die Machbarkeit ihrer Verwendung für die Bereitstellung fehlerfreier Software wissen müssen.
John R. Strohm
12

Die Gründe, warum keine fehlerfreien Programme geschrieben werden, sind meist wirtschaftlich.

Es gibt mathematische Methoden, um die Richtigkeit eines Programms zu beweisen. In einem hochwertigen Informatikkurs werden sie erwähnt. Es gibt Programmiersprachen, die speziell für diesen Zweck erfunden wurden. In der Theorie, Programmierung , ohne Fehler ist möglich.

Ja, es gibt eine unvollständige Hardware, die sich manchmal geringfügig ändert, weil ein Neutrino, das vor Millionen von Jahren von einer entfernten Supernova abgefeuert wurde, Ihren Prozessor gerade an der richtigen Stelle getroffen hat. Okay, jede Theorie hat ihre Annahmen und Abstraktionen. Unter der Annahme, dass der Prozessor wie angekündigt arbeitet, gibt es mathematische Werkzeuge, die sicherstellen, dass das Programm auch korrekt funktioniert.

Einige häufig gestellte Fragen in diesem Thema sind irreführend. Zum Beispiel Gödels Unvollständigkeitssatz und Halteproblem bedeutet nur , dass Sie nicht haben können zB ein automatisiertes Tool , die Richtigkeit oder Unrichtigkeit entscheiden würde jedes Programm. Aber wir wollen nicht die Richtigkeit entscheiden jedem Programm wollen wir nur einen Beweis für die Richtigkeit der einem bestimmten Programm.

(Analog, nur weil Sie nicht ein Programm zum automatischen Entscheidung Wahrheit schreiben können jeden mathematischen Satz, das bedeutet nicht , dass man nicht beweisen kann , einen bestimmten mathematischen Satz.)

Das Problem ist stattdessen folgendes:

Obwohl es theoretisch möglich ist, ein fehlerfreies Programm zu schreiben, wäre dies sehr teuer . Das Schreiben eines Codes mit einem Beweis seiner Korrektheit ist komplizierter als einfach etwas gegen eine Wand zu werfen und zu sehen, ob es klebt. Auch wenn "sehen, ob es klebt" durch Unit-Tests gemacht wird; und viele Programmierer kümmern sich nicht einmal darum. Die meisten Programmierer würden nicht einmal wissen, wie das geht, was bedeutet, dass Sie als Unternehmen teurere einstellen müssten.

Unter Berücksichtigung aller Kosten ist ein typischer Kunde mit einer billigen Software zufriedener, die 99% der Zeit (und 99,9% der Zeit nach der Installation zusätzlicher Updates) gut funktioniert, als mit einer tausendmal teureren Software, die zu 100% gut funktioniert die Zeit. Außerdem möchte der Kunde diese Software jetzt und nicht in zehn oder zwanzig Jahren haben.

Daher produzieren die Leute wissentlich Software, bei der die Wahrscheinlichkeit von Fehlern besteht, und versuchen, die optimale Kombination zu finden, bei der die Fehler nicht zu häufig und nicht zu schwerwiegend sind und die Produktion schnell und billig genug ist. Die Kombination, die den größten Gewinn im wirklichen Leben bringt. (Manchmal bedeutet dies sogar, dass Sie eine Software mit vielen Fehlern veröffentlichen, bevor Ihre Konkurrenten etwas veröffentlichen, und erst dann eine anständigere Version 2.0 veröffentlichen, wenn Ihre Konkurrenten bereit sind, ihre erste anständige Version zu veröffentlichen.)

Wenn Sie die Entwicklung so lange einfrieren, wie es sein muss, können Sie dann tatsächlich alle Fehler beheben, bis es einfach keinen einzigen Fehler mehr gibt, wenn dies durch Computer überprüft werden könnte?

Mathematisch gesehen könnten Sie. Aus wirtschaftlicher Sicht, warum sollte das jemand tun? Es würde bedeuten, vielleicht zwanzig Jahre und ein paar Millionen Dollar auszugeben. In der Zwischenzeit möchten Kunden neue Funktionen, und Ihre eingefrorenen Anwendungen können diese nicht bereitstellen. Sobald Ihre perfekte Version fertig ist, ist der Markt bereits von Ihren Mitbewerbern besetzt.

Wirtschaftlich zu argumentieren ist in Ordnung. Wir leben in einer Welt, in der Geld und Zeit eine Rolle spielen. Aber nur weil wir aus wirtschaftlichen Gründen etwas nicht tun, sollten wir keinen Unsinn darüber reden, wie das selbst in der Theorie nicht möglich ist. Wer weiß ... vielleicht werden wir in ein paar Jahren einige neue Programmiersprachen und Tools haben, mit denen sich die Korrektheit leicht nachweisen lässt .

Viliam Búr
quelle
Danke, obwohl ich wünschte, die meiste Software hätte 99% der Zeit funktioniert, sind die meisten großen, die ich wie die in OP verwende, extrem fehlerhaft. Aber ich denke, Monopol und der Kauf von Mitbewerbern tragen auch dazu bei. Aber ich verstehe deinen Standpunkt.
Joan Venge
1
"Teuer" ist relativ. Vergleichen Sie die Kosten für das Auffinden und Beheben von Fehlern mit den Kosten für z. B. ein Strahlentherapiegerät, das mehrere Patienten tötet und mehrere andere verstümmelt. (Google "Therac 25".)
John R. Strohm
6

Nein.

David Hilbert schlug bereits 1900 sein zweites mathematisches Problem vor , das die Welt im wesentlichen aufforderte, zu beweisen, dass die Arithmetik wie beabsichtigt funktionierte. Er schlug später " das Entscheidungsproblem " vor, das in logischen Begriffen etwas Ähnliches verlangte. Kurt_Gödels " erster Unvollständigkeitssatz " bewies 1931, dass keine Theorie der Elementararithmetik sowohl konsistent als auch vollständig sein kann. Alan Turings Repräsentation des Entscheidungsproblems als " das stoppende Problem " rückte das Thema direkt in den Mittelpunkt dieser Frage, wo er bewies, dass es unmöglich ist zu beweisen, ob ein Programm bis zum Ende laufen wird oder nicht. Angesichts dieser UnentscheidbarkeitEs ist auch unmöglich zu beweisen, ob ein Programm Fehler enthält oder nicht.

Nichts davon befreit die übenden Programmierer unter uns davon, nach keinen Fehlern zu streben. Es bedeutet lediglich, dass wir im Allgemeinen nicht erfolgreich sein können.

Ross Patterson
quelle
9
Die Unentscheidbarkeit gilt nur generell - es gibt Programme, für die Sie weder Richtigkeit noch Unrichtigkeit nachweisen können. Für ein bestimmtes Programm kann jedoch häufig die Richtigkeit (oder häufiger: die Unrichtigkeit) nachgewiesen werden. Dies setzt voraus, dass Sie eine formale Sprachspezifikation und einen nachweislich korrekten Compiler haben - letzterer existiert für keine höhere Programmiersprache, obwohl CompCert sehr nahe kommt.
Daniel
+1 für das Zitieren des relevanten theoretischen Hintergrunds. Ich wusste noch nicht, dass das "Entscheidungsproblem" auf Englisch genauso heißt wie auf Deutsch!
Peopleware
5
Stimme Daniel zu. Die Herausforderung betrifft eine einzelne Instanz. Die Halteprobleme betreffen alle möglichen Fälle. Hält int main() { return 0; } trivial an und ist fehlerfrei.
MSalters
1
Das Problem des Anhaltens besagt nicht, dass es unmöglich ist zu beweisen, ob ein Programm vollständig ausgeführt wird. es heißt, dass es Programme gibt , für die es unmöglich ist zu beweisen. Regelmäßige Alltagsprogramme sind nicht in dieser Klasse. "Während der Beweis von Turing zeigt, dass es keine allgemeine Methode oder keinen Algorithmus gibt, um zu bestimmen, ob Algorithmen anhalten, können einzelne Instanzen dieses Problems durchaus angreifbar sein. Bei einem bestimmten Algorithmus kann man oft zeigen, dass es für jede Eingabe anhalten muss." und tatsächlich tun Informatiker oft genau das als Teil eines Korrektheitsnachweises. "
Endolith
6

Errare humanum est

Selbst wenn Sie Code mit einer formalen Sprache wie der B-Methode schreiben, mit der Sie mathematisch nachweisen können, dass die Anforderungen erfüllt sind,

Auch wenn Sie eine formale Spezifikationssprache verwenden,

Es gibt immer einen menschlichen Schritt, der darin besteht, die Bedürfnisse des Benutzers von einem oder mehreren Gehirnen zu einem Computer zu extrahieren.

Dieser menschliche Schritt ist fehleranfällig und der Wurm steckt im Apfel.

mouviciel
quelle
1
Ist es immer noch ein Fehler, wenn ein Programm tut, was gefragt wurde, anstatt was beabsichtigt war?
MSalters
Ich denke, es ist ..
Joan Venge
4
@MSalters - Natürlich ist es das. Nicht aus vertraglicher Sicht, aber am Ende hat der Kunde sein Problem nicht gelöst. Würden Sie in einem Flugzeug fliegen, dessen Computer was fragten, aber nicht was beabsichtigten?
Mouviciel
3

Ein angemessener Teil der "Bugs", auf die ich gestoßen bin, kann besser als Missverhältnis zwischen Systemdesign und Kundenerwartung beschrieben werden.

Nun, ob wir diese Fehler nennen oder nicht, ist akademisch, aber die Tatsache bleibt, dass ein Großteil der Wartungsarbeiten als direkte Folge einer unvollständigen Kommunikation und sich verändernden Kundenerwartungen anfällt.

Selbst wenn ein System technisch und nachweislich "korrekt" ist, um eine Spezifikation zu erfüllen (wie unwahrscheinlich es auch für echte kommerzielle Software sein mag), haben Sie dennoch das Problem, die Funktion der Software an die Anforderungen Ihres Kunden anzupassen. wechselnde und schlecht definierte Erwartungen.

Zusamenfassend:

Nein.

William Payne
quelle
+1 Ein Entwickler und ein Kunde haben möglicherweise sehr unterschiedliche Ansichten darüber, was einen "Bug" definiert.
GroßmeisterB
Was aber, wenn der Entwickler auch der Benutzer ist? Ich finde im Allgemeinen die beste Software von diesen Leuten in Bezug auf Benutzerfreundlichkeit, da sie genau wissen, wie etwas funktionieren sollte usw.
Joan Venge
2

Wenn Sie eine ausreichend enge und eingeschränkte Spezifikation haben, können Sie möglicherweise ein fehlerfreies Programm nachweisen, das jedoch nur auf unbeweisbaren Annahmen über die korrekte Funktionsweise aller anderen Komponenten des Systems basiert. Dies lässt zu, dass es keine Möglichkeit gibt, zu beweisen, dass die Spezifikationen von demjenigen, der das ursprüngliche Problem aufgeworfen hat, oder von dem, der den Dienst in Anspruch genommen hat, als korrekt angesehen werden.

ddyer
quelle
1

Ich fand Jim Shores Abschnitt No Bugs eine sehr nützliche Lektüre zu diesem Thema. Die Kurzform: Es ist nicht möglich, fehlerfrei zu entwickeln - aber wir können so arbeiten, dass wir sie so früh wie möglich erkennen.

Während der Produktion des Codes selbst. Zum Beispiel stellen wir durch häufiges Schreiben und Ausführen von Unit Tests während der Entwicklung sicher, dass der Code stets das tut, was er tun soll. Es ist auch nützlich, vorhandenen Code so fortlaufend umzuschreiben, dass das beabsichtigte Systemverhalten am deutlichsten zum Ausdruck kommt.

In Ihrem Fall sprechen Sie jedoch von einer bereits vorhandenen Codebasis mit Millionen von Codezeilen. Wenn Sie ein solches System fehlerfrei erhalten möchten, müssen Sie zunächst wissen, was "ein Fehler" für dieses System ist. Sie können eine Reihe von Post-Hoc-Tests schreiben, um die Funktionsfähigkeit des Systems sicherzustellen (falls noch nicht vorhanden). Das Netz dieser Tests kann als ungefähre Definition für das korrekte Systemverhalten dienen. Aber je mehr Code Sie haben, desto mehr Aufwand ist mit solchen Übungen verbunden. Daher machen die meisten Unternehmen einen Kompromiss: Sie leben mit dem Unvollkommenen und arbeiten mit Fehlerlisten und Wartung, um die nervigsten Fehler aus dem System herauszuholen.

rplantiko
quelle
1

Über das Überprüfen durch Computerteil.

Es gibt zwei Möglichkeiten, ein Programm mithilfe eines Computers zu überprüfen. Einer testet, der andere benutzt ein Proofsystem.

Sobald ein umfassender Test nicht möglich ist, kann der Test nicht mehr zeigen, dass ein Programm keine Bugs enthält, sondern nur noch einige. (Und Sie haben das Problem zu zeigen, dass Ihre Tests selbst nicht auf das Vorhandensein von Fehlern testen).

Um ein Proof-System zu verwenden, gehen Sie von formalen Anforderungen aus (und sie haben möglicherweise selbst Fehler, hoffentlich ist die für die Anforderungen verwendete Sprache geeigneter, um sich davon zu überzeugen, dass es dort keinen Fehler gibt als bei einer Programmiersprache) und konstruieren / beweisen mit Mithilfe von Proof-Systemen ist das Programm fehlerfrei (und es gibt die Frage nach Fehlern in den Proof-Systemen, aber sie haben sich als richtig erwiesen). Der aktuelle Stand der Technik ist ein Compiler für eine C-Teilmenge (und die Teilmenge ist nicht akademisch: "CompCert unterstützt die gesamte MISRA-C 2004-Teilmenge von C sowie viele von MISRA ausgeschlossene Funktionen").

Ein Programmierer
quelle
Um Donald Knuth (aus dem Gedächtnis) zu zitieren: Sie können beweisen, dass ein Programm fehlerfrei ist, aber das heißt nicht, dass es keine Fehler enthält :-)
gnasher729
1

Nein, da sich die Computer- und Softwareumgebung, auf der die Anwendung ausgeführt wird, auch dann weiter ändert, wenn der Code eingefroren ist. Das Betriebssystem wird mit Patches und Fixes sowie den Geräten und Treibern weiterentwickelt. Sobald Sie der Meinung sind, dass keine bekannten Fehler mehr vorliegen, wird von AMD oder nVidia ein Grafiktreiber-Update veröffentlicht, das sich auf die Interaktion mit dem Videosubsystem auswirkt. Jetzt weist Ihre Anwendung bei Kunden mit einer bestimmten Grafikkarte oder Konfiguration (SLI? LOL) visuelle Mängel auf (z. B. Blinken, Flackern oder Reduzierung der Bildrate).

Abgesehen von der Hardware und dem Betriebssystem gibt es auch eine Reihe von Middleware-Produkten unter den wichtigsten Apps, die sich auch außerhalb Ihrer Kontrolle entwickeln. Sobald Sie Ihren Code auf einen fehlerfreien Zustand bringen, werden die darunter liegenden Schichten EOL'ed.

Die Technologie entwickelt sich ebenso wie das Geschäft, das die Technologie nutzt, und die Idee, Code freizugeben, ist nicht möglich oder machbar. Das Unternehmen, das nach einem neuen Funktionsumfang fragt, wird nicht gut auf "Wir haben den Code gesperrt, während wir alle bekannten Fehler verfolgen und niemand in X Monaten einen gültigen Softwarefehler meldet" reagieren. Selbst wenn das Unternehmen diese Produktlinie kauft, werden sie nach X Monaten fragen, wie die neuen Funktionen aussehen, und die Antwort kann nicht lauten: "Wir haben uns entschlossen, den Freeze zu verlängern, da Oracle nur einen Patch veröffentlicht und wir X weitere Monate benötigen das bescheinigen ".

Nein, irgendwann wird das Unternehmen nach einem flexibleren Entwicklungsteam suchen, das die Notwendigkeit unterstützt, mit der Geschwindigkeit der Technologie voranzukommen. Dies ist das grundlegende Problem, mit dem moderne Entwicklungsteams konfrontiert sind.

Thomas Carlisle
quelle
0

Ja, aber Sie werden es nie genau wissen. Je schwieriger Sie suchen, desto mehr werden Sie finden. Je schwerer das System verwendet wird und je mehr Edge-Cases verwendet werden, desto wahrscheinlicher wird eine andere Nichtübereinstimmung mit der ursprünglichen Absicht oder Spezifikation. Dies impliziert, dass ein Fehler selbst keine exakte Sache ist und oft von der Interpretation abhängt, wie schlecht ein Individuum eine wahrgenommene Anomalie einschätzt.

Es ist eine unscharfe Sache. Nur wenige Systeme sind bis zum letzten Bit spezifiziert. Wenn ein System gut funktioniert und die Benutzer keine Beschwerden haben (sie werden von nichts abgehört) und sie sind vollständig an das System angepasst, können Sie es auch als fehlerfrei bezeichnen.

Martin Maat
quelle
-2

Bei ausreichender Disziplin und gemeinsamer Teamkultur ist es möglich, durchgängig fehlerfreie Software bereitzustellen. (Und ein ausgereifter modularer Code, eine umfassende Suite automatisierter Tests, die Überprüfung von Fehlern und die Anpassung Ihres Prozesses sowie viele andere Dinge, die Aufwand und Demut erfordern, sich aber tausendfach auszahlen.)

Aber damit wollen Sie im Allgemeinen kein 20-MLOC-System aufbauen. Wenn das Schreiben von fehlerfreiem Code nicht Ihr Ziel ist, sollten Sie auch nicht viele MLOC-Systeme erstellen.

Meine eigene Argumentation lautet wie folgt:

Eine Person hat ein Bedürfnis zu erfüllen. Eine Person (möglicherweise dieselbe, möglicherweise eine andere) verfügt über ein Budget, um den Bedarf durch das Schreiben von Software zu decken. Alle diese Menschen erwarten einen gewissen Nutzen für ihr Geld.

Die Person mit einem Budget bezahlt einige Leute (möglicherweise die gleichen, möglicherweise unterschiedlichen), die Programmierer genannt werden , so dass diese Programmierer eine vereinbarte Menge ihrer Zeit in Software verwandeln, die den Bedarf erfüllt.

Diese Programmierer arbeiten daher daran, das Geld eines anderen in Software umzuwandeln, die die Anforderungen erfüllt. Es liegt in ihrer Verantwortung, dieses Geld sinnvoll einzusetzen.

Dies hat folgende Auswirkungen auf Ihre Frage:

  • Wenn es einen Fehler in der Software gibt, werden Sie ihn dann überhaupt beheben? Sie benötigen einen Programmierer, um einen Fehler zu beheben, und der Programmierer wird Geld kosten. Ein Programmierer kann sich nicht entscheiden, ob er das Geld dafür ausgeben soll. Es ist die Rolle der Person, die das Budget hält.
  • Kann ich eine 20MLOC-Software von Grund auf neu erstellen, ohne am Ende nicht behobene Fehler zu hinterlassen? Nun, um ein 20MLOC aufzubauen, musste man eine enorme Menge Geld ausgeben. Das ist finanziell dumm. Und es wird nicht an einem Tag gebaut. Aber Software ist für die Bedürfnisse von heute und nicht für morgen. Es wird einen fehlgeleiteten Versuch geben, die Entwicklung zu parallelisieren, indem viele Programmierer eingestellt werden. Aber dann ist zu befürchten, dass Sie keine gemeinsame Kultur entwickeln und Fehler auftreten, Verschwendung und Verzögerung eintreten und das Geld knapp wird, um sie zu beheben. Ich habe noch kein fehlerfreies System dieser Größe gesehen. (Ich habe fehlerfreie Systeme und 20MLOC-Systeme gesehen, aber sie waren nicht die gleichen)
  • Ich bin für die Wartung eines 20MLOC-Systems verantwortlich, das ich nicht geschrieben habe. Kann ich null bekannte Bugs erreichen? Dies hängt nicht von den Programmierern ab. Sie können sich nicht dafür entscheiden, Fehler zu beheben, weil es nicht ihr Geld ist. Reicht der ROI aus, um die verbleibenden Fehler zu beheben? Nun, das System gibt es schon seit einiger Zeit, und die Benutzer haben sich daran gewöhnt und nutzen die Macken des Systems zu ihrem Vorteil bei ihrer täglichen Arbeit. Wenn Sie Fehler aus Prinzip beheben, muss die Person mit dem Geld möglicherweise bezahlen, um eine nicht spezifizierte Funktion neu zu entwickeln , die aus dem System verschwunden ist, was noch mehr Geld kostet.

Es geht nur ums Geld, und das zu Recht.

Laurent LA RIZZA
quelle
-2

Ja.

Aber wie Sie wissen, erfordert es viel zu viel Mühe, um es wert zu sein.

Bevor ich meine Antwort verteidigen kann, müssen wir zuerst definieren, was ein Fehler ist:

  • Ein Fehler ist ein Verhalten, das der Spezifikation widerspricht.
  • Störungen in der Spezifikation (z. B. das 0. Gesetz der Robotik) gelten jedoch nicht als Softwarefehler.
  • Zusätzliche Funktionen gelten nicht als Fehler, es sei denn, die Spezifikation untersagt sie.
  • Widersprüche innerhalb der Spezifikation gelten aus Gründen der Argumentation auch nicht als Softwarefehler.

Wie Sie hoffentlich bereits wissen, sind gute Software-Architekturen modular aufgebaut, sodass jedes Modul einzeln getestet werden kann (oder manuell getestet werden kann oder was auch immer). Durch Disziplin und sorgfältiges Testen ist es möglich, einzelne Module zu schreiben, die keine Bugs enthalten.

"Aber warte!" Ich höre Sie protestieren: "Was ist, wenn ein unerwartetes (aber dennoch korrektes) Verhalten eines Moduls einen Fehler in einem anderen verursacht?" Dann ist der Fehler im zweiten Modul. Fehlerfreie Module können als APIs behandelt werden, und APIs erfordern, wie Sie wissen, einige Sorgfalt, um richtig verwendet zu werden.

Das Schreiben von kugelsicherem Code erfordert ein umfassendes Wissen über Randfälle und Ablauflogik seitens des Entwicklers, und die meisten Softwareentwickler sind entweder nicht schlau genug, um etwas zu lernen, oder es ist ihnen einfach egal. Oder häufiger, sie haben eine Frist.

"Aber gib mir einen Platz zum Stehen, und ich werde die Welt bewegen." - Archimedes

Jonathan Graef
quelle
Es erfordert Mühe, die sich aber auszahlt.
Laurent LA RIZZA
1
Wenn Sie Spezifikationsfehler aus der Gleichung herauslassen, wird Ihre gesamte Software unbrauchbar: Spezifikationen sind nur Werkzeuge, um die Benutzeranforderungen auf eine relativ formale Weise aufzuschreiben, aber am Ende ist es der Benutzer, der zufrieden sein muss, nicht die Spezifikation. Das Erstellen der Spezifikation ist ebenso Teil der Softwareentwicklung wie das Schreiben des Codes. Schließlich würde eine vollständige formale Spezifikation das Verhalten des Systems genau wie der endgültige Code beschreiben. Die Spezifikation ist einfach nicht effizient ausführbar.
cmaster