3 Punkte von GN⁺ 5 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • YAGNI ist keine einfache Sparregel im Sinne von „Schreibe keinen Code, den du noch nicht brauchst“, sondern ein Prinzip, das die Kosten behandelt, wenn man auf Basis von Vermutungen Struktur vorwegnimmt, bevor der Bedarf feststeht
  • Im Zentrum des Problems steht nicht Design an sich, sondern wann man designt; zu frühe Strukturierung kann genauso riskant sein wie zu späte Strukturierung
  • Vorab geschaffene Struktur erzeugt zugleich Optionskosten, weil sie Wahlmöglichkeiten schließt, bevor Informationen vorliegen, und NPV-Kosten, weil sie Kosten vorzieht und Erträge verzögert
  • Selbst wenn die Kosten der Codegenerierung nahezu gegen null gehen, verschwindet YAGNI nicht; im Gegenteil kann billige Generierung vermutungsbasierte Frameworks noch leichter entstehen lassen
  • Die Schlussfolgerung „Baue es, wenn du es brauchst“ liegt nicht an den Kosten des Codeschreibens, sondern daran, dass ungenutzte Optionen und ungenutztes Geld weiterhin Wert haben

YAGNI verbietet Design nicht

  • YAGNI steht für „You Aren’t Gonna Need It“ und ist keine Ausrede dafür, niemals etwas zu entwerfen, das man gerade nicht braucht
  • Wenn etwas gebraucht wird, kann man es bauen; entscheidend ist jedoch das Timing
  • Ausgangspunkt ist die oft erzählte Situation in einem Projekt: „In drei Wochen wird die einfache Implementierung nicht mehr reichen, also möchte ich jetzt etwas Komplexeres bauen“ – worauf wiederholt die Antwort „You aren’t going to need it“ kam
  • Dieses Prinzip betrachtet sowohl zu frühes als auch zu spätes Schaffen von Struktur als riskant

Das Problem sind nicht die Kosten des Codeschreibens, sondern vermutungsbasierte Struktur

  • Eine verbreitete Interpretation sieht YAGNI als Sparregel: „Noch nicht benötigter Code ist teuer, also schreibe ihn nicht“
  • Doch YAGNI zielt nicht auf die Kosten der Codeproduktion, sondern auf spekulative Struktur (speculative structure), die geschaffen wird, bevor echte Features sie benötigen
  • Eine solche Struktur verursacht zu unterschiedlichen Zeiten und aus unterschiedlichen Gründen zwei Arten von Kosten

Erste Kostenart: Optionen

  • Wenn man Struktur baut, bevor das Feature eintrifft, committet man sich auf Grundlage von Vermutungen gegenüber Anforderungen, die man noch nicht kennt
  • Die im Voraus vorbereitete Funktion unterscheidet sich meist von der Funktion, die tatsächlich kommt; dadurch zahlt man doppelt
    • die Kosten, um eine Struktur in der falschen Form zu umgehen
    • die Kosten, um diese Struktur wieder herauszureißen
  • Dieses Problem erschöpft sich nicht in der Aussage „Vorhersagen sind schwierig“
  • Selbst wenn die Vermutung stimmt, bleibt ein Verlust, weil man die Option verliert, sich nicht vorab festzulegen und später die richtige Struktur zu bauen
  • Warten ist keine Faulheit, sondern das Halten eines Vermögenswerts namens Option

Zweite Kostenart: NPV

  • So wie Geld einen Zeitwert hat, haben auch Features einen Zeitwert
  • Wenn man jetzt Struktur für ein Feature baut, das erst in drei Monaten gebraucht wird, werden Kosten vorgezogen und der Launch des Features, das tatsächlich Geld verdient, verzögert
  • Diese Kosten entstehen selbst dann, wenn die Vermutung stimmt
  • Auch perfekte Vorhersage kann die Reihenfolge von Kosten und Erträgen nicht ändern; der Verlust entsteht aus dem Abstand, in dem Kosten vor Erträge gestellt werden
  • Optionskosten betreffen das Problem „Committe dich nicht, bevor die Information vorliegt“, NPV-Kosten das Problem „Zahle nicht, bevor es nötig ist“
  • Selbst beim Einwand „Späteres Ändern ist zu teuer“ kann genau dieser teure Umbau wiederum eine Vorhersage sein

Auch wenn Codegenerierung billig wird, bleibt YAGNI

  • In keiner der beiden Kostenarten sind die Kosten für das Tippen von Code enthalten
  • Wenn die Kosten des Codeschreibens nahezu gegen null gehen, bricht die sparorientierte Interpretation von YAGNI – „Code ist billig geworden, also kann man ihn vorab bauen“ – zusammen
  • Da YAGNI jedoch keine Sparregel ist, macht billige Codegenerierung YAGNI nicht überflüssig
  • Optionskosten entstehen nicht durch die Menge an Aufwand, sondern durch das Commitment, das künftige Wahlmöglichkeiten schließt
  • NPV-Kosten entstehen nicht durch den Produktionspreis, sondern durch das Timing der Cashflows
  • Kostenlose Generierung schwächt YAGNI nicht, sondern erleichtert eher den Bau vermutungsbasierter Frameworks
  • Die generierte Struktur verursacht weiterhin beide Kosten, und weil man sie nicht selbst geschrieben hat, kann das Verständnis dafür sogar geringer sein
  • Die Schlussfolgerung lautet nicht „Warte, weil Code teuer ist“, sondern: Baue es, wenn du es brauchst, weil Optionen und Geld wertvoller sind, solange sie nicht ausgegeben wurden

1 Kommentare

 
GN⁺ 5 시간 전
Hacker-News-Meinungen
  • Ich denke, auch die Kosten für Strukturänderungen sind gesunken
    Dank AI sind die Kosten gesunken, vor einer Strukturänderung das Verhalten durch Tests abzusichern, und auch die Kosten für die Umsetzung von Migrationen ohne Downtime sind niedriger geworden
    Einer der großen Gründe, warum Rust schon vor AI Aufmerksamkeit bekam, war ebenfalls, dass die Kosten für Änderungen an der internen Struktur einer Anwendung niedrig sind, und jetzt gilt das umso mehr
    Die Opportunitätskosten, wenn man Strukturen nicht sicher ändern kann, sind stark gestiegen, und aktuell optimiere ich vor allem auf die Fähigkeit, große Teile von Code und Produkt schnell und sicher ändern zu können

    • Die Fähigkeit, große Teile von Code und Produkt schnell und sicher ändern zu können, war schon immer gut und hatte unabhängig vom Aufkommen von AI Coding einen Wert
      Allerdings dauerten Strukturänderungen vor AI viel länger, daher könnte man auch sagen, dass der Wert dessen, worauf man jetzt optimiert, eher gesunken ist
      Es ist weiterhin wertvoll, aber vielleicht etwas weniger als früher
    • Dem kann ich nur schwer zustimmen
      Mit der Zunahme von fragilen, AI-generierten Tests sind die Kosten für Strukturänderungen höher geworden als früher
      Eine Testsuite aufzuräumen, damit sie den Kern des Problems prüft und nicht zufällige Designentscheidungen, ist etwas, worin AI noch nicht gut ist
    • Stimmt
      Aber es ist auch viel zu einfach, stattdessen eine ungefähr zu 75 % ausgereifte fragile Testsuite zu bekommen
      Viele Leute sind zufrieden damit und betrachten den Schritt von „ein paar mittelmäßigen, fragilen Tests, die Menschen geschrieben haben“ zu „vielen mittelmäßigen, fragilen Tests, die AI geschrieben hat“ als objektive Verbesserung
      Ich stimme völlig zu, dass man Tools so nutzen sollte, aber daraus folgt schwerlich, dass man sich keine Sorgen machen muss, zu früh ein falsches Luftschloss zu bauen
      Einen perfekten Testvertrag zu entwerfen, der Refactorings standhält, bleibt ziemlich schwierig
    • Das erinnert an das Open-Closed-Principle: „offen für Erweiterung, geschlossen für Änderung“
      Altes kommt also wieder wie neu zurück
      Von der kontextuellen Effizienz von Ansätzen wie DDD oder Clean Architecture bis hin zu solchen Punkten: AI schafft keine neuen Kompromisse, sondern wirkt wie ein Verstärker
      Sie steigert die Produktivität von Teams, die es richtig machen, und vergrößert zugleich die Schulden von Teams mit niedrigen Qualitätsmaßstäben bei Design und Architektur
    • Es sieht so aus, als würde man immer mehr Herumgepfusche betreiben und darauf wetten, dass AI es schon reparieren wird
      Der einzige Gewinn ist, dass man nicht tief nachdenken muss
      Tiefes Nachdenken kostet aber gar nicht so viel Zeit oder Mühe; man wird also von Leuten überholt werden, die AI genauso einsetzen, aber genug nachdenken, damit es nicht zu Herumgepfusche wird
  • Kent Beck vergleicht Code, den man noch nicht geschrieben hat, mit einer Finanzoption, die man zu einem bestimmten Preis kaufen kann
    Aber das ist eben nur eine Metapher, und wenn man sie zu weit treibt, wird es seltsam
    Hat man unendlich viele Optionen, wenn man noch gar keinen Code geschrieben hat? Auch wenn man noch keine Zeit investiert hat, scheint das nicht zu stimmen
    Es könnte auch als Begründung dienen, in der Planungsphase zu bleiben und das Schreiben von Code unbegrenzt aufzuschieben, um nichts festzulegen
    Wenn die Metapher dennoch funktioniert, könnten die Kosten im Lesen von Code liegen
    Nicht geschriebener Code muss nicht gelesen werden, und wenn man Coding Agents einsetzt, verschmutzt er den Kontext auch nicht mit irrelevanten Details
    Code, den man noch nicht geschrieben hat, muss man auch nicht testen, und Tests, die man noch nicht geschrieben hat, kosten auch keine Laufzeit
    Deshalb ist es gut, ein Projekt so klein wie möglich zu halten; wenn man Features aufschiebt, kann man das Wachstum der Codebasis maximal verlangsamen
    Das bedeutet auch, dass man viele Kosten vermeiden kann, wenn man fremden Code ausführt
    Wenn man eine Standard-API nutzen kann, muss man die Implementierung nicht im Detail verstehen oder deren Tests ausführen, aber das Hinzufügen von Abhängigkeiten birgt Risiken

    • In Kents „Tidy, First?“ wird Software so verstanden, dass sie auf zwei Arten Wert schafft: durch das, was man heute tut, und durch die Möglichkeit, morgen etwas Neues tun zu können
      Nicht geschriebener Code hat keinen Wert
      Damit Code, der heute geschrieben wird, Wert schafft, muss er die heutige Anfrage oder das heutige Issue lösen oder darauf ausgerichtet sein, morgen etwas leichter zu machen
      Wenn man mit einer hackigen Lösung technische Schulden aufnimmt oder Zeit auf etwas verschwendet, das YAGNI widerspricht, schafft man keinen Wert
      Entscheidend ist nicht der nicht geschriebene Code, sondern der Code, den man künftig schreiben wird, und dessen Zweck
      Man muss den richtigen Kompromiss finden zwischen dem Erledigen des heutigen Tickets bzw. To-dos und dem Vermeiden, sich künftig selbst ins Bein zu schießen
      Code zu schreiben ist eine Verpflichtung; der heutige Wert ist sichtbar, der morgige Wert aber eher eine Schätzung
      Trotzdem fallen später immer Kosten an, also schätzt man, was gebraucht werden könnte, um die Kosten zu minimieren
  • Ich finde, dass Best Practices im AI-Zeitalter nicht genug betont werden, aber Kent übersieht hier etwas vollständig
    Es hat erheblichen Wert, schneller herauszufinden, welche Funktionalität benötigt wird
    Eine spekulative Struktur zu bauen, kann ein Zwangsmechanismus sein, der Anforderungen konkretisiert, und zumindest beginnt er, Fehlermuster sichtbar zu machen
    Das kann teurer sein als abzuwarten, daher sollte man das bei den meisten Anforderungen nicht tun, aber manchmal kann es die beste Wahl sein
    Die Kosten, etwas Falsches zu bauen, sind jetzt viel niedriger, und dadurch ändert sich auch die Rechnung rund um YAGNI
    Trotzdem muss man weiterhin rechnen, und derzeit muss jedes Team selbst herausfinden, wie sich das für es verändert hat

    • Wenn man die spekulative Struktur als Spike baut und anschließend wegwirft, ist das in Ordnung
      Wenn man sie nicht wegwirft, wird sie zu einem Zwangsmechanismus für ein schmutziges Ergebnis
    • Meiner Ansicht nach ergeben sich benötigte Funktionen bereits aus den Anforderungen und dem Systemdesign, das diese Anforderungen erfüllen soll
      Bei YAGNI geht es um das Problem, Dinge zu bauen, die nicht in den aktuellen Anforderungen enthalten sind, weil man erwartet, dass sich die Anforderungen später ändern
      Das ist etwas anderes, als aktuelle Anforderungen und Einschränkungen zu konkretisieren
      Solche Dinge entstehen vor allem aus Gesprächen mit Stakeholdern, Nutzern und Kunden sowie aus Ressourcen, technischen Einschränkungen und Fähigkeiten
      Prototypen sind wertvoll, wenn man mit Stakeholdern spricht, ein Projektmanagement-Modell erstellt oder Engineering-Forschung betreibt
      Alles andere stellt Ursache und Wirkung auf den Kopf
  • Der Ansatz, laufende Software als Asset zu betrachten, ist richtig
    Allerdings sind die Kosten für das Ausführen und erneute Erstellen deutlich gesunken
    Nicht gesunken sind die Kosten dafür, die Vertrauenskette in vorhersagbare Ergebnisse zu brechen
    Eine bestimmte Version laufender Software hat Vertrauen aufgebaut; wenn man sie von Grund auf neu schreibt, wird dieses Kapital beim Release zurückgesetzt

  • Irgendwann hat sich meine Sichtweise geändert
    Ich verschiebe Konkretes mit YAGNI und schreibe, soweit möglich, eine abstrakte Version
    Soll ich einen UserStore bauen? Das wirkt am einfachsten, aber vielleicht brauche ich gar keine konkrete Form namens User
    Also baue ich einen Store, der alles aufnehmen kann, was speicherbar ist
    Wenn man das nicht gewohnt ist, sieht es nach Overengineering und Generics-Wildwuchs aus, aber paradoxerweise ist es die Art, die sich am wenigsten auf irgendeine konkrete Implementierung festlegt

    • Es sieht tatsächlich genau nach Overengineering und Generics-Wildwuchs aus
      Man hat nicht nur ein UserStore-Interface gebaut, das vermutlich nicht nötig war, sondern auch noch eine verallgemeinerte Store-Abstraktion, die ganz sicher nicht nötig war
      Um sich nicht auf eine konkrete Implementierung festzulegen, hat man klebrige Schichten implementiert, die nicht nötig sind und sehr wahrscheinlich auch künftig nicht nötig sein werden
      Wenn eine Abstraktion nicht auf einem tatsächlichen Bedarf basiert, ist sie, selbst wenn sie später nötig wird, höchstwahrscheinlich fast falsch gebaut
      Am Ende wird man UserStore ohnehin brauchen, also hätte man damit anfangen sollen
  • Ich stimme nicht zu, dass „das Argument nicht lautet, Vorhersagen seien schwierig, als ob ein schärferer Architekt das vermeiden könnte“
    Dieses Argument funktioniert nur unter der Prämisse, dass Vorhersagen schwierig sind

    • Auch „selbst wenn man richtig rät, ist es schlechter, als sich nicht festgelegt zu haben“ ist verwirrend
      Wenn man eine sehr wahrscheinliche Funktion im Voraus vorbereitet und alles zusammenpasst, liefert man schneller aus
      Es gibt auch keine Garantie, dass das Team zwangsläufig wächst oder die Besetzung gleich bleibt; kurz vor der Deadline hektisch YAGNI nachzuholen fühlt sich schlimmer an, als Selbstbeschränkung zu feiern
  • Kürzlich musste ich funktional aus einer Codebase herauskommen, in der sich sehr viel YAGNI angesammelt hatte, und selbst mit Agents war das eine riesige Arbeit
    Wie weiß man in einem verteilten System, was wirklich in Benutzung ist? Ich habe Dinge übersehen, der Agent hat Dinge übersehen, und insgesamt dauerte es viel länger als nötig
    Es war auch kein bloßes 1:1-Porting, sondern sollte eine Gelegenheit zur Vereinfachung sein, deshalb musste ich vollständig verstehen, wie das alte System funktioniert
    Auch Dinge, die tatsächlich überhaupt nicht genutzt wurden, gehörten zum Verständnisumfang, wenn man sie nicht als solche identifizieren konnte

  • Am Ende läuft es meiner Ansicht nach darauf hinaus, Probleme zu erkunden und Lösungen zu implementieren
    Das falsche Problem zu lösen hat immer Kosten, und es kostet auch, eine schlechte Lösung für etwas zu implementieren, das gar nicht nötig ist
    Softwareentwicklung kann manchmal zu bloßem Trial and Error werden, statt über Strategien zur Erkundung und über die Menge der Probleme nachzudenken
    Es gibt Fälle, in denen es langfristig hilft, ein Problem in eine bestimmte Richtung tiefer zu erkunden, als unmittelbar nötig wäre; aber ziellos Lösungen zu implementieren ist nie gut
    Ich denke, was Kent Beck wirklich kritisiert, ist die Haltung, „für den Fall der Fälle“ etwas zu implementieren, nur weil es in Zukunft vielleicht nötig sein könnte

  • Es hieß: „Wenn man Struktur baut, bevor die Funktion kommt, legt man sich auf eine Vermutung fest“, aber ich denke, in beiden Fällen stellt man Vermutungen an
    Die Wahrscheinlichkeit, dass die Funktion kommt, kann hoch sein, aber sicher ist sie nicht
    Wenn man die Struktur jetzt nicht baut, entstehen Refactoring-Kosten; baut man sie zu früh und die Funktion kommt nicht, verschwendet man Aufwand
    Wie sehen Kosten, Wahrscheinlichkeiten und Trade-offs zwischen diesen Möglichkeiten aus? Das hängt natürlich von der Situation ab
    YAGNI als Ganzes ist absichtlich eine starke Verallgemeinerung
    Letztlich kommt es auf die Umstände an
    In beiden Richtungen gibt es oft viele Vermutungen und vage Handwedelei, ähnlich wie bei verlässlichen Aufwandsschätzungen
    Manche Entwickler, die mit einer unsicheren Welt schlecht zurechtkommen, suchen für alles nach Schwarz-Weiß-Regeln

  • Ich habe in Kent Becks Texten noch nie etwas gesehen, das für eine Chipfirma nützlich wäre
    In Chipfirmen müssen viele Menschen über lange Zeit arbeiten, Kunden können bis zur Fertigstellung nichts sehen, und um Geld zu verdienen, muss man in Stückzahlen von Millionen verkaufen

    • Ist er nicht jemand, der Software baut und über Softwareentwicklung schreibt?
      Hardware hat starke Einschränkungen
      Software wurde ursprünglich genau deshalb erfunden, um solchen Einschränkungen zu entkommen
    • Dass Kunden vor der Fertigstellung absolut nichts sehen können, stimmt nicht unbedingt
      Es stimmt wohl, dass viele Chipfirmen ihre laufende Arbeit nicht teilen, aber Simulationen, Prototypen und Engineering Samples zu teilen ist möglich und passiert auch tatsächlich
      Natürlich muss man dafür normalerweise ein großer Kunde sein
      Erkenntnisse aus einer Branche, in der Änderungskosten vergleichsweise niedrig sind, lassen sich nicht einfach auf Branchen mit hohen Änderungskosten übertragen, und umgekehrt gilt das oft genauso
    • Interessant
      Wie planen Chipfirmen solche Projekte? Agile, Wasserfall, oder nutzen sie ein anderes Framework als die Softwarebranche?