Vor fast zwanzig Jahren habe ich aus David Thielens ausgezeichnetem Buch "No Bugs: Bereitstellung von fehlerfreiem Code in C und C ++", das jetzt als kostenloses PDF verfügbar ist, viel Einblick in dieses Thema erhalten .
Er hat mir zwei großartige Ideen beigebracht ...
Bugs kommen nicht aus dem Nichts. Wir alle Programmierer setzen uns und schreiben sie mit unseren eigenen Fingern in unseren Code.
"Bug" bedeutet, dass eine externe Agentur beschlossen hat, Ihr Programm mit Bugs zu infizieren. Wenn Sie ein sauberes Leben führen und kleine Pelztiere am Fuße Ihres Computers opfern, verschwinden diese ... Dieses Konzept ist wichtig, weil es farbig ist Ihr Ansatz zum Debuggen Ihres Codes. Wenn Sie Fehler als "Fehler" betrachten, hoffen Sie, dass keine gefunden werden. (Sie hoffen, die gute Fee kam vorbei, besprengte Elfenstaub und die Käfer gingen.)
Bugs sollten nicht als Bugs bezeichnet werden, sondern als Massive Fuck-Ups [MFUs] ... MFUs existieren, weil Programme von Menschen geschrieben werden und Menschen Fehler machen ... Sie werden MFUs schreiben. Sie werden sich hinsetzen und mit völliger Bosheit der Voraussicht MFUs in Ihren Code einfügen. Denken Sie darüber nach - Sie wissen, dass Sie derjenige sind, der die Fehler dort hineinsteckt. Wenn Sie sich also zum Code setzen, werden Sie einige Fehler einfügen.
Da es das unausweichliche Schicksal aller Programmierer ist, Fehler zu schreiben, muss ich defensiv codieren, einschließlich Dinge, die aufspringen, schreien und rote Fahnen schwenken, wenn sie einen Fehler entdecken.
Nachdem sie in den frühen 90er Jahren geschrieben wurden, sind die Einzelheiten dazu in Thielens Buch ziemlich veraltet. Unter Linux und Mac OS X müssen Sie beispielsweise keinen eigenen Wrapper mehr für den neuen C ++ - Operator schreiben. Sie können dafür Valgrind verwenden.
Aber es gibt ein paar Dinge, die ich routinemäßig für C / C ++ / ObjC mache:
- Wenn ich es vernünftigerweise kann, aktivieren Sie die Option "Warnungen sind Fehler" des Compilers und beheben Sie sie alle. (Ich unterhalte ein Legacy-Projekt, bei dem das Beheben aller Probleme auf einmal Wochen dauern würde. Daher repariere ich alle paar Wochen eine Datei - und in einigen Jahren kann ich diese Option aktivieren.)
- Verwenden Sie ein statisches Code-Analyse-Tool wie Gimpels PC-Lint oder das sehr raffinierte, das jetzt in Apples Xcode integriert ist. Die Deckung ist noch besser, aber die Kosten sind für große Unternehmen, nicht nur für Sterbliche.
- Verwenden Sie dynamische Analysewerkzeuge wie Valgrind, um nach Speicherproblemen, Lecks usw. zu suchen.
- Wie Thielen sagt (und das Kapitel ist immer noch lesenswert): Assert The World . Natürlich wird niemand außer einem Idioten Ihre Funktion mit einem Null-Zeiger aufrufen - und das bedeutet, dass irgendwo jemand ein Idiot ist, der genau das tut. Vielleicht bist du es in drei Jahren sogar, wenn das, was du heute getan hast, neblig geworden ist. Fügen Sie einfach am Anfang der Funktion eine Zusicherung hinzu, um dieses Zeigerargument zu überprüfen. Die Eingabe dauert drei Sekunden und verschwindet in der ausführbaren Release-Datei.
- In C ++ ist RTTI dein Freund. Auch hier wird niemand außer einem Idioten Ihre Funktion mit einem Zeiger auf die falsche Art von Objekt aufrufen - was bedeutet, dass zwangsläufig ein Idiot dies tun wird - und die Kosten für die Verteidigung dagegen sind vernachlässigbar. In C-basiertem Code, der von GObject abgeleitet ist, können Sie dasselbe mit den defensiven dynamischen Cast-Makros tun.
- Automatisierte Unit- und Regressionstests sind jetzt ein wichtiger Bestandteil meines Repertoires. Bei einem Projekt sind sie ein integraler Bestandteil des Release-Build-Systems, und der Build wird erst abgeschlossen, wenn alle erfolgreich sind.
- Ein weiterer wichtiger Teil ist die Protokollierung von Code in den ausführbaren Debug- und Release-Dateien, der zur Laufzeit durch eine Umgebungsvariable aktiviert werden kann.
- Schreiben Sie Defensivtests, damit Programmierer, die ausführbare Debug-Dateien ausführen, diese nicht ignorieren können, wenn sie fehlschlagen. Laufzeitnachrichten an die Konsole können ignoriert werden. Das Programm, das mit einem Assert abstürzt, kann nicht ignoriert werden.
- Stellen Sie beim Entwerfen öffentliche APIs und private Implementierungen bereit, auf die externer Code nicht zugreifen kann. Auf diese Weise verlässt sich niemand auf eine magische innere Zustandsvariable oder so etwas, wenn Sie umgestalten müssen. In C ++ - Klassen bin ich ein großer Fan von geschützt und privat. Ich denke auch, dass Proxy-Klassen großartig sind, aber ich benutze sie nicht wirklich selbst.
Was Sie für eine neue Sprache oder Technologie tun, hängt natürlich von den Details ab. Aber wenn Sie einmal die Vorstellung in Ihr Herz geschlossen haben, dass Bugs massive Fuck-Ups sind, die Sie mit Ihren eigenen Fingern geschrieben haben, und Ihr Code ständig von einer Armee von Idioten angegriffen wird, mit Ihnen an der Spitze als General, bin ich sicher, dass Sie Ich werde geeignete Abwehrtechniken finden.