De-slop: Generierten Code von einem sorgfältigen Menschen nicht unterscheidbar machen
Slop ist kein Stilproblem, sondern ein Vertrauensproblem. Prüfer, die einen Slop entdecken, hören auf, den Code zu lesen, und beginnen, nach weiteren zu suchen. Die Behebung ist niemals rein kosmetisch: Jeder untenstehende Durchgang verifiziert Notwendigkeit, nicht nur Aussehen.
Arbeite vom tatsächlichen Diff, niemals aus der Erinnerung an das, was du geschrieben hast. Wenn die Arbeit mehrere Branches umfasst, prüfe jeden Branch-Diff gegen seine Merge-Basis.
Durchgang 0 — Klein schreiben, jede Zeile rechtfertigen (Vorbeugung ist besser als Nachreinigung)
Slop ist am günstigsten zu entfernen, bevor er entsteht. Beim Erstellen:
- Baue Stück für Stück. Beginne mit der kleinsten Änderung, die eine Sache tut; mache sie korrekt und idiomatisch, bevor du das nächste Stück hinzufügst. Ein großer Diff, der in einem Zug geschrieben wird, zieht immer Slop an; N kleine Inkremente, die jeweils gegen diesen Skill überprüft werden, tun das nicht. Das erzeugt auch kleine PRs, die Prüfer durchweg schneller vertrauen und genehmigen als einen großen.
- Hinterfrage jede Zeile zum Zeitpunkt der Erstellung: Warum existiert diese Zeile? Warum ist dies eine neue Funktion anstelle eines Aufrufs einer bestehenden? Warum eine neue Datei? Wenn die Antwort „Der Generierungsfluss war so“ lautet, lösche oder falte sie. Jede Hinzufügung benötigt einen Grund, den du in einer Überprüfung laut aussprechen könntest.
- Überkompliziere nicht. Die offensichtliche 5-Zeilen-Version schlägt die abstrahierte 25-Zeilen-Version, bis ein zweiter Aufrufer existiert. Keine spekulativen Parameter, keine „für zukünftige Flexibilität“, keine Wrapper-Typen um einen einzelnen Wert.
- Erfinde das Rad nicht neu — zum Zeitpunkt des Erstellens, nicht nur beim Aufräumen: Bevor du eine Hilfsfunktion schreibst, durchsuche das Repository nach einem vorhandenen Helfer und prüfe den Abhängigkeitsbaum auf ein Paket, dem das Problem gehört (siehe Durchgang 2).
- Passe dich der Nachbarschaft an, bevor du schreibst. Lies zuerst die benachbarten Dateien; übernehme deren Namensgebung, Fehlerbehandlung und Test-Harness, damit der neue Code so aussieht, als wäre er schon immer da gewesen.
Wenn die Aufgabe nicht Stück für Stück erstellt werden kann (ein großer Port, ein vertraglich festgelegtes Vendor-Paket), sage dies und kompensiere mit einer strengeren Prüfung der Durchgänge 1–5, bevor irgendjemand anderes sie sieht.
Durchgang 1 — Kommentare
Das mit Abstand größte Erkennungsmerkmal. Wende eine Regel an: Ein Kommentar muss eine Einschränkung angeben, die der Code nicht zeigen kann. Alles andere wird gelöscht.
Auf Sicht löschen:
- Erzählung:
// Schleife über die Einträge,// Hilfsfunktion aufrufen,// Ergebnis zurückgeben - Wiederholung des Codes oder seines eigenen Doc-Headers ein zweites Mal im Rumpf
- Prüfer-Gerede:
// das ist sicher, weil wir oben geprüft haben,// beachte, dass...— das bist du, der den Diff verteidigt, nicht den nächsten Leser informiert - Verweise auf den PR, die Überprüfung, das Gespräch oder „vor kurzem geändert“
- Kommentare, die erklären, warum die Änderung korrekt ist (gehört in den PR-Body)
- Abschnittsbanner (
// ---- Hilfsfunktionen ----) in Dateien unter ~300 Zeilen
Behalten (diese sind tragend):
- Drahtformat- oder Protokollbeschränkungen, insbesondere reverse-engineered ohne öffentliche Spezifikation: Feld X muss auch bei null vorhanden sein; Client Y lehnt die gesamte Nutzlast ab, wenn Z fehlt; zitiere die Upstream-Quelldatei
- Warum-nicht-Kommentare: warum der offensichtliche Ansatz verworfen wurde, was kaputt geht
- Plattformfakten, über die ein Leser stolpern wird: diese Umgebungsvariable ist eine Unix-Konvention; diese API macht auf Windows stillschweigend nichts
- Sicherheits-/Datenschutzinvarianten: nie den Rohdatensatz cachen, er enthält Geheimnisse
- Bewusste Richtlinien-Festschreibungen, die von den Standardeinstellungen des Upstreams abweichen, mit der Bedingung für die Aufhebung
Dichte-Heuristik, keine Regel: Für Klebe-/CRUD-Code verdient mehr als ~1 Kommentarzeile pro 15 hinzugefügten Zeilen einen zweiten Blick. Bei undokumentiertem Protokollcode kann hohe Dichte korrekt sein — die Kommentare SIND die Spezifikation. Beurteile jeden Kommentar nach den Behalten/Löschen-Listen, niemals nur nach der Anzahl.
Doc-Header: 4–8 Zeilen reine Einschränkungen. Wenn ein Header ein Absatz ist, der schrittweise beschreibt, was das Modul tut, kürze ihn auf das, was der Dateiname und die Exporte nicht bereits sagen können.
Durchgang 2 — Handgeschriebener Code, den eine Abhängigkeit oder die Standardbibliothek bereits bereitstellt
Das zweitgrößte Erkennungsmerkmal: Neuimplementierung von uuid, Hashing, Semver-Parsing, Glob-Matching, Datumsmathematik, Deep-Merge.
Vorgehen:
- Prüfe, wovon das Paket bereits abhängt (lies package.json, nicht die Erinnerung). Bevorzuge eine vorhandene Abhängigkeit oder die Laufzeit-Standardbibliothek gegenüber dem Hinzufügen von etwas Neuem.
- Wenn eine neue Abhängigkeit gerechtfertigt ist, wähle die langweilige, kampferprobte.
- Bevor du eine vorhandene handgeschriebene Implementierung austauschst, beweise die Gleichwertigkeit empirisch — führe beide mit denselben Eingaben aus und vergleiche die Ausgaben. Besonders bei deterministischen ID- und Hashing-Code: Ein Austausch, der die Ausgaben ändert, zerbricht stillschweigend die Idempotenz für bestehende Benutzer.
- Wenn es wirklich richtig ist, die handgeschriebene Version zu behalten (vermeidet eine Abhängigkeit für 10 Zeilen), erwarte die Frage des Prüfers und entscheide, ob das Argument die Abhängigkeit wert ist. Meistens ist es das nicht: Langweilig gewinnt bei Überprüfungen.
- Ausnahme: Code, der bereits aus Standardbibliothekskomposition besteht (createHash + pipeline), ist nicht handgeschrieben. Sage dies, wenn gefragt; wickele ihn nicht weiter ein.
Durchgang 3 — Kohäsion und Notwendigkeit
Slop sammelt sich an: Jede Bearbeitung fügt hinzu, ohne zu konsolidieren. Suche nach:
- Wiederholten Bedingungsausdrücken → einmal extrahieren, nach Bedeutung benennen (
noConfigChanges, nichtcheck1) - Demselben Literal in N Dateien → eine gemeinsame Konstante im Modul, dem das Konzept gehört; Adoptanten importieren sie
- Lokalen Neuimplementierungen von Repository-Helfern → suche nach einem vorhandenen Helfer, bevor du eine private Kopie behältst (
pathExists, Ausgabe-/Formatierungs-Hilfsfunktionen, Fehlerhelfer). Lösche die lokale Kopie, importiere die gemeinsame. - Totem Code: Für jeden Helfer/Typ/Export im Diff finde einen Verwender. Kein Verwender → jetzt löschen, nicht „für später“.
- Aufrufstellen, die selbst machen, was ein Helfer besitzt (Abstände, Zitierung, ID-Generierung) → verschiebe das Verhalten in den Helfer, verschlanke die Aufrufstellen
- Derselbe Sachverhalt zweimal genannt (Doc-Header + Inline-Kommentar) → einen behalten
- Funktionen, die Tupel von losen verwandten Werten zurückgeben → oft ein Zeichen, dass zwei Verantwortlichkeiten verschmolzen wurden; teile sie auf oder dokumentiere den Vertrag
Überprüfe dann die Passung ins Repository: Lese benachbarte Dateien und gleiche deren Idiom, Namensgebung, Fehlerstil und Testmuster an. Code, der den Hausstil ignoriert, wirkt generiert, selbst wenn er korrekt ist.
Durchgang 4 — Tests
- Tests müssen das Verhalten festlegen, nicht den Fehler. Wenn eine Assertion den falschen Wert kodiert, „weil der Code das so macht“, korrigiere beides.
- Spiegele das vorhandene Test-Harness und die Helfer der Suite; erfinde keinen parallelen Mock-Stil in derselben Datei.
- Jeder plattformspezifische Skip enthält einen einzeiligen Grund.
- Testnamen beschreiben das Szenario, nicht die Implementierung.
- Wenn du die Ausgabeform änderst, füge eine negative Assertion für die entfernte Form hinzu.
Durchgang 5 — Werkzeug-Parität, dann verifizieren
- Verwende die festgelegte Version des Formatierers/Linters des Repositorys (lies package.json — eine andere Hauptversion lokal ausführen lässt CI-exklusive Fehler durchschlüpfen).
- Führe die Tests aus, die der Diff berührt, auf jeder Ebene einer gestapelten Änderung, nicht nur an der Spitze.
- Überprüfe den endgültigen Diff noch einmal nach allen Bearbeitungen:
git diffund lies jede verbleibende Kommentarzeile laut gegen Durchgang 1. Dichte-Prüfung:git diff | grep -cE '^\+\s*(//|\*)'im Vergleich zu den gesamten hinzugefügten Zeilen. - Commit-Nachrichten: Erkläre warum, in Prosa, wie ein Mensch. Keine Aufzählungslisten-Changelogs für einen 3-Zeilen-Commit, kein „erweitert/verbessert/robust“.
Berichterstattung
Wenn gefragt wird „Ist das de-sloppt?“: Überprüfe den aktuellen Diff und antworte mit Beweisen (Dichtezahlen, was gelöscht wurde, was bewusst behalten wurde und warum), niemals „ja“ aus dem Gedächtnis. Wenn etwas behalten wurde, das ein Prüfer anmerken könnte — z. B. eine Datei mit hoher Protokolldichte — nenne es proaktiv und gib die Verteidigung in einem Satz.
Wenn ein Prüfer etwas als Slop bezeichnet: Gib das Muster zu, bevor du einzelne Instanzen verteidigst. Behebe die Kategorie überall, einschließlich Dateien, die sie nicht beanstandet haben (und denjenigen, die sie gelobt haben). Die Anwendung des Standards als Disziplin, nicht als Schadensbegrenzung an beanstandeten Zeilen, ist das, was Vertrauen wiederherstellt.