Usa las dependencias de forma idiomática
Cada dependencia fue construida para una forma particular de problema. Su API codifica ese modelo: qué posee, qué te deja a ti, qué garantiza y dónde espera ser extendida. Escribe la solución idiomática, la que mostrarían los propios documentos y ejemplos canónicos de la biblioteca, y cuando el problema tenga una forma diferente (un desajuste de impedancia), elige la herramienta adecuada para el trabajo. Los fallos que debes evitar son reinventar la rueda, luchar contra el framework y subutilizar silenciosamente una funcionalidad incorporada para ese caso.
La fricción es un olor: un casteo, parche o solución alternativa en el camino obvio significa que el modelo se ha leído mal o la herramienta es incorrecta. Las violaciones más costosas no tienen fricción alguna: compilan bien y parecen locales mientras derrotan una garantía que la biblioteca existe para proporcionar, así que búscalas a propósito.
Escribiendo código que usa una dependencia
El camino por defecto. Revisar, auditar, añadir y actualizar se ramifican a partir de aquí (abajo).
-
Reformula el problema. Cuidado con el problema XY: la tarea a menudo llega como una solución, de tu parte o del usuario. Reformúlala como el problema general:
- "Reintentar la subida tres veces" es una política de reintentos.
- "Necesito
row_number() over (partition by account_id)para las facturas más recientes de cada cuenta" es top-N por grupo, que un ORM puede modelar sin función de ventana.
"La biblioteca no puede hacer X" es una afirmación que verificar en el paso 3, quienquiera que la haga.
Hecho cuando puedas nombrar el problema en las palabras que usarían los documentos de la biblioteca.
-
Encuentra dónde ya está resuelto, lo más cercano primero:
- El framework en el que estás: las políticas de reintentos y temporizadores de un motor de flujos de trabajo, la paginación y los actualizadores de almacenamiento de un cliente GraphQL, los temporizadores falsos de un ejecutor de pruebas.
- Las dependencias declaradas del proyecto (
package.json,pyproject.toml,go.mod,Cargo.toml) y cómo la base de código las importa. El uso existente muestra la convención de la casa, que puede diferir del diseño de la biblioteca. - Los paquetes compartidos del proyecto, que a menudo envuelven una dependencia de la forma en que el proyecto quiere usarla.
- La biblioteca estándar, para la versión de tiempo de ejecución en uso (
engines,.nvmrc,requires-python). Las más amplias cubren más de lo que la gente recuerda:itertools,collections,functools,pathlibde Python;fetch,AbortSignal.timeout,util.parseArgs,node:testde Node moderno.
Hecho cuando cada fuente ha sido revisada y tienes una lista corta, posiblemente vacía.
-
Aprende el modelo de la documentación de la versión instalada. Toma la versión del archivo de bloqueo; una fuente cuenta solo si coincide. Lee, en orden:
- La guía del proyecto para esta dependencia, encontrada y mantenida según GUIDANCE.md. Es la autoridad sobre las decisiones deliberadas de la casa y un caché del modelo de la biblioteca: cuando su versión registrada difiere del archivo de bloqueo, o una afirmación decide tu enfoque, confírmalo en las fuentes siguientes.
- Un checkout de referencia: el repositorio de la dependencia clonado en el proyecto o traído por una herramienta como
opensrc, usualmente con un puntero enAGENTS.mdoCLAUDE.md. Verifica su etiqueta contra el archivo de bloqueo. Sus documentos, ejemplos y pruebas son el mejor registro del uso previsto. - El paquete instalado: tipos exportados y sus comentarios de documentación, a menudo despojados de documentos y ejemplos.
- En línea, cuando ninguno de los dos últimos tenga documentos: los documentos oficiales para esa versión mayor, páginas de concepto y guías además de la referencia de la API; luego el repositorio ascendente en la etiqueta correspondiente.
Construye solo sobre la API pública: lo que los documentos describen, alcanzado a través de puntos de entrada declarados (un mapa
exports,__all__, nombres sin guion bajo inicial). Lee el código fuente para entender el comportamiento; cualquier cosa que encontraste solo allí es privada. Semver protege la API pública y nada más. Tu memoria de la biblioteca es una hipótesis que verificar contra los documentos, y los archivos de tiempo de ejecución que abras por casualidad no son sustituto de ellos.Hecho cuando puedas responder desde los documentos, antes de escribir o juzgar código que la use:
- ¿Para qué fue construida y qué deja deliberadamente fuera?
- ¿Qué posee (almacenamiento, caché, ciclo de vida, reintentos, transacciones), qué genera o te pide que declares (salida de generación de código, esquemas, tipos), y para qué parte de tu código es cada pieza?
- ¿Qué garantía mantiene (enmascaramiento de datos, determinismo del flujo de trabajo, aislamiento de transacciones), entre qué partes del sistema, y qué la derrotaría silenciosamente? A menudo se sienta entre tus propios módulos.
- ¿Qué API pública y puntos de extensión documentados (opciones, plugins, middleware, hooks, escotillas de escape) cubren esto, y cómo se ve el ejemplo canónico, hasta qué módulo importa qué?
- ¿Qué verificaciones incluye (un plugin de linter, validación del compilador o generador de código, un modo de tipos estricto), y las ejecuta el proyecto?
-
Elige el ajuste:
- El problema coincide con el modelo: úsalo.
- Parte de él queda fuera de la API principal: usa la escotilla de escape documentada para esa parte (SQL sin formato en un ORM, un componente sin cabeza, un resolvedor personalizado). Las escotillas de escape son parte del diseño.
- La versión instalada carece de ello: si el registro de cambios muestra que una versión más nueva lo tiene, propón la actualización según UPGRADING.md.
- Desajuste de impedancia: usa una dependencia cuyo modelo se ajuste, o código simple que se mantenga alejado de esta, detrás de una costura que poseamos. Que esté instalada, o usada cerca, no convierte a una biblioteca en la herramienta adecuada.
Hecho cuando hayas elegido una y puedas justificarla desde el modelo.
-
Escribe el código a la manera de la biblioteca, sobre su API pública. La primera versión que funciona a menudo no es la idiomática. Donde el código vecino y el ejemplo canónico difieran, sigue el ejemplo canónico e informa al usuario sobre la deriva. Ejecuta las verificaciones propias de la biblioteca mientras avanzas; si el proyecto las deja apagadas, di qué atraparía encenderlas.
Hecho cuando las verificaciones de la biblioteca pasan, ningún olor de abajo se aplica (o cada uno que se aplica es una elección que reportarás), y los mantenedores de la biblioteca reconocerían el código como su biblioteca usada según el diseño.
-
Cuando la fricción persista, primero adapta nuestro diseño al modelo de la biblioteca; sus restricciones a menudo codifican una lección (las reglas de determinismo de un motor de flujos de trabajo, el enmascaramiento de datos de un cliente GraphQL). Luego revisa el paso 4. Trabaja contra la biblioteca solo con el acuerdo del usuario, nombrando el comportamiento no documentado del que dependes en la propuesta y en un comentario en la solución alternativa. Un conflicto entre el modelo y un requisito del producto es decisión del usuario.
Olores: luchando contra la biblioteca
Cada uno te envía de vuelta al paso 4. Clasifica por lo que la biblioteca está ahí para proporcionar: una garantía derrotada supera a todo lo demás, incluso cuando nada está roto hoy, y una regla de la casa que codifica el modelo toma la severidad del modelo.
- Garantía derrotada: código generado usado fuera del módulo para el que fue generado (tipos de fragmento de otro componente), leer datos enmascarados de otro módulo, un fragmento o esquema compartido entre llamadores no relacionados, no determinismo dentro de un flujo de trabajo determinista. Estos compilan limpios, así que búscalos deliberadamente.
- Casteos o supresiones del verificador de tipos (
as,any,@ts-expect-error,# type: ignore) donde nuestro código se encuentra con los tipos de la biblioteca. - API privada: rutas internas (
pkg/dist/…,pkg._internal), nombres con guion bajo, exportaciones no documentadas, casteos dentro de campos privados de un objeto de la biblioteca, comportamiento encontrado solo en el código fuente. Una API inestable o experimental está documentada pero fuera de semver: úsala cuando los documentos lo recomienden aquí, y dilo. - Un parche que cambia cómo se comporta la biblioteca (parche del gestor de paquetes, monkey-patching, fork vendido). Un parche que hace que haga lo que sus documentos ya prometen es una corrección de errores y la acción correcta: mantenlo en la corrección y enlaza el issue ascendente.
- Estado duplicado: una segunda fuente de verdad para algo que la biblioteca posee, como un caché GraphQL reflejado en el estado del store o contadores de reintentos que el framework ya rastrea.
- Temporizadores, banderas o cadenas de efectos que ejecutan código "después" de la biblioteca, donde esta ofrece un callback, evento o hook.
- Un valor por defecto sobreescrito en cada punto de llamada, o un wrapper que deshace un comportamiento en cada llamada.
- Un wrapper superficial que principalmente renombra la API que envuelve. Aplica la prueba de eliminación: si eliminarlo solo mueve sus llamadas de vuelta a la biblioteca, no está ganando su mantenimiento.
- Parte de una funcionalidad de la biblioteca reconstruida porque el todo parecía más de lo que necesitabas.
Olores: subutilizando la biblioteca
El código funciona sobre la API pública, pero una funcionalidad incorporada construida para este caso lo haría más corto o más declarativo. Para encontrarla, lee el tipo de cada objeto de opciones que pases y la guía de la biblioteca para el problema del paso 1.
- Varias llamadas haciendo una operación: buscar-y-luego-crear cuando hay un upsert, escrituras en un bucle cuando hay una API batch.
- Pegamento remodelando la salida, cuando la consulta o hook toma una opción de selección o proyección.
- Estado que la biblioteca rastrea, reconstruido a mano: banderas de carga, pendiente, sucio o reintento.
- Las mismas opciones en cada punto de llamada, cuando hay valores por defecto, configuración compartida, un tema o una fábrica.
- Código imperativo para algo que la biblioteca te permite declarar: un esquema, una variante, una relación, una política.
La proporción funciona en ambos sentidos: cuando unas pocas líneas claras de código simple hacen el trabajo, el código simple es idiomático.
Revisando, auditando, añadiendo y actualizando
- Revisar el cambio de otra persona: lee REVIEWING.md.
- Auditar el uso de una dependencia en una base de código: lee AUDITING.md.
- Añadir un paquete, o actualizar una dependencia o el tiempo de ejecución: lee UPGRADING.md primero.
- Encontrar, escribir o actualizar la guía del proyecto para una dependencia: lee GUIDANCE.md.
Responde: las funcionalidades de la biblioteca que soportan el comportamiento que no escribiste; para código de propósito general que escribiste tú mismo, qué verificaste y por qué nada encajó; cada dependencia que omitiste y la parte de su modelo que no coincidió; y cada olor que mantuviste, con la razón. Cuando hayas aprendido algo duradero sobre la dependencia, añade la guía que propones, según GUIDANCE.md.