Was macht Abhängigkeiten idiomatisch nutzen?
Jede Abhängigkeit wurde für eine bestimmte Problemform geschaffen. Ihre API kodiert dieses Modell: was sie besitzt, was sie dir überlässt, was sie garantiert und wo sie erwartet, erweitert zu werden. Schreibe die idiomatische Lösung, die die Dokumentation und kanonischen Beispiele der Bibliothek zeigen würden. Wenn das Problem eine andere Form hat (ein Impedanzkonflikt), wähle das richtige Werkzeug für die Aufgabe. Die zu vermeidenden Fehler sind: das Rad neu erfinden, gegen das Framework kämpfen und eine für den Fall geschaffene Möglichkeit stillschweigend nicht auszuschöpfen.
Reibung ist ein Geruch: Ein Cast, Patch oder Workaround auf dem offensichtlichen Pfad bedeutet, dass das Modell falsch gelesen oder das Werkzeug falsch gewählt ist. Die teuersten Verstöße haben gar keine Reibung: Sie bestehen den Typprüfer und sehen lokal aus, während sie eine Garantie untergraben, die die Bibliothek bieten soll – suche also gezielt danach.
Code schreiben, der eine Abhängigkeit nutzt
Der Standardpfad. Überprüfen, Auditieren, Hinzufügen und Aktualisieren zweigen davon ab (unten).
-
Formuliere das Problem neu. Achte auf das XY-Problem: Die Aufgabe kommt oft als Lösung daher, von dir oder dem Benutzer. Formuliere sie als das allgemeine Problem um:
- „Lade den Upload dreimal erneut“ ist eine Wiederholungsrichtlinie.
- „Ich brauche
row_number() over (partition by account_id)für die aktuellsten Rechnungen jedes Kontos“ ist „Top-N pro Gruppe“, was ein ORM möglicherweise ohne Fensterfunktion modelliert.
„Die Bibliothek kann X nicht“ ist eine Behauptung, die in Schritt 3 zu überprüfen ist, egal wer sie aufstellt.
Erledigt, wenn du das Problem mit den Worten benennen kannst, die die Dokumentation der Bibliothek verwenden würde.
-
Finde heraus, wo es bereits gelöst ist, zuerst am nächsten:
- Das Framework, in dem du dich befindest: Wiederholungsrichtlinien und Timer einer Workflow-Engine, Paginierung und Store-Updater eines GraphQL-Clients, Fake-Timer eines Test-Runners.
- Die deklarierten Abhängigkeiten des Projekts (
package.json,pyproject.toml,go.mod,Cargo.toml) und wie die Codebasis sie importiert. Die vorhandene Nutzung zeigt die Hauskonvention, die vom Design der Bibliothek abweichen kann. - Die gemeinsamen Pakete des Projekts, die oft eine Abhängigkeit so kapseln, wie das Projekt sie nutzen möchte.
- Die Standardbibliothek für die verwendete Laufzeitversion (
engines,.nvmrc,requires-python). Breite Standardbibliotheken decken mehr ab, als man denkt: Pythonsitertools,collections,functools,pathlib; modernes Nodesfetch,AbortSignal.timeout,util.parseArgs,node:test.
Erledigt, wenn jede Quelle geprüft ist und du eine kurze Liste hast, möglicherweise leer.
-
Lerne das Modell aus der Dokumentation der installierten Version. Nimm die Version aus der Lockdatei; eine Quelle zählt nur, wenn sie übereinstimmt. Lies in dieser Reihenfolge:
- Die Projektanleitung für diese Abhängigkeit, gefunden und gepflegt gemäß GUIDANCE.md. Sie ist die Autorität für bewusste Hausentscheidungen und ein Cache des Bibliotheksmodells: Wenn die aufgezeichnete Version von der Lockdatei abweicht oder eine Behauptung deinen Ansatz bestimmt, bestätige sie in den folgenden Quellen.
- Ein Referenz-Checkout: Das Repository der Abhängigkeit, geklont in das Projekt oder von einem Tool wie
opensrcabgerufen, normalerweise mit einem Hinweis inAGENTS.mdoderCLAUDE.md. Überprüfe den Tag gegen die Lockdatei. Dessen Dokumentation, Beispiele und Tests sind die beste Aufzeichnung der beabsichtigten Nutzung. - Das installierte Paket: Exportierte Typen und ihre Doc-Kommentare, oft ohne Dokumentation und Beispiele.
- Online, wenn keine der letzten beiden Quellen Dokumentation hat: Die offizielle Dokumentation für diese Hauptversion, Konzept- und Leitfadenseiten sowie die API-Referenz; dann das Upstream-Repository zum passenden Tag.
Baue nur auf der öffentlichen API auf: Was die Dokumentation beschreibt, erreicht über deklarierte Einstiegspunkte (eine
exports-Map,__all__, Namen ohne führenden Unterstrich). Lese den Quellcode, um das Verhalten zu verstehen; alles, was du nur dort gefunden hast, ist privat. Semver schützt die öffentliche API und nichts anderes. Deine Erinnerung an die Bibliothek ist eine Hypothese, die du gegen die Dokumentation prüfen musst, und Laufzeitdateien, die du zufällig öffnest, sind kein Ersatz dafür.Erledigt, wenn du aus der Dokumentation beantworten kannst, bevor du Code schreibst oder beurteilst, der sie nutzt:
- Wofür wurde sie gebaut und was lässt sie bewusst außen vor?
- Was besitzt sie (Speicher, Cache, Lebenszyklus, Wiederholungen, Transaktionen), was generiert sie oder bittet sie dich zu deklarieren (Codegen-Ausgaben, Schemata, Typen) und für welchen Teil deines Codes ist jedes Stück gedacht?
- Welche Garantie erhält sie aufrecht (Datenmaskierung, Workflow-Determinismus, Transaktionsisolation), zwischen welchen Systemteilen, und was würde sie stillschweigend untergraben? Sie sitzt oft zwischen deinen eigenen Modulen.
- Welche öffentliche API und dokumentierten Erweiterungspunkte (Optionen, Plugins, Middleware, Hooks, Escape-Hatches) decken dies ab, und wie sieht das kanonische Beispiel aus, bis hin zu welchem Modul was importiert?
- Welche Prüfungen liefert sie mit (ein Lint-Plugin, Compiler- oder Codegen-Validierung, ein strikter Typmodus) und führt das Projekt sie aus?
-
Wähle die Passung:
- Das Problem passt zum Modell: Nutze es.
- Ein Teil fällt außerhalb der Haupt-API: Nutze den dokumentierten Escape-Hatch für diesen Teil (rohes SQL in einem ORM, eine kopflose Komponente, ein benutzerdefinierter Resolver). Escape-Hatches sind Teil des Designs.
- Die installierte Version hat es nicht: Wenn das Changelog zeigt, dass eine neuere Version es hat, schlage das Upgrade gemäß UPGRADING.md vor.
- Impedanzkonflikt: Verwende eine Abhängigkeit, deren Modell passt, oder einfachen Code, der sich von dieser fernhält, hinter einer Naht, die wir besitzen. Installiert zu sein oder in der Nähe genutzt zu werden, macht eine Bibliothek nicht zum richtigen Werkzeug.
Erledigt, wenn du eine Wahl getroffen und sie anhand des Modells begründen kannst.
-
Schreibe es auf die Weise der Bibliothek, über ihre öffentliche API. Die erste Version, die funktioniert, ist oft nicht die idiomatische. Wenn benachbarter Code und das kanonische Beispiel uneins sind, folge dem kanonischen Beispiel und teile dem Benutzer die Abweichung mit. Führe die eigenen Prüfungen der Bibliothek während der Arbeit aus; wenn das Projekt sie weglässt, sage, was das Einschalten abfangen würde.
Erledigt, wenn die Prüfungen der Bibliothek bestehen, keiner der unten stehenden Gerüche zutrifft (oder jeder, der zutrifft, eine Wahl ist, die du melden wirst), und die Maintainer der Bibliothek den Code als ihre Bibliothek erkennen würden, die wie designed genutzt wird.
-
Wenn die Reibung anhält, passe zuerst unser Design an das Modell der Bibliothek an; seine Einschränkungen kodieren oft eine Lektion (die Determinismusregeln einer Workflow-Engine, die Datenmaskierung eines GraphQL-Clients). Gehe dann zurück zu Schritt 4. Arbeite nur mit Zustimmung des Benutzers gegen die Bibliothek, benenne das undokumentierte Verhalten, auf das du dich verlässt, im Vorschlag und in einem Kommentar beim Workaround. Ein Konflikt zwischen dem Modell und einer Produktanforderung ist die Entscheidung des Benutzers.
Gerüche: Gegen die Bibliothek kämpfen
Jeder schickt dich zurück zu Schritt 4. Rangfolge nach dem, was die Bibliothek bieten soll: Eine untergrabene Garantie hat Vorrang vor allem anderen, selbst wenn heute nichts kaputt ist, und eine Hausregel, die das Modell kodiert, hat die Schwere des Modells.
- Untergrabene Garantie: Generierter Code, der außerhalb des Moduls verwendet wird, für das er generiert wurde (Fragmenttypen einer anderen Komponente), Lesen maskierter Daten eines anderen Moduls, ein Fragment oder Schema, das von unabhängigen Aufrufern geteilt wird, Nichtdeterminismus innerhalb eines deterministischen Workflows. Diese bestehen den Typprüfer sauber – suche also gezielt danach.
- Casts oder Typ-Prüfer-Unterdrückungen (
as,any,@ts-expect-error,# type: ignore), wo unser Code auf die Typen der Bibliothek trifft. - Private API: Interne Pfade (
pkg/dist/…,pkg._internal), Unterstriche-Namen, undokumentierte Exporte, Casts in private Felder eines Bibliotheksobjekts, Verhalten, das nur im Quellcode gefunden wurde. Eine instabile oder experimentelle API ist dokumentiert, aber außerhalb von Semver: Verwende sie, wenn die Dokumentation sie hier empfiehlt, und sage es. - Ein Patch, der das Verhalten der Bibliothek ändert (Paketmanager-Patch, Monkey-Patching, verkaufte Abspaltung). Ein Patch, der sie das tun lässt, was ihre Dokumentation bereits verspricht, ist ein Bugfix und der richtige Schritt: Halte ihn auf den Fix und verlinke das Upstream-Issue.
- Duplizierter Zustand: Eine zweite Quelle der Wahrheit für etwas, das die Bibliothek besitzt, wie ein GraphQL-Cache, der in den Store-Zustand gespiegelt wird, oder Wiederholungszähler, die das Framework bereits verfolgt.
- Timer, Flags oder Effektketten, die Code „nach“ der Bibliothek ausführen, wo sie einen Callback, ein Event oder einen Hook anbietet.
- Ein Standardwert, der an jeder Aufrufstelle überschrieben wird, oder ein Wrapper, der ein Verhalten bei jedem Aufruf rückgängig macht.
- Ein flacher Wrapper, der hauptsächlich die umschlossene API umbenennt. Wende den Löschtest an: Wenn das Löschen nur seine Aufrufe zurück zur Bibliothek verschiebt, verdient er seinen Platz nicht.
- Ein Teil einer Bibliotheksfunktion, der nachgebaut wurde, weil das Ganze wie mehr aussah, als du brauchtest.
Gerüche: Die Bibliothek nicht ausschöpfen
Der Code funktioniert auf der öffentlichen API, aber eine Möglichkeit, die für diesen Fall geschaffen wurde, würde ihn kürzer oder deklarativer machen. Um sie zu finden, lies den Typ jedes Optionsobjekts, das du übergibst, und die Anleitung der Bibliothek für das Problem aus Schritt 1.
- Mehrere Aufrufe für eine Operation: Finde-und-erzeuge, wo es ein Upsert gibt, Schreibvorgänge in einer Schleife, wo es eine Batch-API gibt.
- Klebecode, der Ausgaben umformt, wo die Abfrage oder der Hook eine
select- oderprojection-Option nimmt. - Zustand, den die Bibliothek verfolgt, von Hand nachgebaut: Lade-, Ausstehend-, Schmutzig- oder Wiederholungsflags.
- Dieselben Optionen an jeder Aufrufstelle, wo es Defaults, gemeinsame Konfiguration, ein Theme oder eine Factory gibt.
- Imperativer Code für etwas, das die Bibliothek dich deklarieren lässt: ein Schema, eine Variante, eine Beziehung, eine Richtlinie.
Das Verhältnis gilt in beide Richtungen: Wenn ein paar klare Zeilen einfachen Codes die Arbeit erledigen, ist der einfache Code idiomatisch.
Überprüfen, Auditieren, Hinzufügen und Aktualisieren
- Überprüfen einer Änderung eines anderen: Lese REVIEWING.md.
- Auditieren der Nutzung einer Abhängigkeit in einer Codebasis: Lese AUDITING.md.
- Hinzufügen eines Pakets oder Aktualisieren einer Abhängigkeit oder der Laufzeit: Lese zuerst UPGRADING.md.
- Finden, Schreiben oder Aktualisieren der Projektanleitung für eine Abhängigkeit: Lese GUIDANCE.md.
Antwort: die Bibliotheksfunktionen, die das Verhalten tragen, das du nicht geschrieben hast; für allgemeinen Code, den du selbst geschrieben hast, was du geprüft hast und warum nichts passte; jede Abhängigkeit, die du übergangen hast, und der Teil ihres Modells, der nicht passte; und jeder Geruch, den du behalten hast, mit dem Grund. Wenn du etwas Dauerhaftes über die Abhängigkeit gelernt hast, füge die vorgeschlagene Anleitung gemäß GUIDANCE.md hinzu.