a-philosophy-of-software-design
Qué hace
Usar al escribir, modificar o revisar código siempre que el cambio añada un nombre exportado o importable, cree un módulo, clase, componente, helper, hook, servicio o wrapper, centralice código repetido o cambie una API. Reglas de Ousterhout (módulos profundos, ocultación de información, reducir la complejidad) más la prueba invariante para compartir código, la prueba del costo para el lector y una nota de diseño obligatoria al final.
La instalación abre esta ficha en tu app de escritorio AgentsRoom. Si aún no la tienes instalada, te llevaremos a la página de descarga.
SKILL.md
--- name: a-philosophy-of-software-design description: Usar al escribir, modificar o revisar código siempre que el cambio añada un nombre exportado o importable, cree un módulo, clase, componente, helper, hook, servicio o wrapper, centralice código repetido o cambie una API. Reglas de Ousterhout (módulos profundos, ocultación de información, reducir la complejidad) más la prueba invariante para compartir código, la prueba del costo para el lector y una nota de diseño obligatoria al final. --- # Una filosofía del diseño de software (John Ousterhout) ## Cuándo usar esta habilidad Usa esta habilidad cuando diseñes, escribas, cambies o revises código. Se aplica al diseño de módulos, cambios en APIs, descomposición, refactorización, nombres, comentarios, pruebas y trabajo de rendimiento. Úsala también cuando un cambio se sienta incómodo o cuando un cambio se extienda a muchos archivos. ## El sesgo a corregir El código que funciona no es lo mismo que código simple. Piezas pequeñas, patrones familiares, banderas, envoltorios y documentación extra pueden hacer que un diseño sea más complejo. Lo hacen cuando añaden a lo que un lector debe saber, o cuando filtran conocimiento a otros módulos. ## Reglas de decisión - Mide un diseño por cuánto reduce la complejidad. Prefiere el diseño que disminuye la carga del lector. La complejidad tiene cuatro señales. Un cambio necesita editarse en muchos lugares. Las dependencias están ocultas. Los pasos deben ocurrir en un orden fijo. El lector debe mantener muchos hechos en mente. - Trata el diseño como un trabajo continuo. Un primer parche que funciona no está terminado si dificulta cambios posteriores. Para una decisión sobre una interfaz, una división de módulo o una abstracción, compara dos o más diseños posibles. - Prefiere módulos profundos. Un módulo profundo tiene una interfaz pequeña y oculta una gran cantidad de complejidad. Rechaza servicios de paso, envoltorios de bibliotecas delgados y módulos auxiliares pequeños. Rechaza cualquier extracción que añada nombres pero no reduzca la carga del lector. - Diseña una interfaz alrededor de lo que el llamador debe saber, no alrededor de cómo funciona la implementación. Evita secuencias de configuración frágiles, banderas de modo, perillas de configuración y argumentos que muestran elecciones internas. - Oculta las decisiones que pueden cambiar. Ejemplos son representaciones internas, forma de almacenamiento, protocolos, formatos de archivo y trucos de rendimiento. La contabilidad, normalización y casos límite son otros ejemplos. Mantén cada uno dentro del módulo que posee el conocimiento. - Lleva la complejidad hacia abajo al módulo que posee el detalle. Acepta una implementación más compleja cuando da a los llamadores un contrato más simple y elimina trabajo repetido en cada sitio de llamada. - Haz un módulo general al nivel correcto. No ajustes un módulo a un solo llamador. No añadas una abstracción vaga para necesidades futuras. Mantén los casos límite raros fuera del camino principal y pon el comportamiento especial en su propio lugar. - Une o divide módulos por la complejidad total. No los unas o dividas por tamaño, por el orden en que corre el código, por hábito o por apariencia. Mantén juntos estado, comportamiento, reglas y decisiones relacionadas. Divídelos solo cuando el nuevo límite sea más profundo y un lector pueda entender cada lado por separado. - Haz que el conjunto de excepciones sea más pequeño. Cuando sea posible, cambia la interfaz o las reglas para que no puedan ocurrir estados inválidos. No hagas que cada llamador repita el mismo código defensivo. - Usa comentarios para reducir la complejidad. Anota contratos de interfaz, reglas que deben mantenerse, decisiones de diseño ocultas y sus razones. También anota hechos difíciles que los llamadores no deben necesitar saber. No repitas el código en un comentario. No uses un comentario para ocultar un mal nombre, una mala división o un flujo de control confuso. - Trata nombres, consistencia y claridad como información de diseño. Un nombre le dice al lector la abstracción, no el mecanismo. Operaciones relacionadas usan las mismas convenciones. Código que sorprende al lector añade complejidad, incluso cuando es corto. - Escribe pruebas contra contratos públicos y APIs estables. Prueba la complejidad oculta y los casos especiales a través de esos contratos. No permitas que la facilidad de una prueba fuerce una interfaz superficial o con fugas. - Añade un cambio de rendimiento, un patrón, un paradigma o un framework solo por una de dos razones. Reduce la complejidad en esta base de código, o la evidencia muestra que la compensación es necesaria. Oculta cada optimización detrás de una interfaz estable. ## Señales y la respuesta a cada una - Una característica es incómoda, o un cambio se extiende a archivos, o un revisor debe encontrar dependencias ocultas. Respuesta: busca falta de ocultación de información y módulos superficiales. También busca pasos en un orden fijo y complejidad que los llamadores cargan. - Añades un módulo, capa, servicio, ayudante, envoltorio o fachada. O añades un patrón, opción, callback o argumento. Respuesta: muestra que oculta más complejidad de la que añade. - Cambias una API. Respuesta: verifica qué debe saber un llamador normal. Un llamador no debe necesitar el orden de llamadas, la representación o el almacenamiento. Un llamador no debe necesitar el transporte, la caché, el protocolo o el formato de archivo. Un llamador no debe necesitar el flujo interno o muchos pasos de configuración. - Añades un caso especial, una bandera, un camino de excepción, una condición o un contenedor que los llamadores pueden ver. Respuesta: primero pregunta qué puede hacer el módulo propietario en su lugar. Puede eliminar el estado inválido, aislar el comportamiento inusual o dar una operación más fuerte. - Divides código, extraes una función o añades una variable. Respuesta: verifica que el nuevo límite o nombre tenga significado. No debe solo añadir saltos, estado que pasa o pasos intermedios que los llamadores pueden ver. - El código tiene fases como `prepare`, `process` y `finalize`, o los llamadores deben construir objetos en etapas. Respuesta: verifica que el orden temporal sea el concepto real. Si no lo es, organiza el código alrededor de responsabilidades estables. - Un nombre es vago, nombra un mecanismo, no es consistente o sorprende al lector. Respuesta: piensa de nuevo en el límite de abstracción. No aceptes un nombre que sea casi correcto. - Un comentario es largo, repite el código, explica una interfaz confusa o muestra internos para explicar el uso. Respuesta: cambia la abstracción o mueve el contrato faltante a la interfaz. - Optimiza el rendimiento. Respuesta: mide primero, luego oculta la optimización. No renuncies a la profundidad del módulo o a la ocultación de información sin evidencia de que la compensación es necesaria. - Pruebas o revisas. Respuesta: mira el comportamiento público y los contratos de interfaz. También mira la complejidad oculta detrás de APIs estables y los casos especiales mantenidos detrás de la abstracción. ## Lista de verificación final - ¿Reduce el cambio el esfuerzo para entender, modificar, verificar y ampliar el sistema? - ¿Oculta cada elemento de la interfaz, envoltorio, capa, ayudante, opción y nombre la complejidad suficiente para justificarlo? - ¿Están las decisiones importantes en un solo lugar? ¿Son visibles las dependencias? ¿Están escritas las restricciones que los llamadores necesitan? ¿Están protegidos los internos que pueden cambiar? - ¿Funcionan los casos comunes sin pasos adicionales? ¿Se mantienen fuera del camino común los controles raros, casos especiales, trucos de rendimiento y detalles de excepciones? - ¿Son los nombres exactos y consistentes? ¿Están los comentarios actualizados, sin repetir el código? ¿Sigue el código las convenciones existentes, a menos que nueva información justifique cambiarlas? ## Puerta Usa la lista de verificación completa cuando el cambio añade un nombre que otro código pueda exportar o importar. Úsala también cuando el cambio crea un módulo, clase, componente, ayudante, hook, servicio o envoltorio, o pone código repetido en un solo lugar. Los cambios de nombre, codemods, cambios de configuración, cambios de datos y correcciones de una línea no la necesitan. ## Prueba invariante: compartir solo código que cambia junto - Extrae código compartido solo cuando protege una regla que puedas nombrar. La evidencia es el co-cambio: la historia muestra que las copias se arreglaron o cambiaron juntas. Código que solo parece similar y cambia independientemente es una rima. Deja las rimas como duplicados. Tres bloques similares no prueban una regla. - Una corrección debe eliminar el problema, no moverlo. Seis conversiones movidas a un ayudante genérico de conversiones siguen siendo seis conversiones. Escribe el mapeador tipado que las conversiones ocultaban. - Cuando una abstracción está mal, vuelve a poner el código en línea y deja que la duplicación regrese. No dobles la abstracción con banderas. - No dividas código solo por su tamaño. Un módulo de 400 líneas que oculta una decisión es mejor que cuatro módulos de 100 líneas que filtran las mismas uniones. - Una lectura mecánica de Clean Code o SOLID (funciones muy pequeñas, una clase para cada responsabilidad) da módulos superficiales. Esta habilidad tiene prioridad sobre esa presión. ## Costo para el lector: la tercera prueba La prueba de profundidad y la prueba invariante deciden si debe existir un límite. La prueba de costo para el lector decide si el código alrededor del límite es barato de cambiar. El siguiente lector, una persona o un agente, paga por cada línea que debe leer. Un agente paga en tokens. Un agente encuentra código por búsqueda de texto, lecturas parciales, chequeo de tipos y pruebas. - **Encontrable.** Usa un nombre para cada concepto. Escríbelo igual en todas partes, para que la búsqueda de texto simple lo encuentre. Defectos: nombres construidos a partir de cadenas, cableado mediante efectos secundarios de importación, dos nombres para un concepto. Las cadenas de re-exportación que ocultan la definición también son defectos. - **Parada temprana.** Pon el contrato en la parte superior del archivo o encima de la exportación. Di lo que promete, lo que oculta y lo que nunca hace. Así el lector puede detenerse temprano. - **Comprobable por máquina.** Usa tipos exactos dentro y fuera de cada límite, para que un chequeo de tipos reemplace la lectura de los llamadores. Defectos: `any`, diccionarios simples, banderas booleanas cuyo significado está solo en el cuerpo. - **Acoplamiento visible.** Dos lugares deben cambiar juntos. Hazlo cumplir con un tipo compartido, una prueba o una única fuente. Si no puedes, márcalo en ambos lugares. - **Sin ruido.** Elimina comentarios que repiten el código y código comentado. Elimina ramas muertas y comentarios que registran historial de cambios. Elimina un camino antiguo que queda junto a su reemplazo. - **Predecible.** Sigue la estructura existente del repositorio. Pon la prueba donde un lector la busque y haz que se ejecute sola. El tamaño del archivo no está en esta lista a propósito. Un archivo muy grande es razón para buscar una segunda decisión oculta. Nunca es razón para cortar el archivo. ## Seguridad Para código existente, primero escribe una prueba que mantenga el comportamiento actual. Luego haz el módulo más profundo. Para código nuevo, escribe la prueba que define el comportamiento previsto. ## Nota de diseño (requerida cuando aplica la puerta) Cuando aplica la puerta, pon una sección con el título `## Design note` en la descripción del pull request. Escribe dos a cuatro líneas: - Cada límite que añadiste y la decisión que oculta. - Cada duplicación que mantuviste a propósito y la razón. - Cada parte superficial que aceptaste y la razón. Si la puerta no aplica, escribe `## Design note` seguido de `Gate not applicable: <reason>`. También pon la nota de diseño en el resumen de tu paso final. ## Modo revisión Usa esta sección cuando revises o pruebes código que otro agente o persona escribió. 1. Revisa la nota de diseño. Cuando aplica la puerta y el pull request no tiene sección `## Design note`, reporta un hallazgo bloqueante. Cuando la nota no coincide con el diff, reporta un hallazgo bloqueante. 2. Un hallazgo de diseño es bloqueante solo cuando cumple ambas condiciones: - Nombra una regla de esta habilidad. La regla es una regla de decisión, la puerta, la prueba invariante o un ítem de costo para el lector. - Indica un costo concreto para el lector o para el siguiente cambio. Ejemplos: "Los llamadores deben conocer la forma del almacenamiento." "Un concepto tiene dos nombres." "Un cambio de límite necesita ediciones en tres archivos." 3. Marca todas las demás observaciones de diseño como no bloqueantes. Ponlas en una lista separada con el título "Notas de diseño no bloqueantes". Una nota no bloqueante nunca devuelve el trabajo al creador. 4. No reportes una preferencia como hallazgo. Un nombre diferente, estructura de archivos o estilo es una preferencia. Se convierte en hallazgo solo cuando rompe una regla nombrada y tiene un costo concreto. 5. Cuando el mismo hallazgo de diseño regresa en un segundo ciclo de revisión, escálalo. No pidas el mismo cambio una tercera vez. ## Habilidades relacionadas (cuando están instaladas) - `find-shared-code`: una búsqueda solo para reporte del historial reciente de código que vale la pena compartir. Usa la prueba invariante y la prueba de profundidad de esta habilidad. - `refactoring` y `working-effectively-with-legacy-code`: los pasos seguros hacia un diseño más profundo. Esta habilidad decide si un nuevo límite se mantiene. ## Fuente y licencia Esta habilidad se basa en las reglas "mini" de A Philosophy of Software Design en el repositorio ciembor/agent-rules-books en GitHub (licencia MIT, commit 893a88a). La puerta, la prueba invariante, la prueba de costo para el lector, la nota de diseño y el modo de revisión son adiciones a esas reglas. El repositorio también contiene las reglas completas del libro.
Tags
Para profundizar
Claude Ads: el skill de Claude Code que audita tus cuentas de anuncios
Claude Ads es un skill open source para Claude Code: más de 250 comprobaciones en Google, Meta, LinkedIn, TikTok o Amazon Ads, una nota sobre 100 y un plan de acción priorizado, en unos diez minutos. Instalación, comandos, límites y cómo orquestarlo en AgentsRoom.
AGENTS.md: un solo archivo de contexto para todos tus agentes de código (Codex, Antigravity, Claude)
AGENTS.md es el archivo de instrucciones portable que tus agentes de código leen antes de tocar tu código. Qué poner en él, en qué se diferencia de CLAUDE.md, y cómo mantener un único contexto entre Codex, Antigravity y Claude.
Descargar AgentsRoom
Ejecuta todos tus agentes de IA, en todos tus proyectos, desde una sola ventana.
App complementaria: supervisa tus agentes en movimiento
Usa Claude, Codex, Antigravity CLI u otro proveedor de IA.
Envía bugs y peticiones directamente a tu backlog público.