Wie kann die Anzahl der Fehler beim Codieren verringert werden?

30

Niemand ist perfekt und egal was wir tun, wir werden von Zeit zu Zeit Code produzieren, der Fehler enthält. Mit welchen Methoden / Techniken können Sie die Anzahl der von Ihnen verursachten Fehler verringern, sowohl beim Schreiben neuer Software als auch beim Ändern / Verwalten von vorhandenem Code?

GSto
quelle
Eine gute Methode besteht darin, mehr im Voraus zu entwerfen (nicht zu viel, aber genug, um den Code strukturierter und verständlicher zu gestalten).
Giorgio

Antworten:

58

Vermeiden Sie ausgefallene Codierungen. Je komplizierter der Code, desto wahrscheinlicher sind Fehler. In der Regel ist klar geschriebener Code auf modernen Systemen schnell und klein genug.

Verwenden Sie verfügbare Bibliotheken. Die einfachste Möglichkeit, Fehler beim Schreiben einer Dienstprogrammroutine zu vermeiden, besteht darin, sie nicht zu schreiben.

Lernen Sie ein paar formale Techniken für die komplizierteren Dinge. Wenn es komplizierte Bedingungen gibt, nageln Sie sie mit Stift und Papier fest. Idealerweise sollten Sie einige Beweistechniken kennen. Wenn ich nachweisen kann, dass der Code korrekt ist, ist er fast immer gut, außer für große, dumme, offensichtliche Fehler, die leicht zu beheben sind. Natürlich geht das nur so weit, aber manchmal kann man formell über kleine, aber komplizierte Dinge nachdenken.

Erfahren Sie, wie Sie bei vorhandenem Code eine Umgestaltung durchführen: wie Sie kleine Änderungen am Code vornehmen, häufig mithilfe eines automatisierten Tools, mit dem der Code besser lesbar wird, ohne das Verhalten zu ändern.

Mach nichts zu schnell. Nehmen Sie sich etwas Zeit, um die Dinge richtig zu machen, zu überprüfen, was Sie getan haben, und darüber nachzudenken, was Sie tun, kann sich später auszahlen.

Sobald Sie den Code geschrieben haben, verwenden Sie, was Sie haben, um es gut zu machen. Unit-Tests sind großartig. Sie können häufig Tests vorab schreiben, was ein großartiges Feedback sein kann (wenn dies konsequent durchgeführt wird, ist dies eine testgetriebene Entwicklung). Kompilieren Sie mit Warnoptionen und beachten Sie die Warnungen.

Bitten Sie jemanden, sich den Code anzusehen. Formale Codeüberprüfungen sind gut, aber möglicherweise nicht zu einem geeigneten Zeitpunkt. Pull-Anforderungen oder ähnliches, wenn Ihr SCM sie nicht unterstützt, ermöglichen asynchrone Überprüfungen. Buddy-Prüfung kann eine weniger formelle Überprüfung sein. Die Paarprogrammierung stellt sicher, dass zwei Augenpaare alles betrachten.

David Thornley
quelle
x2 - was Ryan gesagt hat.
JBRWilkinson
2
Auch die meisten Sprachen können mehr oder weniger wählerisch sein. Sie möchten, dass es so wählerisch wie möglich ist.
1
"Lernen Sie ein paar formale Techniken für die komplizierteren Dinge." ... zum Beispiel?
Dan Rosenstark
1
@Yar: Ich erwarte so etwas wie die in diesem Buch erläuterten Systeme: amazon.com/Verification-Sequential-Concurrent-Programs-Computer/… ; Obwohl ich sagen muss, dass ein bestimmtes Buch extrem trocken und langweilig ist, gibt es wahrscheinlich viel bessere Bücher (aber es ist das einzige, das ich gelesen habe).
Joeri Sebrechts
30

Mit Unit Tests können Sie die Anzahl der Fehler reduzieren, die ein zweites Mal auftreten. Wenn Sie in Ihrem Code einen Fehler finden, können Sie durch Schreiben eines Komponententests sicherstellen, dass er später nicht mehr angezeigt wird. (Außerdem ist es manchmal schwierig, an alle Fälle zu denken und Tausende von Einheitentests im Voraus zu schreiben.)

Ryan Hayes
quelle
3
"Vorab an alle Fälle denken" führt zu sauberen, vollständig spezifizierten Schnittstellen, was nur gut sein kann. Unit-Tests sind nur schwer zu schreiben, wenn Sie sie mit Code nachrüsten, der nicht für Tests entwickelt wurde.
Mike Seymour
1
Wenn du kannst, solltest du. Leider wurden Unit-Tests in den meisten Fällen als etwas angesehen, das mehr kostet als nur "das schnelle Beheben von Fehlern". Also, wenn Sie können, sollten Sie Tests im Voraus schreiben, aber wenn dies nicht als "kostengünstig" angesehen wird, können Sie sie zusammen mit Fehlerkorrekturen im Laufe der Zeit aufbauen, ohne zu viel Geld für das Schreiben von Komponententests zu investieren .
Ryan Hayes
4
"Testen zeigt das Vorhandensein, nicht das Fehlen von Fehlern." - E. Dijkstra. Davon abgesehen sind automatisierte Tests auf jeden Fall eine sehr nützliche Methode, um die Softwarequalität zu erhalten und zu verbessern.
Limist
9

+1 für beide Kommentare zum Komponententest.

Stellen Sie darüber hinaus die höchste Warnstufe ein, die Ihr Compiler anbietet, und stellen Sie sicher, dass Warnungen als Fehler behandelt werden. Fehler verbergen sich oft in diesen "fehlerhaften" Fehlern.

In ähnlicher Weise sollten Sie in statische Analysetools investieren, die zur Kompilierungszeit ausgeführt werden (ich betrachte diese als zusätzliche Stufe von Compiler-Warnungen).

Alan
quelle
+1 für den statischen Analysekommentar. Es ist von unschätzbarem Wert, all diese Informationen kostenlos zu bekommen :)
Morten Jensen
9

Zusätzlich zu dem, was erwähnt wurde:

  • Ignorieren Sie keine Fehlercodes - nehmen Sie beispielsweise nicht an, dass Sie ein gültiges Ergebnis erhalten haben, dass eine Datei erfolgreich erstellt wurde usw. ... Eines Tages wird etwas passieren.
  • Gehen Sie nicht davon aus, dass Ihr Code niemals eine Bedingung eingibt und dass es daher sicher ist, diese Bedingung zu ignorieren.
  • Testen Sie Ihren Code und lassen Sie ihn dann von einer anderen Person testen. Ich finde, ich bin die schlechteste Person, um meinen eigenen Code zu testen.
  • Machen Sie eine Pause, lesen Sie Ihren Code erneut und prüfen Sie, ob Sie "das Offensichtliche verpasst haben". Passiert mir oft

Viele andere Dinge vergesse ich im Moment, aber die anderen werden sicherlich an sie denken. :)

MetalMikester
quelle
7
Und wenn Sie so sicher sind , dass diese Bedingung X wird nie passieren ... verwenden , um eine Assertion , um sicherzustellen , dass , wenn Bedingung X passiert, werden Sie wissen es (durch eine Ausnahme, oder Protokollierung, oder was auch immer).
Frank Shearar
@MetalMikester: Unit-Tests sind gut. Aber mit hochqualifizierten Sprachen und guten Bibliotheken erfordern die meisten schweren Fehler Integrationstests und Regressionstests.
Vector
9

Ich habe einen ziemlich funktionalen Programmierstil entwickelt, obwohl meine Hauptsprachen C ++ und Python sind. Ich stellte fest, dass mein Code viel robuster geworden ist, wenn ich den gesamten Kontext an eine Funktion (oder Methode) übergebe, die diese Funktion zur Ausführung ihrer Aufgabe benötigt, und die aussagekräftigen Daten zurückgebe, nach denen ich suche.

Der implizite Zustand ist der Feind und meiner Erfahrung nach die häufigste Fehlerquelle. Dieser Status kann eine globale Variable oder eine Mitgliedervariable sein. Wenn die Ergebnisse jedoch von etwas abhängen, das nicht an die Funktion übergeben wird, die Sie nach Problemen fragen, Es ist offensichtlich nicht möglich, den Status zu beseitigen, aber seine Minimierung hat enorme positive Auswirkungen auf die Programmzuverlässigkeit.

Ich sage meinen Mitarbeitern auch gerne, dass jede Filiale (wenn, für, während,? :) ein wahrscheinlicher Fehler ist. Ich kann nicht sagen, wie sich der Fehler manifestieren wird, aber je weniger bedingt Ihr Code sich verhält, desto wahrscheinlicher ist es, dass er fehlerfrei ist, allein aufgrund der Tatsache, dass die Codeabdeckung während der Ausführung konsistenter ist.

Das alles hat natürlich auch positive Auswirkungen auf die Leistung. Sieg!

Dash-Tom-Bang
quelle
Nach meiner Erfahrung kann es schnell mühsam werden, bei jedem Aufruf den gesamten Zustand zu durchlaufen, wenn die Methoden so klein sind, wie sie sein sollten. Dieses Problem kann durch die Verwendung vieler kleiner unveränderlicher Klassen mit kurzen Objektlebensdauern gelöst werden. Auf diese Weise können Sie den temporären Status als Felder speichern und das Objekt verwerfen, wenn Sie den Status nicht mehr benötigen. :-)
Jørgen Fogh
Eine andere Überlegung für den Fall, dass es langweilig wird, ist, dass Sie vielleicht versuchen, zu viel Staat herumzugeben. :)
Dash-Tom-Bang
In vielen Fällen stimmt das, ist es aber oft nicht. Innerhalb einiger Domains benötigen Sie Zugriff auf viele Zustände, auch wenn Sie nicht über viele veränderbare Zustände verfügen . Ich arbeite derzeit an einem Codegenerator, bei dem ich auf mehrere Symboltabellen zugreifen muss. Ich möchte sie nicht an jede Methode weitergeben.
Jørgen Fogh
8
  • Schreiben Sie weniger Code, der mehr bewirkt.
  • Denken Sie über die Auswirkungen auf niedriger Ebene und die Auswirkungen auf hoher Ebene nach
  • Betrachten Sie die Abstraktion, die Sie in Ihrem Code erstellen.
  • Schreiben Sie nach Möglichkeit nur die wesentliche Komplexität.
Paul Nathan
quelle
Ich wollte einen großen Beitrag schreiben, der sich wie folgt zusammensetzt: "Weniger schreiben, das mehr kann" (Ich kenne und benutze die Tools, die Ihnen zur Verfügung stehen). Ich werde dies stattdessen nur +1.
Kaz Dragon
1
Achten Sie jedoch darauf, keinen ausgefallenen Code zu erhalten, wenn Sie versuchen, weniger Code zu erhalten.
Gablin
1
@gablin: Phantasie liegt in vielerlei Hinsicht im Auge des Betrachters. Ich kann heute Code schreiben und lesen, der vor 4 Jahren verblüfft gewesen wäre. Haskell gefällt mir heute. :)
Paul Nathan
8

Eine etwas weniger technische Antwort: Programmieren Sie nicht, wenn Sie müde sind (9 Stunden / Tag sind genug), betrunken oder "gebacken". Wenn ich müde bin, habe ich nicht die nötige Geduld, um sauberen Code zu schreiben.

Alexandru
quelle
2
Normalerweise benötigen die meisten Programmierer mehrere Jahre, um dies zu realisieren. Es ist ein wichtiger Punkt.
Jeff Davis
7

Schreiben Sie Komponententests und Integrationstests .

ysolik
quelle
5

Einige gute Antworten hier in Bezug auf Unit-Tests und Tools. Das einzige, was ich ihnen hinzufügen kann, ist Folgendes:

Binden Sie Ihre Tester so früh wie möglich ein

Wenn Sie ein Testteam haben, geraten Sie nicht in die Falle, sie als Gatekeeper für Ihre Codequalität zu behandeln und Ihre Fehler für Sie zu erkennen. Arbeiten Sie stattdessen mit ihnen und binden Sie sie so früh wie möglich ein (bei agilen Projekten wird dies von Anfang an der Fall sein, aber wir können immer Wege finden, sie früher einzubeziehen, wenn wir es wirklich versuchen).

  • Finden Sie heraus, was ihr Testplan ist. Überprüfen Sie ihre Testfälle mit ihnen - decken Sie sie alle mit Ihrem Code ab?
  • Bitten Sie sie um Verständnis für die Anforderungen. Ist es dasselbe wie deins?
  • Geben Sie ihnen frühe Builds, mit denen Sie Erkundungstests durchführen können - Sie werden erstaunt sein, welche Verbesserungen sie vorschlagen werden.

Eine gute Zusammenarbeit mit Ihren Testern bedeutet, dass Sie schlechte Annahmen und Mängel frühzeitig erkennen können, bevor sie Schaden anrichten können. Dies bedeutet auch, dass sich die Tester befähigt fühlen, beim Produktdesign zu helfen und Usability-Probleme zu erkennen, wenn Zeit zur Behebung ist.

Paddyslacker
quelle
4

Statische Analyse-Tools

Plugins und Apps wie FindBugs crawlen Ihren Code und finden Orte, an denen potenzielle Fehler auftreten können. Orte, an denen Variablen nicht initialisiert und verwendet werden, oder einfach nur verrückte Dinge, die neun Mal von zehn sind, machen das Auftreten von Fehlern einfacher. Mit Tools wie diesen kann ich verhindern, dass mein Knochenkopf die Straße hinunterfährt, auch wenn es noch kein Fehler ist.

PS: Denken Sie daran, immer zu untersuchen, warum ein Tool Ihnen sagt, dass etwas schlecht ist. Es tut nie weh zu lernen (und nicht in allen Situationen stimmt alles).

Ryan Hayes
quelle
3

Code-Inspektion oder andere Formen von Peer-Review, z. B. Paarprogrammierung.

Strukturierte Code-Reviews wie die Fagan-Inspektion können mindestens so effektiv und effizient sein wie Unit-Tests und haben sich in einigen Fällen sogar als besser als Unit-Tests erwiesen. Inspektionen können auch früher im Software-Lebenszyklus und mit anderen Artefakten als Code durchgeführt werden.

Peer Reviews in Software von Karl Wiegers ist ein großartiges Buch zu diesem Thema.

Michael
quelle
2

Aktivieren Sie zusätzlich zu allen anderen Vorschlägen hier alle möglichen Warnungen mit höchster Empfindlichkeit und behandeln Sie sie als Fehler. Verwenden Sie auch alle Flusenwerkzeuge, die in der Sprache verfügbar sind.

Sie werden erstaunt sein, wie viele einfache Fehler durch Warnungen abgefangen werden können und wie viele dieser einfachen Dinge sich in echten Fehlern in Ihrem Code niederschlagen.

greyfade
quelle
2

Viele gute Antworten hier, aber ein paar Dinge, die ich hinzufügen wollte. Stellen Sie sicher, dass Sie die Anforderung wirklich verstehen. Ich habe viele Fehler gesehen, als der Benutzer dachte, die Anforderung bedeute X und der Programmierer dachte, sie bedeute Y. Drücken Sie zur Klärung schlechter oder mehrdeutiger Anforderungen zurück. Ich weiß, dass wir alle gerne einspringen und programmieren, aber je mehr Zeit im Vorfeld für das Verständnis aufgewendet wird, desto weniger Nacharbeit und Fehlerbehebung wird es geben.

Lernen Sie das Unternehmen kennen, das Sie unterstützen. Oft sehen Sie Dinge in Anforderungen, die fehlen oder dann einer weiteren Erläuterung bedürfen. Wenn Sie Aufgabe Y wie angegeben ausführen, wird das vorhandene Feature Z beschädigt.

Verstehen Sie Ihre Datenbankstruktur. Viele, viele Fehler sind das Ergebnis einer syntaktisch korrekten Abfrage, die jedoch die falschen Ergebnisse zurückgibt. Erfahren Sie, wie Sie erkennen, wann Ihre Ergebnisse lustig aussehen. Wenn ich eine komplexe Berichtsabfrage schreibe, lasse ich meine Ergebnisse immer von einem technischen Spezialisten überprüfen, bevor ich sie als betriebsbereit markiere. Die Daten, die ich verpasst habe, enthalten zwangsläufig etwas. Machen Sie sich dann Notizen darüber, was Sie nicht bemerkt haben, und denken Sie daran, dass Sie beim nächsten Mal etwas Ähnliches tun.

HLGEM
quelle
1

Ich denke, die wichtigste Technik ist , sich Zeit zu nehmen . Wenn Sie der Meinung sind, dass Sie zwei Tage brauchen, um ein neues Modul zu codieren, aber Ihr Chef Sie zwingt, nur an einem Tag zu codieren, ist Ihr Code wahrscheinlich fehlerhafter.

Eines der Bücher , die ich vor einiger Zeit gelesen , sagte, dass Sie mit nicht leben sollten zerbrochene Fensterscheiben , weil die Menschen sich nicht darum kümmern , wenn anotherone kaputt geht ... Codierung die gleiche ist, jeder der ersten über das Sein in etwas zu tun , kümmern wird schlecht aber schnell , aber keiner kümmert sich um einen Höllencode mit vielen Fehlern und sehr schlechtem Design und Stil.

greuze
quelle
1

Ich folge der Praxis von Test-Code-Test anstelle von Code-Test-Code-Test. Dies hilft mir, über Anwendungsfälle nachzudenken und die Logik angemessen zu gestalten

viv
quelle
1

Verwenden Sie Tools zur Codeinspektion wie ReSharper oder IDEs wie IntelliJ IDEA , die vor vielen Fehlern beim Kopieren und Einfügen und anderen warnen, indem Sie z. B. auf Variablen hinweisen, die "geschrieben, aber nie gelesen" werden. Hat mir viel Zeit gespart.

DonJoe
quelle
1

Überraschenderweise wurden die folgenden drei sehr wichtigen Punkte noch nicht erwähnt:

  • Verwenden Sie Behauptungen großzügig. Die Frage, die Sie sich immer stellen sollten, lautet nicht "Soll ich das behaupten?" aber "gibt es etwas, das ich vergessen habe zu behaupten?"

  • Entscheiden Sie sich für Unveränderlichkeit. (Benutze final / readonly liberal.) Je weniger veränderlicher Zustand du hast, desto weniger Dinge können schief gehen.

  • Optimieren Sie nicht vorzeitig. Viele Programmierer werden mit Leistungsproblemen konfrontiert, was dazu führt, dass sie ihren Code unnötig verschachteln und ihre Entwürfe verfälschen, ohne vorher zu wissen, ob Leistung ein Problem sein wird. Erstellen Sie Ihr Softwareprodukt zunächst auf akademische Weise, ohne Rücksicht auf die Leistung. Prüfen Sie dann, ob die Leistung schlecht ist. (Dies wird wahrscheinlich nicht der Fall sein.) Wenn es Leistungsprobleme gibt, suchen Sie eine oder zwei Stellen, an denen Sie nette und formale algorithmische Optimierungen vornehmen können, damit Ihr Produkt die Leistungsanforderungen erfüllt, anstatt Ihre gesamte Codebasis zu optimieren und zu hacken Quetsch-Taktzyklen hier und da.

Mike Nakis
quelle