Software Architect · Módulo 05

Descomponer no es ordenar archivos en carpetas. Es elegir las boundaries dentro de las cuales un cambio se mantiene local.

Cohesion · coupling · bounded context · ownership

§ 01

Una buena boundary corre por donde el sistema cambia naturalmente de responsabilidad, de lenguaje o de ritmo de cambio.

La descomposición arranca por las razones de cambio

Si una puerta la mueven todo el tiempo por el depósito y otra por la entrada de invitados, son dos zonas distintas del edificio. No tienen por qué ir en la misma pared.

Un componente con high cohesion contiene cosas que cambian por el mismo motivo. Un componente con low coupling sabe poco de sus vecinos y se comunica con un contrato claro. Estas dos propiedades importan más que el nombre de cualquier pattern.

Una mala descomposición suele verse prolija en el IDE: controllers, services, repositories, utils. Pero si un retoque chico de producto te obliga a tocar cinco capas y tres dominios, el sistema sigue mal cortado. Una buena descomposición te deja cambiar checkout, billing o identity sin tener que cargar mentalmente el resto del producto.

Una boundary es también ownership

Un mapa de la ciudad no sirve si nadie sabe quién arregla los puentes, quién maneja los semáforos y a quién llamar después de un choque.

Una architectural boundary necesita un owner. Si un módulo es "compartido" pero todos lo modifican, se convierte rápido en una zona de riesgo. Si un bounded context le pertenece a un equipo, ese equipo gana el derecho de evolucionar el modelo interno y el deber de mantener estable el contrato externo.

Por eso descomposición y team topology van de la mano. A veces la pregunta correcta no es "qué servicio extraemos" sino "qué equipo debería ser dueño de este flujo end-to-end".

§ 02

El mismo dominio se puede cortar por tablas, por capas o por flujos de negocio. La tercera variante es la que suele funcionar.

Ejemplo: checkout como vertical slice

La caja de un local es dueña del recorrido de compra: carrito, precio, pago, ticket. No es una "capa de botones" ni una "capa de SQL".

En e-commerce, checkout puede ser dueño del pricing snapshot, del payment intent, del order draft y del failure handling. Catalog sigue siendo dueño de los productos, identity de los usuarios, warehouse del stock. Checkout no copia la lógica de otros equipos — pide los datos vía contratos y publica un evento OrderPlaced.

Ese vertical slice resulta cómodo: el equipo ve el flujo del usuario completo y los cambios en pagos no se derraman por todos los subsistemas.

Antiejemplo: capas técnicas como única boundary

Si todos los cocineros cortan verdura en una sala, fríen en otra y salan en una tercera, un pedido simple termina exigiendo coordinar el edificio entero.

El sistema está partido en user-service, order-service, payment-service, pero adentro de cada servicio hay un common-domain compartido, una base compartida y validators compartidos. Formalmente hay servicios. Funcionalmente no hay boundaries.

Peor todavía cuando los equipos son dueños de capas: equipo de frontend, equipo de backend, equipo de base de datos. Toda feature se vuelve un proyecto de coordinación. Eso infla el lead time y la cognitive load.

Autoevaluación
  • ¿Cuál es la razón de cambio de este módulo? - ¿Puede el equipo cambiarlo sin negociar con cinco vecinos? - ¿Tiene la boundary un owner? - ¿Qué datos e invariantes realmente pertenecen a este contexto?