X.7 Justificación de la Selección de Patrones de Diseño

X.7.1 Introducción

La elección de los patrones documentados en las secciones anteriores no obedeció ni al azar ni a la imitación de trabajos de grado precedentes. Es habitual que las tesis de pregrado en Tecnología e Ingeniería de Sistemas reporten un conjunto recurrente de patrones —Modelo-Vista-Controlador (MVC), Singleton, Observer, Repository y una mención superficial de Factory— cuya presencia, en la mayoría de los casos, no responde a una decisión de diseño consciente sino a una imposición del framework empleado. MVC, por ejemplo, viene dado por Laravel, Django o Spring; el Singleton de la conexión a base de datos lo provee el propio motor de persistencia; y Observer suele mencionarse en el marco teórico sin una implementación verificable en el código entregado. El resultado es un catálogo genérico que describe la herramienta utilizada, pero que no evidencia pensamiento de diseño por parte del autor.

PYMETORY adopta deliberadamente el enfoque contrario. En lugar de enumerar los patrones que el framework impone, se realizó un análisis del código fuente real del sistema —apoyado en un grafo de conocimiento de 3.243 nodos y 367 comunidades— para identificar qué problemas concretos del dominio de inventarios habían sido resueltos y mediante qué estructura. De ese análisis emergieron cinco patrones, cada uno asociado a un problema específico y verificable: la configuración multicanal de alertas (Strategy), el control de acceso por capas (Chain of Responsibility), la unión de persistencia y dominio en las entidades (Active Record), el despacho transaccional FEFO (Transaction Script) y la construcción de datos de prueba (Factory Method). La presente sección contrasta cada uno de estos patrones con la alternativa "típica" que una tesis convencional habría reportado, y argumenta por qué dicha alternativa habría sido inadecuada o redundante para el caso particular de PYMETORY.

X.7.2 Tabla comparativa: patrón típico vs. patrón elegido

Problema del sistemaPatrón típico en tesisPatrón elegido en PYMETORYRazón del cambio
Notificar alertas de inventario Observer Strategy Los canales no son suscriptores pasivos; el administrador elige cuáles se ejecutan. El problema es seleccionar un algoritmo, no avisar a una lista.
Controlar el acceso por rol Guard simple / if en el controlador Chain of Responsibility Se requieren varias validaciones independientes y reordenables (auth, verified, rol), no una única comprobación monolítica.
Acceder a los datos del inventario Repository Active Record Eloquent ya es Active Record. Añadir un Repository sería una capa vacía —código muerto— para la complejidad real del proyecto.
Ejecutar el despacho FEFO Domain Model Transaction Script El despacho es un procedimiento lineal y transaccional de ~30 líneas. Un modelo de dominio rico sería sobreingeniería.
Construir datos para las pruebas Factory (mención teórica) Factory Method (uso real) El mismo patrón, pero como infraestructura efectiva: sin él no existirían las 60 pruebas PHPUnit. No es adorno.

X.7.3 Análisis de cada decisión

a) Notificaciones: Observer → Strategy

La mayoría de los trabajos que abordan un módulo de notificaciones recurren al patrón Observer, que modela un "sujeto" que avisa automáticamente a una lista de "observadores" suscritos cada vez que ocurre un evento. En términos sencillos, Observer es como una lista de correo: cuando algo sucede, todos los suscritos reciben el mismo aviso, de forma automática, sin que nadie decida caso por caso.

Ese modelo no se ajusta al problema real de PYMETORY. Aquí los canales de alerta —notificación en aplicación, Telegram y correo— no se suscriben solos ni reciben todos el mismo trato: es el administrador quien configura explícitamente cuáles están activos, y el sistema debe decidir en tiempo de ejecución qué método de envío ejecutar según esa configuración. El problema, por tanto, no es "avisar a quien esté suscrito", sino "elegir cuál de varios algoritmos de envío aplicar". Esa es precisamente la definición del patrón Strategy: una familia de algoritmos intercambiables (cada canal) seleccionados según una condición. La evidencia está en app/Services/AlertService.php, método send() (líneas 14–25), donde cada canal se invoca condicionalmente según el valor leído de la configuración.

b) Control de acceso: Guard simple → Chain of Responsibility

La solución convencional al control de acceso consiste en una verificación única —un if (Auth::check()) dentro de cada controlador, o un "guard" monolítico. Para un profesor de sistemas, la analogía es la de un único portero en la entrada que revisa simultáneamente la identificación, el permiso y el rol del visitante.

PYMETORY requiere, en cambio, varias validaciones independientes: que el usuario esté autenticado, que haya verificado su correo y que posea el rol adecuado. La solución adoptada es Chain of Responsibility: en lugar de un portero, una fila de porteros donde cada uno revisa una sola cosa y, si la aprueba, deja pasar al siguiente (auth → verified → role:admin). La evidencia está en app/Http/Middleware/CheckRole.php, método handle() (líneas 20–27), y en su aplicación declarativa en routes/web.php.

c) Acceso a datos: Repository → Active Record

El patrón Repository es quizá el más sobreutilizado en las tesis de la región. El problema es que, sobre un ORM como Eloquent, suele ser redundante: Eloquent ya implementa de forma nativa el patrón Active Record, en el que cada modelo representa una fila de la tabla y contiene tanto su persistencia como su lógica de dominio. En lenguaje claro: el modelo Lote ya sabe leerse y guardarse en la base de datos, y además ya sabe calcular si está crítico o cuánto vale.

Introducir un Repository encima de Eloquent habría producido una capa de envoltura que no agrega valor —"código muerto" que solo reenvía llamadas. La decisión fue conservar Active Record y aprovechar que el modelo Lote concentra las reglas del dominio en un único lugar. La sección X.3 documenta el contraste formal entre Active Record y Data Mapper.

d) Despacho FEFO: Domain Model → Transaction Script

Una tesis que busque demostrar sofisticación podría proponer un Domain Model: distribuir la lógica del despacho entre múltiples objetos de dominio ricos. Pero el despacho FEFO de PYMETORY no tiene esa complejidad: es un procedimiento lineal —ordenar lotes por vencimiento, descontar cantidades, marcar los agotados y registrar cada movimiento en el Kardex— que se resuelve en unas treinta líneas dentro de una única transacción.

En este escenario, un Domain Model sería sobreingeniería. La elección fue Transaction Script, que organiza la lógica como un procedimiento único por petición, con garantía de atomicidad mediante DB::transaction. Evidencia en app/Http/Controllers/ConsumptionController.php, método store() (líneas 38–67).

e) Datos de prueba: Factory (teórica) → Factory Method (real)

Factory es el único patrón que PYMETORY comparte con el repertorio típico. La diferencia es de fondo: en muchos trabajos aparece como mención teórica. En PYMETORY, Factory Method es infraestructura efectiva de pruebas: sin LoteFactory no existirían las 60 pruebas PHPUnit. Cada prueba necesita un Lote con sus dependencias —la fábrica lo construye en una línea. No es adorno, es el habilitador directo de la estrategia de verificación del proyecto.

X.7.4 Conclusión

La selección de patrones presentada no constituye una lista genérica de conceptos extraídos de un catálogo, sino una bitácora de decisiones de diseño: para cada problema concreto del dominio de inventarios se evaluó la solución convencional, se identificaron sus limitaciones en el contexto específico de PYMETORY y se justificó la alternativa adoptada con evidencia en el código fuente. Tres de las cinco decisiones consistieron en descartar deliberadamente el patrón que una tesis típica habría incluido —Observer, Repository y Domain Model— por considerarlo inadecuado o redundante. Esta capacidad de elegir y, sobre todo, de no usar un patrón cuando no aporta valor es la manifestación más clara del pensamiento crítico de diseño que se busca demostrar en un trabajo de grado.