Wie kann man das Programmieren durch Zufall überwinden? [geschlossen]

24

In dem Buch The Pragmatic Programmer erwähnen die Autoren das Konzept der zufälligen Programmierung . Es erklärt, was es ist, warum es verursacht wird, welchen Gefahren Sie begegnen können und es ist vergleichbar mit einem Landminenfeld in einem Krieg.

Schaust du dir jemals alte Schwarz-Weiß-Kriegsfilme an? Der müde Soldat kommt vorsichtig aus der Bürste. Vor uns liegt eine Lichtung: Gibt es Landminen oder ist es sicher zu überqueren? Es gibt keine Anzeichen dafür, dass es sich um ein Minenfeld handelt - keine Schilder, Stacheldraht oder Krater. Der Soldat stößt mit seinem Bajonett und zuckt zusammen und erwartet eine Explosion. Es gibt keinen. Also geht er eine Weile mühsam durchs Feld und stupst und stupst dabei. Schließlich ist er überzeugt, dass das Feld sicher ist, richtet sich auf und marschiert stolz vorwärts, um dann in Stücke gerissen zu werden.

Die ersten Minensonden des Soldaten enthüllten nichts, aber das war nur ein Glücksfall. Er wurde zu einer falschen Schlussfolgerung geführt - mit katastrophalen Ergebnissen.

Als Entwickler arbeiten wir auch in Minenfeldern. Es gibt Hunderte von Fallen, die nur darauf warten, uns jeden Tag zu fangen. Wenn wir uns an die Geschichte des Soldaten erinnern, sollten wir uns davor hüten, falsche Schlussfolgerungen zu ziehen. Wir sollten es vermeiden, durch Zufall zu programmieren - indem wir uns auf Glück und zufällige Erfolge verlassen -, um absichtlich zu programmieren ...

Aber ich bin nicht wirklich zufrieden mit der Art und Weise, wie sie das Problem "wie man es überwindet" beschreiben. Ja, Sie müssen überlegen, bevor Sie den Code schreiben, aber wie können Sie das üben? Das Einzige, was ich mir vorstellen kann, ist das Hinzufügen von Funktionen zu vorhandenen Open Source-Projekten, bei denen Sie sowohl über Kenntnisse darüber verfügen müssen, was ich gerade tue als auch darüber, wie die anderen Codeteile funktionieren wenn Sie Ihre eigenen Projekte schreiben.

BEARBEITEN:

eine Zusammenfassung Ihrer Beiträge:

  • Errate deinen nächsten Schritt nicht, beweise, dass er korrekt ist
  • Unit Test und Refactor soweit möglich, wenn nötig
  • Features hinzufügen - häufig kompilieren - testen
  • Wenn Sie einem Neuling den Code nicht erklären können, programmieren Sie wahrscheinlich zufällig.

Übrigens ist es schwer, eine Antwort zu akzeptieren, es ist wirklich schwer. Alle Antworten sind wirklich toll :)

py_script
quelle
6
Es würde Leuten helfen, die das Buch vielleicht schon lange nicht mehr gelesen haben, einen Link wie pragprog.com/the-pragmatic-programmer/extracts/coincidence zu haben .
btilly
Wenn Sie nicht über eine sehr kurze Programmierkarriere verfügen (oder ein Ein-Mann-Unternehmen sind), werden Sie wahrscheinlich auf Code stoßen, der seltsamerweise vertraut aussieht, und später wird der Penny fallen: Es liegt bei Ihnen. Es ist nicht nur eine Open-Source-Überlegung ...
Robbie Dee
@ Robbie Dee. kannst du es ein bisschen genauer erklären? Ich verstehe dich nicht. In der Tat habe ich eine kurze Programmierkarriere und das ist der Grund für das Tag des Junior-Programmierers.
py_script
2
@py_script Ich habe gerade darauf hingewiesen, dass Sie Jahre später genauso leicht auf Ihren eigenen Code stoßen können (und sich davon überraschen lassen) wie auf den eines anderen. Wenn Sie also mit guten Gewohnheiten beginnen, zahlt sich dies später aus.
Robbie Dee

Antworten:

26

Sie müssen nicht vorausdenken, nur sehr klar darüber sein, was getan wurde, und sehr klar darüber, was Sie gerade tun.

Subroutinen sollten sagen, was sie tun, was sie sagen und keine versteckten Abhängigkeiten haben. Dann kann jemand, der sie anruft, leichter überlegen, was sie tun werden.

Vermeiden Sie den globalen Staat. (Variablen, Singletons usw.) Je mehr Status Sie in Ihrem Kopf haben müssen, um zu verstehen, was die Dinge tun, desto schwieriger ist es, zu verstehen, was passieren soll, und die Randfälle zu finden.

Schreiben Sie Komponententests. Unit-Tests eignen sich hervorragend zur Erfassung des tatsächlichen Verhaltens von Code, den Sie gerade geschrieben haben, anstatt des idealen Verhaltens, das Sie sich erhofft haben.

Verkürzen Sie Ihren Bearbeitungs- / Kompilierungs- / Testzyklus. Wenn Sie einen großen Teil des Codes hinzufügen und schlecht testen, besteht die Wahrscheinlichkeit, dass er sich anders verhält, als Sie denken. Dann "reparieren" Sie es mit einer zufälligen Änderung, und Sie haben die richtige Antwort für den Moment, aber keine Ahnung, wie es tatsächlich passiert ist. Sie programmieren jetzt zufällig. Aber wenn Sie 5 Zeilen addieren und dann testen, ist die Wahrscheinlichkeit, dass Sie die richtige Antwort erhalten haben, viel höher, weil es so funktioniert, wie Sie denken, dass es funktioniert. Aus Erfahrung kann ich sagen, dass 5 Blöcke mit jeweils 10 Zeilen, die einzeln getestet wurden, eine ganz andere Bestie sind als 50 Codezeilen, die alle gleichzeitig getestet wurden.

Rücksichtslos umgestalten. Oft habe ich einen Refactor entdeckt, der meinen Code etwas einfacher macht, aber eine Menge Arbeit in Anspruch nimmt, die ich nicht machen wollte. Nachdem ich damit begonnen hatte, diese Refaktoren vorrangig in Angriff zu nehmen, stellte ich fest, dass sich dies normalerweise innerhalb eines Monats auszahlt. Beachten Sie jedoch den Schlüssel, die Refaktoren, auf die ich mich konzentriere, sind diejenigen, die das tägliche Leben einfacher machen, und nicht diejenigen, die einer willkürlichen Ästhetik von besser oder allgemeiner entsprechen. Ich habe gelernt, mit diesen Refaktoren viel vorsichtiger umzugehen.

Keines dieser Dinge erfordert Vorausplanung. Sie alle machen es jedoch einfacher, Ihren vorhandenen Code zu verstehen, und machen es daher einfach, Ihren nächsten kleinen Teil absichtlich zu implementieren.

btilly
quelle
Danke, wirklich gute Antwort. Ich denke, der Teil über den Zyklus ist wirklich wertvoll. Können Sie mir Beispiele für die Umgestaltung nennen, die Sie durchführen sollten, deren Implementierung jedoch sehr lange dauern wird und die möglicherweise jemanden entmutigen?
py_script
1
Ich habe viele Beispiele. In einem C ++ - Projekt habe ich Klassen ohne Stringifizierungsmethoden erstellt. Nachdem ich diese erstellt hatte, wurde das Debuggen einfacher und die Entwicklung beschleunigte sich. In einem Perl-Projekt hatten wir einen Konfigurations-Hash, bei dem jeder Entwickler eine eigene optimierte Kopie jeder neuen Konfiguration hatte. Das Hinzufügen von Konfigurationsparametern war mühsam, da Sie die Konfiguration jedes Entwicklers bearbeiten mussten. Ich habe ein Template-System für Hashes geschrieben, und das wurde einfacher. In einem Berichtssystem habe ich eine Funktion hinzugefügt, um Zwischenergebnisse anzuzeigen. Meine Entwicklung hat sich beschleunigt, und ich habe sogar einen Benutzer-Fehlerbericht erhalten ...
btilly
1
Wo die Finanzabteilung meine Logik verfolgt und die genaue Frage gefunden hat, bei der ich einen Fehler gemacht habe und was mein Fehler war. (Ich habe versehentlich doppelte Zeilen mit den UNIONbenötigten gequetscht UNION ALL.) Und so weiter.
btilly
1
Innerhalb eines Monats? Normalerweise finde ich, dass jedes Mal , wenn ich Code berühre, der meiner Meinung nach überarbeitet werden sollte, aber noch nicht überarbeitet wurde, fast so viel Zeit benötigt wird, wie für die Überarbeitung.
Amy Blankenship
1
@AmyBlankenship Ja. Innerhalb eines Monats. Mal lächerlich drinnen, mal nicht. Die oben erwähnte Konfigurationsdatei ist ein Beispiel für "manchmal nicht". Es dauerte ein paar Tage, bis ich eine neue Template-Engine geschrieben, dokumentiert und getestet hatte. Schreiben Sie dann die vorhandene Konfiguration neu, um sie zu verwenden, und seien Sie viel kürzer, aber erzeugen Sie dieselbe exakte Datenstruktur. (Das war der schwierigste Teil des Projekts.) Also ... verschwendete Tage mit absolut keinem sichtbaren Ergebnis. Der Aufwand hat sich in knapp einem Monat ausgezahlt, ist aber seitdem auf Interesse gestoßen.
Mittwoch,
41

Es läuft ziemlich darauf hinaus, nicht zu raten . Meistens machen es neue Programmierer, aber ich habe auch Veteranen gesehen, weil sie denken, dass dies Forschungszeit spart. Etwas funktioniert nicht, also fügen Sie ein +1oder ein hinzu -1, ändern ein truein ein falseoder umgekehrt, ordnen einige Anweisungen neu an, fügen Verzögerungen hinzu oder ändern sie, ändern Thread-Prioritäten und andere kleine Transformationen, und testen im Grunde genommen zufällige Permutationen, bis es funktioniert.

Dies gilt hauptsächlich für das Ändern von vorhandenem Code, ist jedoch auch ein Faktor für brandneuen Code, da niemand wirklich von vorne anfängt. Sie bauen immer auf Standardbibliotheken, Betriebssystemen oder zumindest Prozessorarchitekturen auf.

Mit anderen Worten, Sie sind erst fertig, wenn Sie wissen, warum Ihr Fix funktioniert. Der Weg dorthin ist nicht so wichtig. Sogar zufällige Permutationen können manchmal hilfreich sein, um einen schwer zu diagnostizierenden Fehler einzugrenzen, solange Sie sich danach die Zeit nehmen, sich die Frage zu stellen: "Okay, indem Sie" true "in" false "ändern, wird der Fehler behoben, aber warum?"

Karl Bielefeldt
quelle
1
Hervorragender Punkt +1. Nirgendwo gilt dies mehr als Code-Korrekturen ...
Robbie Dee
Leider auch für mich. Um ehrlich zu sein, gibt es manchmal objektive Schwierigkeiten wie fehlende Dokumentation. Heute habe ich meinen Code ein wenig verbessert und bin auf die Tatsache gestoßen, dass ich nicht wusste, wozu ein Parameter nützlich ist, weil es an Dokumentation mangelte. Wir wissen nur, dass es eine Zahl ist.
py_script
Ich gebe zu. Wenn Sie mit dem Leaning-Toothpick-Syndrom konfrontiert sind, kann es einfacher sein, die \ s zu stapeln, bis es funktioniert, als herauszufinden, mit wie vielen Schichten der Flucht Sie es zu tun haben ...
Mittwoch,
16

Der gruseligste Kommentar, den ich jemals in einem Programm gesehen habe, war

Berühre das nicht. Es klappt. Wir wissen nicht wie oder warum, aber es funktioniert. 1

und es ist beängstigend, nur weil es anerkennt, dass das Stück Code das Ergebnis zufälliger Programmierung war .

Um ein zufälliges Programmieren zu vermeiden, sollten Sie in der Lage sein, (einem Mitarbeiter, sich selbst oder einer Gummiente ) genau zu erklären , was der Code tut und warum er funktioniert. Die Aufzählungszeichen für die absichtliche Programmierung helfen meistens dabei, das Ziel zu erreichen, den Code erklären zu können.


1 Für den Kontext wurde dieser Kommentar im Code angezeigt, der Kontextwechsel in einem primitiven Betriebssystem behandelt. Der Code war bereits seit einigen Jahren in Produktion, als ich darauf stieß.

Bart van Ingen Schenau
quelle
2
Dies wird auch als Voodoo-Huhn-Codierung bezeichnet. c2.com/cgi/wiki?VoodooChickenCoding
minusSeven
1
Selbst wenn der Kodierer glaubt, dass dies wahr ist, ist diese Art von Kommentar äußerst wenig hilfreich. Der Code mag durchaus komplex gewesen sein, aber wenn Sie den Code anders gelesen hätten, könnten Sie denken, dass er unkompliziert war. Alles, was der Kommentar tut, ist, die Paranoia zu erhöhen!
Robbie Dee
3
Dies kann auch passieren, wenn eine alte Codebasis gepflegt wird, mit der sich die meisten aktuellen Entwickler nicht besonders gut auskennen.
pcurry
Gummiente ist also nicht nur zum Debuggen. Nizza ... Ich glaube, wir arbeiten an der gleichen Firma, wir haben viele Kommentare wie diesen: P
py_script
Es gibt Situationen, in denen ein Fix nur aufgrund eines Fehlers in einer API funktioniert und es keinen besseren und logischeren Fix gibt. Das Debuggen einer kompilierten Drittanbieter-Bibliothek kann so tief wie das Kernel-Debuggen gehen. Und selbst wenn Sie das Problem gefunden haben, können Sie nach stundenlangem Debuggen nur wenig tun. Sie gehen das Problem also anders an. Sie verwenden das Black-Box-Modell, das Sie zwingt, zufällig zu programmieren. Du spielst mit dem seltsamen Verhalten der Black Box herum und wenn du es schaffst, sie so zu machen, wie du willst, füge einen Kommentar mit "Magie, berühre nicht" hinzu und mache weiter.
Radu Simionescu
7

Für neue Programmierer besteht der wichtigste Teil der Überwindung darin, zu verstehen, was sie tun.

Wenn Sie in vielen Bereichen nicht wissen, wie etwas zu tun ist, gehen Sie einfach durch Ausprobieren vor. Versuche etwas; Wenn es funktioniert, großartig, wenn nicht, probieren Sie etwas anderes.

In der Programmierung funktioniert dieser Ansatz einfach nicht, insbesondere wenn eine Sprache verwendet wird, die das Konzept eines undefinierten Verhaltens aufweist (wie C oder C ++), da Erfolg keine boolesche Entscheidung mehr ist. Sie können Dinge haben, die "irgendwie" funktionieren, die manchmal funktionieren, die für einige Eingaben funktionieren, aber für andere nicht.

Ich habe gelegentlich neue Programmierer unterrichtet und die Tendenz, zufällige Dinge zu tippen, um zu sehen, ob es funktioniert, ist weit verbreitet. Sie tippten eine Zeile, wandten sich dann an mich und fragten: "Würde es so funktionieren?" während es klar war, dass sie absolut keine Ahnung hatten, ob es könnte.

Die Erkenntnis ist, dass Sie als neuer Programmierer wirklich erklären müssen, was Ihr Code tut. Sie müssen lernen, Code zu lesen, nicht nur zu schreiben.

(Das gilt natürlich auch für erfahrene Programmierer, aber ich habe hier hauptsächlich Erfahrungen mit Anfängern gesammelt.)

Sebastian Redl
quelle
<< Sie müssen lernen, Code zu lesen, nicht nur zu schreiben. >> Glauben Sie also, dass es mir bei meiner ersten Frage helfen wird, Funktionen für Open Source-Projekte hinzuzufügen?
py_script
2

Es ist viel zu einfach, "on the racing line" zu codieren, zu testen und zu reparieren. Sie haben einige Funktionen, die bei X & Y Z erzeugen. Aber was ist, wenn X beschädigt und Y nicht verfügbar ist? Was ist, wenn Sie Z nicht ausgeben können? Denken Sie stets daran, was schief gehen kann, und notieren Sie dies für den Testzyklus.

Halten Sie Ihre Routinen kurz und beschreibend - der beste Code erfordert nur wenige (wenn überhaupt) Kommentare.

Sinnvolle Methoden-, Klassen- und Variablennamen tragen wesentlich zur besseren Lesbarkeit bei.

Wenn Sie auf einen Codegeruch stoßen, hören Sie auf. Es ist unwahrscheinlich, dass dieser Geruch verschwindet und ein wenig Anstrengung könnte Ihnen später eine Menge Kummer ersparen.

Schließen Sie das Testen in Ihren Entwicklungsprozess ein. Ich würde die Verwendung von BDD anstelle von TDD befürworten, da dies Sie dazu zwingt, zu beschreiben, was Sie erreichen möchten, anstatt sich blind auf eine Reihe von Tests zu verlassen, die Ihnen ein falsches Sicherheitsgefühl vermitteln könnten.

Widerstehen Sie dem Drang, zusätzliche coole Funktionen hinzuzufügen (es sei denn, es ist Ihr eigenes Lieblingsprojekt). Jeder zusätzliche Code muss entworfen, geschrieben, getestet und gewartet werden. Wenn es vom Kunden / Unternehmen nicht benötigt wird, besteht die Gefahr, dass dies zu einer enormen Belastung Ihrer Ressourcen führt.

Robbie Dee
quelle