Code Partitioning Strategies

Pregunta y alcance

¿Qué criterio utilizamos para dividir física y conceptualmente el código? Code Partitioning Strategies es una práctica para elegir y combinar esos criterios. No representa una única arquitectura ni asigna una arquitectura distinta a cada carpeta.

Particionar puede facilitar navegación, encapsulación y ownership; esas propiedades requieren decisiones que el agrupamiento físico no demuestra. modularity examina encapsulación y relaciones efectivas; granularity necesita precisar qué unidades comparamos, sin inferir su tamaño arquitectónico del número de carpetas o proyectos. Una estructura puede parecer alineada con el negocio y permitir que cualquier parte acceda a detalles privados de otra.

Parnas analiza la importancia del criterio de división y propone ocultar decisiones susceptibles de cambio, en lugar de identificar módulos automáticamente con pasos de ejecución. On the Criteria To Be Used in Decomposing Systems into Modules. La pregunta práctica es qué decisión queremos encapsular y qué cambios deberían permanecer juntos.

Criterios que pueden combinarse

La tabla distingue focos, no categorías excluyentes ni arquitecturas independientes:

CriterioQué agrupaQué necesita comprobar
Technical layerResponsabilidades técnicas, como presentación o persistencia.Dependencias y abstracciones permitidas entre grupos.
FeatureComportamiento de una capacidad visible para usuarios.Qué partes cambian juntas y cuáles pertenecen a políticas comunes.
Domain/moduleReglas y responsabilidad de una área del negocio.Contratos, invariantes y ownership lógico.
ComponentUna capacidad encapsulada detrás de una interfaz.Acceso restringido a detalles de implementación.
Bounded contextCódigo que expresa un modelo dentro de su contexto de validez.Lenguaje, consistencia del modelo y traducción entre contextos.
Use caseUn objetivo concreto de interacción con la aplicación.Coordinación y reglas necesarias para ese recorrido.
Deployment unitCódigo entregado dentro de un artefacto o unidad desplegable.Qué debe versionarse y liberarse conjuntamente.
PluginUna contribución a contratos de un host.Compatibilidad, lifecycle y dependencias de extensión.
Pipeline stageUna transformación del procesamiento.Entrada/salida, estado y posibilidades de composición.

No hay una correspondencia obligatoria entre esos criterios y directorios, repositorios, namespaces o proyectos. El mecanismo físico debe ayudar a hacer cumplir la frontera conceptual con un costo razonable.

Technical partitioning

Un agrupamiento familiar es:

Controllers/
Services/
Repositories/
Models/

Facilita navegar por tecnología y aplicar convenciones uniformes. Un equipo puede localizar rápidamente controladores o mecanismos de persistencia. Sin embargo, cambiar una feature puede requerir modificar archivos repartidos entre todos esos grupos.

Carpetas técnicas no prueban layered-architecture. Para hablar de capas necesitamos responsabilidades y reglas de interacción/dependencia. Si un controller accede libremente a cualquier repository y todo tipo es público, la estructura física no conserva el límite pretendido.

En un ejemplo propio de revisión documental, una modificación de permisos puede afectar controller, servicio y mapping. La partición técnica ayuda a encontrar cada categoría, pero no necesariamente a observar todo el cambio de aprobación como una unidad.

Feature y use case partitioning

Una capacidad amplia puede agruparse como Reviews/ o Reports/. Un caso de uso concreto puede organizarse como Features/ApproveReview/ o Features/RejectReview/. La granularidad difiere: una feature puede contener varios recorridos y reglas compartidas.

Este agrupamiento favorece localidad de cambio y lectura orientada al comportamiento. Puede resultar menos directo encontrar todos los consumidores de una tecnología o controlar decisiones repetidas entre features. La necesidad de compartir una regla estable no desaparece.

Carpetas por feature no prueban vertical-slice-architecture. La arquitectura necesita cohesión por caso de uso y decisiones sobre dependencias y responsabilidades. Mover clases a ApproveReview sin cambiar sus accesos o sus obligaciones puede ser solamente reorganización.

En nuestro ejemplo, validaciones con intención diferente pueden permanecer cerca de cada recorrido. La política única de quién puede aprobar requiere una autoridad coherente: copiarla por comodidad puede introducir divergencia.

Dominio, componentes y bounded contexts

Agrupar Reviews, Reporting y Billing puede expresar responsabilidades del negocio. Un módulo debe aclarar qué información controla y qué contrato ofrece. Un componente puede reunir una capacidad técnica o de negocio y ocultar su implementación.

Simon Brown distingue organizar código de encapsularlo en su análisis de package by component. Su ejemplo muestra que permisos de acceso y dependencias hacen efectiva una frontera que los nombres de paquetes no garantizan.

Bounded context expresa un límite de validez de un modelo y su lenguaje; no es un sinónimo de carpeta, módulo o servicio. Fowler explica modelos y relaciones entre contextos en Bounded Context. No se desarrolla aquí un nuevo canonical de DDD.

En nuestro ejemplo, «documento aprobado» en el flujo de revisión y «documento facturable» en Billing pueden tener condiciones distintas. Compartir una clase global Document no elimina esa diferencia. La partición debe evitar mezclar autoridades por tener vocabulario parcialmente común.

Código, deployment y decomposición arquitectónica

Code partition no equivale a deployment partition. Un módulo puede implementarse como library, namespace, project, package o componente de runtime sin entregarse de manera independiente. Un modular-monolith combina módulos protegidos con una entrega común. modifiability evalúa el cambio localizado y deployability cómo su artifact llega a ejecución: module y deployment unit no son identidades equivalentes.

Organizar según deployment unit puede hacer visible qué código necesita liberarse junto. No demuestra independencia si los artefactos requieren cambios sincronizados, comparten representaciones privadas o asumen la misma versión de todas sus dependencias.

Code partitioning enfatiza organización y estructura del código. decomposition puede establecer además límites de ownership, datos, equipos, runtime, fallos y deployment. Una partición de código puede contribuir a esa descomposición y ser arquitectónicamente significativa; no se reduce a una decisión cosmética.

Mover archivos de Billing a otro proyecto no crea automáticamente un nuevo propietario de datos ni contiene sus fallos. Convertirlo en proceso remoto agrega contratos y riesgos de interacción que un cambio de carpetas no resuelve. architectural-significance ayuda a examinar esas consecuencias.

Plugins y etapas de procesamiento

Particionar por plugin-architecture puede reunir implementación, manifiesto y recursos de una contribución. El contrato que controla el host establece qué puede hacer y cómo evoluciona. No todos los módulos del negocio necesitan transformarse en plugins.

Particionar por pipe-and-filter acerca las decisiones de una transformación y sus contratos de entrada/salida. Una carpeta Decode/ no garantiza independencia si modifica estado compartido que todas las etapas conocen.

En nuestro ejemplo, un exportador opcional puede ser un plugin dentro de Reporting. Su procesamiento puede contener etapas de normalización y formato. Son dimensiones jerárquicas compatibles si se respetan obligaciones, no una razón para multiplicar abstracciones.

Composición jerárquica y revisión

Una organización plausible es:

Domain modules
└── Reviews
    ├── Use cases
    │   ├── ApproveReview
    │   └── RejectReview
    ├── Domain policies
    └── Infrastructure adapters

Primero agrupamos por módulo; después por caso de uso y por responsabilidades que conviene proteger. Otro módulo puede necesitar una organización diferente. Layer vs feature no es una elección binaria universal.

Para revisar esta práctica, elegir cambios reales: agregar un permiso, sustituir persistencia, incorporar un exportador y modificar un formato. Identificar qué partes deben cambiar, qué contratos permanecen y qué accesos deberían prohibirse. Después comprobar si los mecanismos de visibilidad, proyectos o revisiones mantienen esas obligaciones.

La partición agrega costos de navegación, build y coordinación. Crear un proyecto por clase puede dificultar mantenimiento; agrupar todo en Common puede conectar cambios sin intención compartida. Es preferible ajustar límites cuando existe evidencia del problema que completar una jerarquía anticipada.

architecture-profile describe compromisos de sistema sobre varios ejes. Los criterios de este documento ayudan a materializar su interior, sin sustituir las decisiones de arquitectura. internal-structure conecta patrones concretos y mantiene esta práctica como una herramienta de elección contextual.