Suche/Eine große modulare Codebasis lesbar halten und ohne Brüche ändern

Eine große modulare Codebasis lesbar halten und ohne Brüche ändern

Für den Einsatz, wenn eine KI in einer großen Codebasis aus vielen Komponenten arbeitet. Gibt Regeln für Codestil, Datei- und Änderungsgröße, Code-Review, Tests, API-Namen und Builds vor, damit Änderungen klein und lesbar bleiben und keine anderen Teile kaputtgehen.

Diese KI-Regeln verwenden
## Nackte true/false-Argumente vermeiden, damit jeder Aufruf für sich verständlich ist Klarheit an der Aufrufstelle zählt mehr als raffinierter Code. - Binde Variablen direkt in Platzhalter zur Zeichenkettenformatierung ein, anstatt sie positionsbezogen zu übergeben. - Bevorzuge Methodenreferenzen gegenüber trivialen Closures, wenn die Sprache dies erlaubt. - Vermeide unklare Positionsargumente – nackte Booleans, null/none oder numerische Literale –, die Lesende zum Raten der Bedeutung zwingen (z. B. `foo(false)`). Bevorzuge Enums, benannte Methoden, Newtypes oder andere selbsterklärende API-Formen. - Wenn eine selbsterklärende Form nicht möglich ist und ein Positionsliteral bestehen bleiben muss, versieh es mit einem Inline-Kommentar `/*param_name*/`, der exakt dem Parameternamen der aufgerufenen Funktion entspricht. Lasse String-/Zeichenliterale unkommentiert, es sei denn, der Kommentar schafft tatsächlich mehr Klarheit. - Gestalte Verzweigungen erschöpfend (keine Catch-all-Wildcard-Zweige), damit neu hinzugefügte Fälle bereits zur Kompilierzeit auffallen. - Versieh neu hinzugefügte Abstraktionen (Traits/Interfaces) mit Dokumentationskommentaren, die ihre Rolle erklären und wie Implementierende sie verwenden sollen. - Halte dich an dateilokale Konventionen. Wandle Code nicht ohne klaren Gewinn an Lesbarkeit oder Funktionalität zwischen gleichwertigen Formen um, und füge keine Typannotationen nur hinzu, um eine Kurzschreibweise zu erfüllen. - Erstelle keine kleinen Hilfsfunktionen, die nur an einer einzigen Stelle verwendet werden. ## Dateien und Änderungen klein halten, statt die zentrale Komponente aufzublähen Halte Einheiten klein, damit voneinander unabhängige Änderungen nicht mehr kollidieren. ### Modulgröße - Bevorzuge das Anlegen eines neuen Moduls gegenüber dem Vergrößern eines bestehenden. Ziel sind Module mit weniger als etwa 500 Zeilen Code ohne Tests; sobald eine Datei sich der Marke von ~800 Zeilen nähert, bringe neue Funktionalität in ein neues Modul, sofern kein triftiger, dokumentierter Grund dagegenspricht. - Wende dies am striktesten auf stark frequentierte, zentrale Orchestrierungsdateien an, die schon jetzt themenfremde Änderungen anziehen; halte solche Dateien auf die Orchestrierung fokussiert, statt eigenständige Hilfsfunktionen anzuhäufen. - Wenn Code aus einem großen Modul ausgelagert wird, verschiebe die zugehörigen Tests sowie Typ-/Moduldokumentation zusammen mit der neuen Implementierung, damit Invarianten nah am Code bleiben, dem sie gehören. ### Der Aufblähung der größten Komponente widerstehen - Die größte oder zentralste Komponente ist für neuen Code der Weg des geringsten Widerstands – genau deshalb wächst sie immer weiter. Widerstehe der Versuchung, dort weiter hinzuzufügen. Frage zuerst, ob eine bestehende Komponente die bessere Heimat ist oder ob es Zeit für eine neue ist – und refaktoriere bei Bedarf. Weise im Review Änderungen zurück, die die zentrale Komponente unnötig vergrößern würden. ### Änderungsgröße - Halte die Gesamtzahl geänderter Zeilen unter ~800, sofern die Änderung nicht rein mechanisch ist; bei komplexer Logik unter ~500. - Ist eine Änderung größer, teile sie in überprüfbare Stufen auf und bringe zuerst die kleinste in sich schlüssige Stufe ein; richte die Aufteilung am tatsächlichen Diff, den Abhängigkeiten und den betroffenen Aufrufstellen aus. ## Im Code-Review inkompatible Änderungen und unbegrenzt wachsenden Kontext finden Prüfe gezielt auf Risiken, deren spätere Entdeckung teuer wäre. ### Öffentliche Schnittstelle klein halten Halte die öffentliche/exportierte API jeder Komponente so klein wie möglich. Bevorzuge private interne Elemente mit einer explizit exportierten öffentlichen Schnittstelle und vermeide eine Wucherung reiner Test-Hilfsfunktionen im Produktionscode. ### Modell-/Inferenzkontext absichern Wenn ein System einen Kontext pflegt, der bei jeder Inferenzanfrage an ein Modell gesendet wird, schütze ihn: - Baue den Kontext schrittweise auf; schreibe die Historie niemals um. - Vermeide häufige Kontextänderungen, die das Caching ungültig machen. - Alles Eingefügte muss eine begrenzte Größe und eine feste Obergrenze haben – keine unbegrenzten Elemente und kein einzelnes Element, das eine festgelegte Token-Obergrenze überschreitet. - Markiere jedes neue Element, das für sich genommen einen hohen Größenschwellenwert überschreiten kann, für eine zusätzliche manuelle Prüfung. - Leite alle eingefügten Fragmente über eine einzige typisierte Abstraktion, statt sie ad hoc einzufügen. ### Inkompatible Änderungen erkennen Suche aktiv nach inkompatiblen Änderungen an externen Integrationsschnittstellen: öffentliche APIs, Ereignis-Nutzdaten (auch experimentelle), Kommandozeilenparameter, das Laden von Konfigurationen sowie die Möglichkeit, bestehende Sitzungen oder gespeicherten Zustand fortzusetzen. ## Echtes Verhalten mit Integrations- und Snapshot-Tests prüfen Teste Verhalten, halte Tests ehrlich und halte sie aus dem Produktionscode heraus. - Bevorzuge bei Änderungen am Kernverhalten Integrationstests, die eine reale Instanz durchlaufen, gegenüber eng gefassten Unit-Tests. Jede Änderung an diesem Verhalten MUSS einen Integrationstest ergänzen; liste dabei die Verhaltensweisen auf, die abgedeckt werden müssen. - Lege Unit-Tests in einer eigenen, danebenliegenden Testdatei ab statt direkt in der Implementierungsdatei, und gib der Datei einen aussagekräftigen Namen. Füge Produktionsmodulen keine reinen Testfunktionen hinzu und schreibe bestehende Inline-Testmodule nicht allein deshalb um, um dieser Konvention zu folgen. - Jede Änderung an für Nutzende sichtbarer, gerenderter Ausgabe muss durch Snapshots abgedeckt sein – füge den Snapshot hinzu oder aktualisiere ihn und prüfe den Diff als Teil der Änderung, damit die Auswirkung auf die Oberfläche sichtbar bleibt. - Prüfe ganze Objekte per Deep-Equality-Vergleich, statt Felder einzeln zu vergleichen, und nutze dafür eine Assertion-Bibliothek, die klare Diffs erzeugt. - Verändere innerhalb von Tests keinen globalen Prozesszustand (zum Beispiel Umgebungsvariablen); übergib Abhängigkeiten und Flags stattdessen von außen. - Teste keine statisch definierten Konstanten und füge keine Negativtests für entfernte Logik hinzu. - Prüfe auf vorhandene Test-Hilfsfunktionen, bevor du einen neuen Testaufbau schreibst, damit Tests schlank und lesbar bleiben. ## API-Namen und Feldformate überall gleich halten Bei der Weiterentwicklung einer netzwerkbasierten oder sprachübergreifenden API verhindert Konsistenz an der Übertragungsgrenze stille Inkompatibilitäten. - Konzentriere die aktive Entwicklung auf die aktuelle API-Version; erweitere veraltete Versionen nicht um neue Funktionsfläche. - Benenne Nutzdaten einheitlich nach ihrer Rolle (ein Suffix für Anfrageparameter, eines für Antworten, eines für Benachrichtigungen). Biete Methoden als Ressourcennamen gefolgt von einem Aktionsnamen an, mit einer einheitlichen Konvention für Singular/Plural der Ressource. - Lege eine einheitliche Schreibweise (Casing) für Felder und Enum-Werte auf der Übertragungsebene fest und wende sie überall an; weiche nur bei ausdrücklichem Kompatibilitätsbedarf davon ab. Halte Serializer- und Typgenerierungs-Annotationen aufeinander abgestimmt, damit beide Seiten übereinstimmen; verwendet eine Seite eine explizite Umbenennung, muss die andere entsprechend nachziehen. - Verwende bei diskriminierten Unions in jedem Serializer eine explizite Kennzeichnung (Tagging). - Bevorzuge an der Schnittstelle einfache String-IDs und konvertiere sie intern. Verwende ganzzahlige Zeitstempel mit einheitlicher `*_at`-Benennung. - Implementiere für Listen-Endpunkte standardmäßig eine Cursor-Paginierung (eingehend ein Cursor und ein Limit; ausgehend ein Datenarray und ein nächster Cursor). - Sichere experimentelle Funktionsfläche hinter einer expliziten Kennzeichnung ab und generiere Dokumentation, Beispiele und Schema-Fixtures immer neu, wenn sich API-Formen ändern. ## Zuerst Formatter und eng gefasste Tests ausführen und Sandbox-Schutz nicht anfassen Respektiere die Toolchain und die bereits bestehenden Einschränkungen. ### Umgebungs- und Sandbox-Absicherungen - Füge niemals ohne bewusste Absicht Code hinzu oder ändere Code, der Sandbox- oder Umgebungsfähigkeits-Flags verwaltet. Diese Absicherungen existieren, weil Code und Tests um bestimmte Laufzeitgrenzen herum geschrieben wurden – zum Beispiel Tests, die vorzeitig abbrechen, wenn eine Fähigkeit wie Netzwerkzugriff nicht verfügbar ist. Eine Absicherung stillschweigend zu entfernen oder zu verändern bricht diese Annahmen. ### Build- und Toolchain-Hygiene - Lass den Formatierer automatisch laufen, sobald Codeänderungen abgeschlossen sind; hole keine Freigabe fürs Formatieren ein. - Führe zuerst die am engsten gefassten relevanten Tests aus, beschränkt auf die geänderte Komponente. Weite den Testlauf nur dann auf die gesamte Suite aus, wenn gemeinsam genutzter oder zentraler Code geändert wurde, und hole vor dem Start langer vollständiger Testläufe eine Bestätigung ein. - Wenn du Eingaben änderst, die generierte Artefakte speisen – Schemas, Lockfiles, generierte Typen –, generiere diese im selben Änderungsschritt neu; Abweichungen werden in der CI überprüft. - Falls das Build-Tool eine Deklaration von Quelldateien für den Zugriff zur Kompilierzeit benötigt, aktualisiere diese Deklaration jedes Mal, wenn du solche Zugriffe hinzufügst. - Sei geduldig bei langsamen Build- und Testbefehlen; erwartete Sperrkonflikte (Lock Contention) können sie verlangsamen. Beende sie nicht anhand ihrer Prozess-ID. ### Plattformunterstützung - Tests und Funktionen müssen jedes offiziell unterstützte Betriebssystem abdecken, sofern eine Funktion nicht ausdrücklich betriebssystemspezifisch ist. Wo das System es erlaubt, Komponenten auf unterschiedlichen Betriebssystemen laufen zu lassen, müssen neue Tests diese betriebssystemübergreifenden Konfigurationen prüfen.