CommunityProgramación y desarrollogithub.com

yutna/oo-design

Úsalo al comenzar un nuevo módulo, funcionalidad o sistema en una base de código orientada a objetos, al dimensionar el diseño o si no estás seguro de qué regla de objetos aplicar.

¿Qué es oo-design?

Esta habilidad proporciona una guía completa de diseño orientado a objetos para desarrolladores que trabajan en bases de código OO. Ayuda a dimensionar el esfuerzo de diseño según la tarea (desde un simple método hasta un sistema completo) y dirige al usuario a las habilidades específicas necesarias. Incluye un bucle de diseño paso a paso que cubre desde el lenguaje del dominio hasta la comprobación de señales de alerta, tablas de síntomas que mapean problemas comunes a habilidades concretas, y soporte para múltiples lenguajes (Java, Kotlin, TypeScript, JavaScript, etc.) con reglas específicas por lenguaje. Está diseñada para agentes de IA como Claude Code, Cursor o Codex, y se integra con un ecosistema de más de 40 habilidades relacionadas.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/yutna/object-oriented-design-skills/tree/HEAD/plugins/core/skills/oo-design

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Diseño Orientado a Objetos

Resumen

Este paquete contiene reglas de diseño para bases de código escritas en un estilo orientado a objetos, no consejos universales. Las convenciones escritas del propio proyecto prevalecen sobre el paquete. Sigue el modismo del módulo que se está modificando. Esta habilidad dimensiona la tarea y nombra la habilidad que corresponde.

Carga la habilidad que este índice nombra antes de responder: sus reglas y ejemplos viven allí, no aquí.

Cuánto diseño justifica una tarea

TareaUsarOmitir
Una respuesta usada una vez y luego desechadaNadaTodo
Un método en una clase que existeSu nombre y su contratoRemodelación
Una funcionalidad dentro de un flujo existenteEl modismo que usa ese flujoNuevos límites
Una nueva clase o móduloEl bucle de diseñoNada
Un nuevo contextoEl bucle, luego sus límitesNada
Un nuevo sistema desde ceroEl bucle, contextos, luego estructuraNada

Antes de diseñar

Antes de diseñar, establece la puerta: una regla que el software debe seguir, con un ejemplo que acepta y uno que rechaza. Por ejemplo, "Un espacio puede contener como máximo una cita." Acepta reservar un segundo paciente en un espacio diferente y rechaza reservar un segundo paciente en el mismo espacio. Si puedes escribir la regla, comienza. Si no puedes, lo que falta no es diseño, y este paquete no puede proporcionarlo.

El bucle de diseño

  1. Di lo que el software debe hacer en las palabras del dominio (hablando el lenguaje del dominio), y encuentra el objeto que sabe lo que cada comportamiento necesita (asignando responsabilidades).
  2. Encuentra el límite de consistencia: qué debe ser verdadero junto en una sola transacción (diseñando agregados).
  3. Decide dónde vive cada regla: una entidad, un objeto de valor o un servicio de dominio (colocando la lógica de dominio).
  4. Diseña los mensajes a los que cada objeto responde (encapsulando estado y comportamiento), y haz que los estados ilegales sean imposibles de construir (haciendo imposibles los estados ilegales).
  5. Invierte las dependencias para que el dominio no sepa nada de la base de datos ni del framework (invirtiendo dependencias, estratificando el sistema).
  6. Nombra las cosas en las palabras del dominio, y comenta solo lo que el código no puede decir (nombrando clases y métodos, comentando lo que el código no puede decir).
  7. Verifica el resultado contra las señales de alerta a continuación (revisando el diseño de objetos).

Qué tan estrictamente se entiende una regla

Cada regla central en este paquete lleva una de tres etiquetas, y la etiqueta dice qué tan estrictamente se entiende.

  • Regla. Romperla es un defecto. Ningún framework la excusa.
  • Predeterminado. Haz esto a menos que se cumpla una condición establecida. La condición es su propia oración, nunca una cláusula final.
  • Juicio. Dos respuestas son defendibles. La habilidad dice qué inclina la balanza.

Síntomas y habilidades

Los síntomas apuntan a la habilidad que los trata, y esta tabla crece a medida que llegan las habilidades.

SíntomaHabilidad
¿Qué clase debería hacer esto?Asignando responsabilidades
Esta clase hace demasiadoAsignando responsabilidades
Un cambio se propaga a través de muchas clasesDiagnosticando acoplamiento
¿Qué tan unidas están estas dos partes?Diagnosticando acoplamiento
¿Es esto un objeto o solo datos?Decidiendo objeto o datos
Nuestro modelo de dominio es anémicoDecidiendo objeto o datos
Otro código decide por este objetoEncapsulando estado y comportamiento
Los setters permiten que este objeto rompa sus reglasEncapsulando estado y comportamiento
Este objeto puede existir medio construidoConstruyendo objetos válidos
Este constructor toma demasiados argumentosConstruyendo objetos válidos
Cada nuevo caso significa editar código en funcionamientoEncapsulando lo que varía
¿Cuánta flexibilidad debería tener esto?Encapsulando lo que varía
¿Es esto un valor o una entidad?Modelando valores y entidades
Cadenas y números sin procesar llevan reglas de dominioModelando valores y entidades
¿Debería extender esa clase o contenerla?Eligiendo composición sobre herencia
Cambiar una clase base rompe sus subclasesEligiendo composición sobre herencia
Una subclase rompe lo que promete su padreHonrando la sustituibilidad
El código verifica qué subtipo contieneHonrando la sustituibilidad
El mismo switch sobre un tipo sigue apareciendoReemplazando condicionales con polimorfismo
¿Subclases o coincidencia de patrones?Reemplazando condicionales con polimorfismo
El código alcanza a través de una cadena de objetosLimitando lo que un objeto sabe
Esta clase solo reenvía llamadasLimitando lo que un objeto sabe
¿Cómo debería llamarse esta clase o método?Nombrando clases y métodos
Nombres como Manager, Helper o UtilNombrando clases y métodos
Los llamadores dependen de métodos de interfaz que nunca usanDiseñando interfaces
¿Interfaz o clase base abstracta?Diseñando interfaces
El código de dominio depende de una base de datos o frameworkInvirtiendo dependencias
¿Dónde se crean y conectan los objetos?Invirtiendo dependencias
Los llamadores saben cómo otra clase almacena o formatea datosOcultando la implementación
Una clase filtra sus errores o pasos internosOcultando la implementación
Las banderas o campos opcionales permiten combinaciones imposiblesHaciendo imposibles los estados ilegales
Un tipo admite valores que el dominio nunca tieneHaciendo imposibles los estados ilegales
Las palabras del código difieren de las del personalHablando el lenguaje del dominio
Una palabra significa cosas diferentes para dos equiposHablando el lenguaje del dominio
¿Qué objetos deben cambiar juntos?Diseñando agregados
Los guardados chocan o una carga trae demasiadoDiseñando agregados
¿Qué cambios de estado están permitidos?Modelando ciclos de vida
Un objeto cancelado o cerrado cambia de nuevoModelando ciclos de vida
¿Cómo deberían almacenarse y encontrarse los objetos de dominio?Diseñando repositorios
El repositorio tiene un método find por pantallaDiseñando repositorios
Los casos de uso repiten la misma verificación de negocioColocando la lógica de dominio
¿Servicio de dominio, método de entidad o servicio de aplicación?Colocando la lógica de dominio
Otras partes deben reaccionar después de que se guarda un cambioPublicando eventos de dominio
Un mensaje salió para un cambio que se deshizoPublicando eventos de dominio
¿Dónde termina el modelo de un equipo y comienza el de otro?Delimitando contextos
¿Qué partes son centrales y cuáles podemos comprar?Delimitando contextos
¿De qué manera deberían depender las capas?Estratificando el sistema
Una pantalla o trabajo no se puede probar sin su frameworkEstratificando el sistema
Los módulos dependen entre sí en un cicloOrganizando módulos
¿Monolito modular o servicios separados?Organizando módulos
Un cambio en nuestra API rompe las aplicaciones que la llamanCruzando límites del sistema
¿Cómo deberíamos versionar esta API o mensaje?Cruzando límites del sistema
La herramienta de mapeo da forma a nuestras clases de dominioDomando la persistencia
Una lista ejecuta una consulta por filaDomando la persistencia
Las pantallas necesitan datos con forma diferente al modeloSeparando lecturas de escrituras
¿Modelo de lectura, proyección o event sourcing?Separando lecturas de escrituras
¿MVC, MVP o MVVM para esta pantalla?Separando presentación del dominio
Una pantalla edita objetos de dominio directamenteSeparando presentación del dominio
¿Qué patrón de diseño se ajusta a este problema?Eligiendo un patrón
Un patrón se agregó antes de su problemaEligiendo un patrón
Estas clases de patrón podrían ser una funciónPatrones que el lenguaje proporciona
¿Visitor o un conjunto cerrado con coincidencia?Patrones que el lenguaje proporciona
Un método devuelve null cuando no encuentra nadaDiseñando el comportamiento ante fallos
Los rechazos vuelven como códigos que los llamadores ignoranDiseñando el comportamiento ante fallos
Los hilos comparten un objeto y pierden o mezclan sus cambiosManejando el estado compartido
¿Un bloqueo o un único propietario para este estado?Manejando el estado compartido
Una llamada a otro sistema se cuelga o falla a mitad de caminoHaciendo el trabajo fiable
Un reintento hizo el trabajo dos vecesHaciendo el trabajo fiable
No podemos explicar un incidente a partir de nuestros registrosDiseñando qué registrar
¿Qué deberíamos registrar, contar o auditar?Diseñando qué registrar
Una revisión encontró una clase dios o lava flowReconociendo antipatrones
¿Qué antipatrón deberíamos arreglar primero?Reconociendo antipatrones
Las pruebas se rompen aunque el comportamiento no cambióProbando código orientado a objetos
¿Mock, stub o fake para este colaborador?Probando código orientado a objetos
Las pruebas dependen del tiempo o valores aleatoriosDiseñando para la testabilidad
El código se hace público solo para que las pruebas puedan alcanzarloDiseñando para la testabilidad
¿Cómo reestructuramos este código de manera segura?Refactorizando hacia el diseño de objetos
Una refactorización creció demasiado para terminarlaRefactorizando hacia el diseño de objetos
Debemos cambiar código que no tiene pruebasTrabajando con código heredado
Reemplazar un sistema antiguo pieza por piezaTrabajando con código heredado
¿Qué debería verificar esta revisión?Revisando el diseño de objetos
¿Qué hallazgos de la revisión bloquean una fusión?Revisando el diseño de objetos
Nadie recuerda por qué el código tiene esta formaDocumentando decisiones de diseño
¿Qué deberíamos dibujar, y a qué nivel?Documentando decisiones de diseño
Los comentarios repiten el código o lo contradicenComentando lo que el código no puede decir
¿Dónde explicamos por qué este código se ve extraño?Comentando lo que el código no puede decir
Un gancho o marcador del framework contiene una regla de negocioTrabajando dentro de un framework
¿Hasta dónde deberíamos seguir al framework?Trabajando dentro de un framework
Un cálculo también guarda, envía o cambia sus entradasAplicando técnicas funcionales
¿Qué técnicas funcionales encajan en código de objetos?Aplicando técnicas funcionales

Habilidades por lenguaje

Una habilidad por lenguaje mantiene las reglas centrales en un lenguaje y nunca las reemplaza. Una habilidad base por lenguaje es para código sin framework.

  • oo-java, de object-oriented-design-java: records, sealed types, equals y hashCode, excepciones verificadas, Optional y clases cerradas a la extensión.
  • oo-kotlin, de object-oriented-design-kotlin: data classes, sealed types, tipos anulables, delegación con by y funciones de extensión.
  • oo-typescript, de object-oriented-design-typescript: identificadores marcados, estado #private, clases abstractas, decoradores, uniones discriminadas y una raíz de composición.
  • oo-javascript, de object-oriented-design-javascript: cierre de variables privadas, prototipos, funciones de fábrica y el patrón módulo.
  • oo-python, de object-oriented-design-python (planeado): @dataclass, @property, __slots__, protocolos y typing.
  • oo-csharp, de object-oriented-design-csharp (planeado): records, tipos anulables, LINQ, propiedades de solo inicialización y clases selladas.
  • oo-ruby, de object-oriented-design-ruby (planeado): módulos, attr_reader, attr_accessor, bloques y Struct.
  • oo-php, de object-oriented-design-php (planeado): tipos declarados, readonly, enumeraciones, traits y union types.
  • oo-swift, de object-oriented-design-swift (planeado): structs, protocolos, enumeraciones con valores asociados, Codable y tipos opcionales.
  • oo-go, de object-oriented-design-go (planeado): interfaces, composición de structs, métodos de valor/receptor y tipos opacos.

Meta-reglas

  1. La identidad de un objeto no es su estado. Dos clientes con el mismo nombre y dirección siguen siendo dos clientes. Los valores son lo que son, no quiénes son.
  2. No expongas una decisión de infraestructura en el dominio. Sin excepciones.
  3. La persistencia es una consecuencia, no una intención de diseño. Las columnas de la base de datos no son atributos de dominio.
  4. Haz que los estados ilegales no sean representables. Si no puedes construirlo, no se filtrará en una prueba.
  5. Encapsula lo que varía. Pon tras una interfaz o clase base lo que podría cambiar; no pongas lo que es estable en el dominio.
  6. La herencia captura especialización, no reutilización. La reutilización pertenece a la composición.
  7. Un método no debería hacer ambas cosas: decidir y hacer. O despacha a otra cosa, o hace el trabajo ella misma.
  8. Depende de abstracciones. Las dependencias concretas impiden la prueba y el cambio.
  9. Los objetos se comunican a través de mensajes, no de getters. Preguntar por datos para decidir por otro objeto es código ajeno.
  10. Los nombres provienen del dominio. Si los desarrolladores y los expertos del negocio usan la misma palabra, es la palabra correcta.

Skills relacionados