52 Punkte von GN⁺ 2025-02-06 | 6 Kommentare | Auf WhatsApp teilen
  • Erfahrene Entwickler teilen mit Berufseinsteigern ihre Philosophie der Softwareentwicklung
  • Enthält Ratschläge zu vielen Themen, darunter das Vermeiden eines vollständigen Neuschreibens (ground-up rewrite), Zeitplanung, Code-Qualität, Automatisierung und der Umgang mit Edge Cases

Vermeide um jeden Preis Situationen, in denen ein vollständiges Neuschreiben (ground-up rewrite) attraktiv erscheint

  • Die Versuchung eines vollständigen Neuschreibens entsteht in dem Moment, in dem die aufgelaufene technische Schuld die Wartung des bestehenden Codes bereits erschwert
  • Warnsignale bei zunehmender Code-Komplexität sollten früh erkannt und aktiv angegangen werden, etwa wenn selbst einfache Änderungen schwierig werden, Kommentare oder Dokumentation schwer zu verfassen sind oder immer weniger Menschen den Kerncode verstehen
  • Nach einer Erweiterungsphase sollte unbedingt eine Integrationsphase folgen, in der die Komplexität reduziert und die Qualität bereinigt wird
  • Wenn ein vollständiges Neuschreiben unvermeidlich wird, bedeutet das, dass das Projekt bereits eine Gefahrenstufe erreicht hat
  • Um das Risiko zu verringern, müssen technische Schulden kontinuierlich verwaltet und die Code-Qualität aufmerksam überwacht werden

Erledige 90 % der gesamten Arbeit in der Hälfte der verfügbaren Zeit

  • Den Code in einer ersten Version zu schreiben und zum Laufen zu bringen, entspricht nur etwa der Hälfte der Gesamtarbeit
  • Für die nachfolgenden Schritte — Behandlung von Edge Cases, Tests, Deployment, Dokumentation, Performance, Wartbarkeit usw. — wird deutlich mehr Zeit benötigt, als man oft denkt
  • Man sollte ausreichend Puffer einplanen, um auf unerwartete Probleme oder Abschlussarbeiten beim Polishing reagieren zu können
  • Letztlich muss man die Lücke zwischen „den ersten Code irgendwie zum Laufen bringen“ und „eine fertige Funktion bereitstellen“ erkennen und in den Zeitplan einbeziehen

Automatisiere Best Practices

  • Wenn man Entwicklern nur wiederholt mündlich oder in Dokumenten sagt „So muss es gemacht werden“, passieren leicht Fehler
  • Wenn möglich, ist es wirksamer, Regeln per automatisierten Tests oder Skripten durchzusetzen, zum Beispiel in der Form „Bei Regelverstoß schlägt der Build fehl“
  • Auch neu eingeführte Regeln — etwa verbotene APIs oder verpflichtende Kommentare — können schrittweise automatisiert werden, um Fehler und Auslassungen zu verringern
  • Allerdings lässt sich nicht alles automatisieren, und zu strenge Regeln können den Entwicklungsfluss behindern; es braucht also Balance

Berücksichtige auch extreme (pathological) Daten

  • Es ist riskant, Code nur anhand normaler Eingaben (golden path) zu beurteilen
  • Man sollte Problemfälle mitdenken, etwa verzögerte oder unterbrochene Requests, riesige Datenmengen (Hunderttausende bis Hunderte Millionen Zeilen) oder merkwürdige Strings (sehr lang, mit Schrägstrichen oder Leerzeichen)
  • Wie gründlich man auf Edge Cases vorbereitet ist, entscheidet letztlich über die Code-Qualität

Meist gibt es einen einfacheren Weg, es zu schreiben

  • Nachdem der Code zunächst funktionsfähig gemacht wurde, ist es gut, ihn mit etwas zeitlichem Abstand noch einmal einfacher und klarer zu überarbeiten
  • Selbst wenn man bereits eine „gut aussehende Lösung“ gefunden hat, ist die Haltung wichtig, sich noch einmal Zeit zu nehmen und zu prüfen, ob es nicht eine bessere gibt
  • Das Refactoring langer und komplexer Codes in eine prägnantere Form erhöht die endgültige Qualität

Schreibe Code so, dass er testbar ist

  • Wenn Schnittstellen und Side Effects minimiert werden, wird das Schreiben automatisierter Tests deutlich einfacher
  • Wenn eine Struktur schwer zu testen ist, ist die Wahrscheinlichkeit groß, dass die Kapselung nicht richtig gelungen ist
  • Wenn die Code-Struktur konkret auf gute Testbarkeit ausgelegt wird, lassen sich Bugs frühzeitig entdecken

Nur weil ein Code „beweisbar“ kein Problem hat, ist er noch nicht fertig

  • Auch Code, der strukturell sicher wirkt, kann Probleme bekommen, wenn sich das Umfeld ändert oder bestimmte Aufrufarten angepasst werden
  • Bei sicherheitsrelevantem Code sollte man selbst dann so entwerfen, wenn die aktuellen Aufrufstellen sicher sind, dass künftige Änderungen berücksichtigt werden
  • Code sollte so geschrieben werden, dass er „offensichtlich sicher ist und auch bei Änderungen kein Problem verursacht“

Kommentare

  • Die Quelle des Satzes „Ich konnte diesen Brief nicht kürzer schreiben, weil ich keine Zeit hatte, ihn kürzer zu schreiben“ ist Pascal
  • Achte immer auf Off-by-one-Fehler (off-by-one error)
  • Eine neue Richtlinie im Wiki ergänzen
    • Wenn Dokumentation und Wissensaustausch im Unternehmen nicht sauber organisiert sind, verstreuen sich Informationen und führen zu Verwirrung
    • Es kommt vor, dass offizielle Dokumente durch Freigabeprozesse veralten oder mehrere Wikis parallel existieren und niemand weiß, welches die maßgebliche Quelle ist
    • Es ist sinnvoll, genau ein Wiki festzulegen und dort alle Materialien zu sammeln; fehlende Teile können Entwickler direkt schreiben oder per Reverse Engineering ergänzen
    • Wenn die Dokumentation gut mit anderen Orten verbunden ist, etwa Source Control oder Code-Kommentaren, ist es leichter, aktuelle Informationen zu erhalten
    • Wenn automatisierte Tests und die Build-Umgebung komplex sind oder Entwicklern nicht offen zugänglich gemacht werden, kann es passieren, dass niemand jemals selbst den kompletten Testlauf ausgeführt hat
    • Jenkins-Build-Skripte sollten einfach gehalten werden, etwa in der Form cd project; ./build-it; auch dieses Skript selbst sollte in Source Control liegen
    • Wenn das gesamte Team dieselbe Umgebung für Build und Tests gemeinsam nutzen kann, etwa ein Virtual-Machine-Image oder gemeinsame Build-Einstellungen, lassen sich Probleme im Vorfeld reduzieren
    • Es ist hilfreich, Edge Cases schon in der Entwicklung zu berücksichtigen, sodass etwa destroy_object(foo) auch dann sicher funktioniert, wenn foo NULL ist, oder destroy_object() bei einem Fehlschlag von create_object() intern aufgerufen wird
    • Letztlich ist entscheidend, dass alle Entwickler leicht auf Dokumentation sowie Build-/Test-Umgebung zugreifen und sich daran beteiligen können
  • Dokumentation und automatisierte Tests: Es wird die praktische Empfehlung erwähnt, dass Dokumente oder Wikis für den Wissensaustausch wichtig sind und dass Konfigurationen von CI/CD-Umgebungen wie Jenkins gemeinsam nutzbar sein sollten
  • Es gibt kein wirksameres Mittel zur Verhaltensänderung, als Menschen „Unannehmlichkeiten zu bereiten“, bis sie sich das gewünschte Verhalten eingeprägt haben
  • So wie es auch Gegenpositionen zu der Schachweisheit „Wenn du einen guten Zug siehst, führe ihn sofort aus“ gibt, hat auch das Programmieren diese Doppelseitigkeit.

6 Kommentare

 
bbulbum 2025-02-07

Üblicherweise gibt es eine Möglichkeit, es noch einfacher zu schreiben.

Ich glaube, dass das Nachdenken über eine prägnantere Lösung die Komplexität von Code und Richtlinien verringert.

 
kipsong133 2025-02-06

> „90 % der gesamten Arbeit in der Hälfte der verfügbaren Zeit abschließen“

Ich finde, das trifft wirklich zu. Statt etwas in einem Durchgang perfekt umsetzen zu wollen, hilft es, schnell ein zweites Mal daraufzuschauen – so passieren weniger Fehler und auch das Zeitmanagement funktioniert besser.

 
jhj0517 2025-02-06
  1. Automatisierung bewährter Praktiken (Testcode, CI/CD-Pipeline)
  2. Es ist gut, den Code zunächst lauffähig zu machen und ihn dann mit etwas zeitlichem Abstand erneut einfacher und klarer zu verbessern.
  3. Situationen, in denen ein vollständiges Neuschreiben (ground-up rewrite) attraktiv erscheint, sollten unter allen Umständen vermieden werden
 
winterjung 2025-02-06

> Achte immer auf Off-by-one-Fehler

Ich habe mich gefragt, was ein Off-by-one-Fehler ist, und es handelt sich offenbar um eine Fehlerklasse im Zusammenhang mit Grenzbedingungen wie for (int i = 1; i < n; ++i) { ... }, for (int i = 0; i <= n; ++i) { ... }.

 
ethanhur 2025-02-06

> Vermeide Situationen, in denen ein kompletter Neuschreib von Grund auf – um jeden Preis – attraktiv erscheint.

Ich denke, das ist eine der Fallstricke, durch die sich das Geschäft vieler IT-Unternehmen nicht weiterentwickelt, und wenn sich in einem Zustand mit viel Technical Debt eine Engineering-Organisation damit nicht auseinandersetzen kann (oder will), dann erscheint ihr ein vollständiger Rewrite attraktiv.

Ich stimme den Autoren sehr zu, dass man einen Rewrite so weit wie möglich vermeiden sollte, wenn es keinen wirklich überzeugenden Grund dafür gibt.

 
GN⁺ 2025-02-06
Hacker-News-Kommentare
  • Softwareentwicklung ist ein wiederholender Prozess aus Ausprobieren und Lernen. Erfahrene Entwickler vertiefen ihr Verständnis durch das Schreiben und Testen von Code und lernen dabei viel, doch das zeigt sich in Meetings oder Planungen oft kaum. Junior-Entwickler tun sich schwer damit, produktionsreifen Code zu liefern, und scheuen sich vor Arbeit, die später verworfen wird. Wenn Managern Entwicklungserfahrung fehlt, kann das diese Probleme verschärfen

  • Das Zitat „Ich entschuldige mich für den langen Brief, aber ich hatte keine Zeit, einen kurzen zu schreiben“ wird dem französischen Mathematiker und Philosophen Blaise Pascal zugeschrieben und bedeutet, dass es schwieriger ist, kurz zu schreiben

  • Die 90/50-Regel betont, wie wichtig Tests und Exception-Handling sind, um die Codequalität zu verbessern. Das Einrichten automatisierter Tests hilft dabei, klare Erwartungen an die Codebasis festzulegen

  • In der Informatikausbildung wird oft dazu angeregt, komplexen Code zu schreiben, doch wichtiger ist es, gut lesbaren Code zu verfassen. Dafür braucht es die Benennung von Variablen und Funktionen, konsistente Formatierung und modulares Design

  • Ein Mechanismus namens Ratchet bietet eine perfekte Methode für die Zukunft

  • Der Versuch, Erfahrung und Domänenverständnis zu verallgemeinern, kann zu fehlerhaften Verallgemeinerungen führen. Entwicklung ist die Kunst, Komplexität zu beherrschen, und es ist wichtig, aus Fehlern zu lernen

  • Das Zitat „Die ersten 90 % der Arbeit beanspruchen 90 % der Zeit, und die restlichen 10 % beanspruchen weitere 90 % der Zeit“ beschreibt die Realität der Entwicklung sehr gut. Wenn man Exception-Handling, Fehler, Benutzerfreundlichkeit und Sicherheit berücksichtigt, entsteht viel unerwartete Arbeit

  • Joel Spolskys Text warnt vor den Risiken von Neuschreibungen und betont die Weisheit von DevOps

  • Die Lesbarkeit von Code sollte optimiert werden, und man sollte erkennen, dass die Kosten steigen, je länger es dauert, bis ein Bug entdeckt wird. Es ist vorteilhaft, funktionale Programmierprinzipien zu bevorzugen und ein starkes Typsystem zu verwenden