En el desarrollo de software moderno, el diseño de sistemas ya no es solo una etapa técnica del ciclo de vida del proyecto. Es una decisión estratégica que determina si una organización va a poder escalar, mantener la seguridad de sus datos y adaptarse a nuevas amenazas sin reescribir todo desde cero. Desde la perspectiva de ciberseguridad, una arquitectura mal diseñada es una vulnerabilidad que se materializa tarde o temprano.
Requisitos funcionales vs. no funcionales: el fundamento invisible
Cuando definimos un sistema, tendemos a concentrarnos en lo que debe hacer: registrar usuarios, procesar pagos, generar reportes. Esos son los requisitos funcionales, los más visibles y los que primero validamos en pruebas. Pero los que realmente determinan si un sistema sobrevive en producción son los requisitos no funcionales: rendimiento, escalabilidad, disponibilidad y, sobre todo, seguridad.
Un sistema puede registrar usuarios perfectamente (funcional) pero exponer hashes de contraseñas en logs si no se diseñó con requisitos de confidencialidad (no funcional). Un firewall puede filtrar tráfico correctamente, pero si la arquitectura monolítica no permite aislar componentes comprometidos, una brecha en un módulo afecta todo el sistema. La distinción no es académica: es operativa.
En mi experiencia gestionando infraestructura para clientes bajo cPanel, Dokploy y VPS, los problemas que más horas de soporte generan no son bugs funcionales. Son fallas de diseño: un servicio que no escala bajo carga, una base de datos sin replicación que se convierte en single point of failure, o una API sin rate limiting que abre la puerta a ataques de fuerza bruta.
Patrones de diseño: soluciones que ya fueron probadas
Los patrones de diseño existen porque alguien ya resolvió el problema que vos estás por enfrentar, y documentó la solución para que no repitas sus errores. En ciberseguridad, esto es crítico: reutilizar un patrón probado reduce la superficie de ataque porque trabajás con código que la comunidad ya auditó, corrigió y endureció.
Singleton, por ejemplo, garantiza una única instancia de una clase — útil para conexiones a bases de datos o configuraciones globales. Desde seguridad, esto permite centralizar el control de acceso: si solo hay una instancia del gestor de sesiones, es más fácil auditar quién entra y cuándo. El riesgo está en el testing: una instancia global dificulta las pruebas unitarias aisladas, lo que puede llevar a que errores de seguridad pasen desapercibidos.
Factory abstrae la creación de objetos, ocultando las clases concretas al código cliente. En términos de seguridad, esto permite implementar sanitización de inputs en el punto de creación: si todos los objetos de usuario se instancian a través de una factory que valida y escapa datos, reducís la probabilidad de inyección en toda la aplicación.
Observer establece notificaciones automáticas entre componentes desacoplados. En monitoreo de seguridad, esto es la base de los sistemas de detección de intrusiones: cuando un componente detecta actividad anómala, notifica a los observadores (logger, firewall, sistema de alertas) sin necesidad de acoplamiento directo. La debilidad potencial es la gestión de observadores: demasiados listeners sin control pueden generar fugas de información si uno de ellos loggea datos sensibles sin filtrar.
Arquitectura de software: la estructura que sostiene (o destruye) la seguridad
La elección entre arquitectura monolítica, en capas o de microservicios no es solo una decisión técnica. Es una decisión de riesgo.
Monolítica: Todo en un solo bloque. Simple de implementar, difícil de escalar y de aislar. Si un atacante compromete un punto de entrada, tiene acceso potencial a toda la base de código. En entornos donde la seguridad es crítica, esto significa que una vulnerabilidad en un módulo secundario puede comprometer datos principales. Es económica al inicio, pero costosa cuando hay que segmentar.
En capas: Separación lógica entre presentación, lógica de negocio y datos. Permite aplicar controles de seguridad por capa: firewalls de aplicación en la capa de presentación, validación de negocio en la lógica, y cifrado en reposo en la capa de datos. El riesgo está en las comunicaciones entre capas: si no están autenticadas y cifradas, un atacante que comprometa una capa puede pivotear a las demás.
Microservicios: Descompone la aplicación en servicios independientes que escalan y se despliegan solos. Desde ciberseguridad, esto permite el principio de mínimo privilegio: cada servicio accede solo a los recursos que necesita. Si comprometen el servicio de notificaciones, no tienen acceso al servicio de pagos. Pero la complejidad aumenta: más superficie de ataque (más APIs expuestas), más interconexiones que proteger, y más dificultad para auditar flujos de datos entre servicios.
La realidad que veo en el campo es que muchas organizaciones eligen microservicios por moda, no por necesidad, y terminan con una arquitectura distribuida que no tienen capacidad de monitorear ni de asegurar. El diseño debe responder a los requisitos no funcionales reales, no a las tendencias del mercado.
Hacia dónde evoluciona el diseño de sistemas
Las arquitecturas impulsadas por datos (Data-Driven) y basadas en eventos (Event-Driven) están ganando terreno porque permiten sistemas que reaccionan en tiempo real a cambios de estado. En ciberseguridad, esto se traduce en capacidad de respuesta: un sistema que detecta un patrón de acceso anómalo y desencadena automáticamente el aislamiento de la cuenta comprometida, sin intervención humana.
Tecnologías como Inteligencia Artificial, computación en la nube y blockchain están redefiniendo las posibilidades arquitectónicas, pero también sus riesgos. Un sistema que utiliza IA para decisiones de seguridad hereda los sesgos y vulnerabilidades del modelo entrenado. Un despliegue en la nube multi-region hereda la complejidad de gestión de identidades y acceso (IAM) de cada proveedor.
Lo que no cambia es la necesidad de un diseño fundamentado: identificar requisitos funcionales y no funcionales desde el inicio, aplicar patrones probados, documentar la arquitectura con estándares como UML e ISO/IEC/IEEE 42010, y —lo más importante— iterar. El diseño de sistemas no es una fase que termina cuando empieza la codificación. Es un proceso continuo que debe adaptarse a nuevas amenazas, nuevas tecnologías y nuevas demandas del negocio.
Material basado en apuntes del curso de Diseño de Sistemas, Instituto Profesional IPG.

