Un sistema puede hacer exactamente lo que se le pidió —cumplir todos sus requisitos funcionales— y aun así ser un fracaso: porque es lento, se cae cada semana, no resiste un ataque o cuesta una fortuna mantenerlo. Todo eso lo gobiernan los atributos de calidad, también llamados requisitos no funcionales. Son, en gran medida, lo que la arquitectura busca lograr: el "cómo de bien" frente al "qué hace". En esta lección aprenderás a identificarlos, a distinguirlos de los requisitos funcionales y, sobre todo, a especificarlos de forma medible mediante escenarios de calidad, porque un atributo que no se puede medir no se puede diseñar ni verificar.
Contenido
- Funcionales frente a no funcionales
- Catálogo de atributos de calidad
- El problema de los requisitos vagos
- Escenarios de calidad: cómo especificarlos
- Tácticas arquitectónicas para lograrlos
- Conflictos entre atributos
- Funcionales frente a no funcionales
Conviene tener clara la frontera desde el principio.
| Tipo de requisito | Responde a | Ejemplo |
|---|---|---|
| Funcional | ¿Qué hace el sistema? | "El usuario puede transferir dinero entre sus cuentas" |
| No funcional (atributo de calidad) | ¿Cómo de bien lo hace? | "La transferencia se completa en menos de 2 segundos el 99% de las veces" |
Los requisitos no funcionales también se conocen como atributos de calidad, NFR (Non-Functional Requirements) o -ilities en inglés (scalability, availability, etc.). Son responsabilidad directa de la arquitectura: la funcionalidad puede implementarse de muchas formas, pero solo algunas estructuras logran la disponibilidad o el rendimiento exigidos.
- Catálogo de atributos de calidad
Existen taxonomías formales (por ejemplo, la norma ISO/IEC 25010). A continuación, los atributos más relevantes en la práctica:
| Atributo | Definición breve | Cómo se suele medir |
|---|---|---|
| Rendimiento | Rapidez de respuesta y uso eficiente de recursos | Latencia (ms), throughput (peticiones/s) |
| Escalabilidad | Capacidad de crecer ante más carga | Usuarios concurrentes soportados, coste por unidad de carga |
| Disponibilidad | Proporción de tiempo operativo | % de uptime (p. ej., 99,9%), MTBF, MTTR |
| Fiabilidad | Funcionar correctamente sin fallos | Tasa de errores, fallos por millón de operaciones |
| Seguridad | Proteger datos y funciones de accesos indebidos | Vulnerabilidades, cumplimiento de normativas |
| Mantenibilidad | Facilidad de cambio y corrección | Tiempo medio de implementar un cambio, complejidad |
| Testabilidad | Facilidad de probar el sistema | Cobertura, tiempo de la suite de pruebas |
| Usabilidad | Facilidad de uso para el usuario final | Tasa de tareas completadas, tiempo de aprendizaje |
| Observabilidad | Capacidad de entender el estado interno desde fuera | Cobertura de logs, métricas y trazas |
| Portabilidad | Facilidad de mover el sistema a otro entorno | Esfuerzo de migración |
Nota sobre disponibilidad: el porcentaje de uptime tiene consecuencias muy concretas en tiempo de caída tolerado al año.
| Disponibilidad | Caída máxima al año (aprox.) |
|---|---|
| 99% ("dos nueves") | ~3,65 días |
| 99,9% ("tres nueves") | ~8,77 horas |
| 99,99% ("cuatro nueves") | ~52,6 minutos |
| 99,999% ("cinco nueves") | ~5,26 minutos |
Cada "nueve" adicional dispara el coste y la complejidad. Por eso es un atributo que debe negociarse con el negocio, no fijarse al máximo "por si acaso".
- El problema de los requisitos vagos
Compara estas dos formas de expresar el mismo requisito:
- Vago: "El sistema debe ser rápido."
- Medible: "El 95% de las búsquedas de productos deben responder en menos de 300 ms con 1.000 usuarios concurrentes."
El primero es inútil: ¿rápido para quién, en qué operación, bajo qué carga, con qué objetivo? No se puede diseñar contra él ni verificar si se cumple. El segundo es medible, específico y verificable. La regla de oro es:
Un atributo de calidad que no es medible no es un requisito, es un deseo.
- Escenarios de calidad: cómo especificarlos
El SEI (Software Engineering Institute) propone los escenarios de calidad como forma estándar de especificar atributos no funcionales. Un escenario tiene seis partes:
| Parte | Significado | Ejemplo (rendimiento) |
|---|---|---|
| Fuente del estímulo | Quién/qué genera el evento | Un usuario externo |
| Estímulo | El evento que llega | Lanza una búsqueda de productos |
| Artefacto | Parte del sistema afectada | El servicio de catálogo |
| Entorno | Condiciones en que ocurre | En hora pico, con 1.000 usuarios concurrentes |
| Respuesta | Qué hace el sistema | Devuelve los resultados de la búsqueda |
| Medida de la respuesta | Criterio de éxito cuantificable | En menos de 300 ms el 95% de las veces |
Leído de corrido: "Un usuario externo lanza una búsqueda de productos en el servicio de catálogo en hora pico con 1.000 usuarios concurrentes; el sistema devuelve los resultados en menos de 300 ms el 95% de las veces."
Podemos representarlo de forma estructurada:
escenario_calidad:
atributo: rendimiento
fuente: usuario_externo
estimulo: busqueda_de_productos
artefacto: servicio_catalogo
entorno: hora_pico_1000_usuarios_concurrentes
respuesta: devolver_resultados_busqueda
medida:
metrica: tiempo_respuesta_ms
objetivo: 300
percentil: 95 # el 95% de las peticiones debe cumplir el objetivoEste YAML formaliza el escenario para que pueda discutirse y verificarse. Lo importante no es el formato concreto, sino que cada escenario incluya las seis partes. El campo percentil: 95 es clave: especificar un percentil (P95, P99) en lugar de un promedio evita engaños, porque un promedio bajo puede esconder un pequeño porcentaje de peticiones desastrosamente lentas que arruinan la experiencia.
Un escenario de disponibilidad podría escribirse así:
escenario_calidad:
atributo: disponibilidad
fuente: nodo_del_sistema
estimulo: caida_inesperada_de_una_instancia
artefacto: servicio_de_pagos
entorno: operacion_normal
respuesta: redirigir_trafico_a_instancia_sana_sin_perdida_de_datos
medida:
objetivo_uptime: "99.9%"
tiempo_recuperacion_max_segundos: 30Aquí el estímulo no viene de un usuario, sino de un fallo interno (la caída de una instancia). La respuesta esperada es que el sistema se recupere automáticamente redirigiendo el tráfico, con un objetivo de disponibilidad del 99,9% y un tiempo de recuperación máximo de 30 segundos. Especificarlo así permite diseñar y probar la tolerancia a fallos de forma concreta.
- Tácticas arquitectónicas para lograrlos
Una táctica es una decisión de diseño que influye en un atributo de calidad concreto. Algunas habituales:
- Rendimiento: caché, índices, balanceo de carga, procesamiento asíncrono.
- Disponibilidad: redundancia, failover automático, health checks, circuit breakers.
- Escalabilidad: escalado horizontal (más instancias), particionado de datos (sharding), colas para absorber picos.
- Seguridad: autenticación y autorización, cifrado en tránsito y en reposo, principio de mínimo privilegio.
- Mantenibilidad: bajo acoplamiento, alta cohesión, modularidad, pruebas automatizadas.
// Ejemplo de táctica de disponibilidad: un circuit breaker simplificado.
// Si un servicio dependiente falla repetidamente, dejamos de llamarlo un tiempo
// para no agotar recursos y dar margen a que se recupere ("fail fast").
public class CircuitBreaker {
private int fallosConsecutivos = 0;
private final int umbral = 5; // a partir de 5 fallos, abrimos el circuito
private boolean abierto = false;
public Respuesta llamar(ServicioRemoto servicio) {
if (abierto) {
// Circuito abierto: no llamamos, devolvemos una respuesta de reserva.
return Respuesta.degradada();
}
try {
Respuesta r = servicio.invocar();
fallosConsecutivos = 0; // éxito: reiniciamos el contador
return r;
} catch (Exception e) {
fallosConsecutivos++;
if (fallosConsecutivos >= umbral) {
abierto = true; // demasiados fallos: abrimos el circuito
}
return Respuesta.degradada();
}
}
}Este ejemplo Java implementa de forma muy simplificada el patrón circuit breaker (cortacircuitos), una táctica clásica de disponibilidad. La idea: si un servicio remoto falla umbral veces seguidas (fallosConsecutivos >= umbral), el circuito se "abre" (abierto = true) y dejamos de llamarlo, devolviendo una respuesta degradada inmediata en lugar de esperar a que vuelva a fallar. Esto evita que un servicio caído arrastre a todo el sistema (efecto dominó) y le da tiempo a recuperarse. En producción se usarían librerías maduras como Resilience4j, pero el concepto es este.
- Conflictos entre atributos
Los atributos de calidad casi nunca son independientes: mejorar uno suele perjudicar a otro. Por eso la arquitectura es el arte de los compromisos (que veremos en detalle en la siguiente lección).
| Si mejoras... | Puedes perjudicar... | Motivo |
|---|---|---|
| Seguridad (más cifrado/validaciones) | Rendimiento | El cifrado y las comprobaciones consumen tiempo |
| Disponibilidad (más redundancia) | Coste | Más servidores y replicación cuestan dinero |
| Rendimiento (más caché) | Consistencia | Los datos en caché pueden quedar obsoletos |
| Escalabilidad (sistemas distribuidos) | Mantenibilidad/simplicidad | Lo distribuido es más complejo de operar y depurar |
La conclusión práctica es que no existe la arquitectura "óptima" en abstracto: existe la arquitectura adecuada para un conjunto priorizado de atributos de calidad. Por eso el primer trabajo del arquitecto es lograr que el negocio priorice: ¿qué importa más, el coste o la disponibilidad?, ¿la velocidad o la consistencia perfecta?
Errores Comunes y Consejos
- Dejar los NFR para el final. Los atributos de calidad deben capturarse al inicio, porque condicionan la estructura completa. Añadir disponibilidad a un sistema que no se diseñó para ella es carísimo.
- Especificarlos de forma vaga. "Rápido", "seguro", "escalable" no son requisitos. Usa escenarios de calidad con medidas concretas.
- Pedir el máximo en todo. Querer cinco nueves de disponibilidad, latencia mínima y coste mínimo a la vez es contradictorio. Hay que priorizar.
- Usar promedios en lugar de percentiles. Un promedio oculta los casos peores. Mide P95/P99.
- Consejo: convierte cada NFR en algo verificable. Si no sabes cómo medir que se cumple, reescríbelo hasta que puedas.
Ejercicios
Ejercicio 1. Reescribe el siguiente requisito vago en un escenario de calidad con sus seis partes: "El sistema de login debe ser seguro y rápido".
Ejercicio 2. Una tienda online exige 99,99% de disponibilidad. ¿Cuánto tiempo de caída al año tolera, aproximadamente? ¿Qué dos tácticas propondrías para alcanzarlo y qué atributo se vería perjudicado?
Ejercicio 3. Identifica el conflicto entre atributos en esta decisión: "Vamos a cifrar todos los datos en la base de datos y validar cada campo en tres capas distintas". ¿Qué atributo mejora y cuál se resiente?
Soluciones
Solución 1. Ejemplo de escenario para la parte de rendimiento del login: Fuente: un usuario registrado. Estímulo: envía sus credenciales. Artefacto: el servicio de autenticación. Entorno: operación normal con 500 usuarios concurrentes. Respuesta: valida las credenciales y devuelve un token de sesión. Medida: en menos de 500 ms el 99% de las veces. (Para la parte de seguridad se redactaría otro escenario aparte, p. ej.: ante 5 intentos fallidos en 1 minuto desde la misma IP, el sistema bloquea la cuenta y registra el evento de seguridad.)
Solución 2. El 99,99% tolera aproximadamente 52,6 minutos de caída al año. Tácticas posibles: redundancia con varias instancias en distintas zonas y failover automático con balanceador y health checks. El atributo perjudicado es principalmente el coste (más infraestructura y replicación), y secundariamente la complejidad/mantenibilidad operativa.
Solución 3. Mejora la seguridad (cifrado y validación exhaustiva). Se resiente el rendimiento: el cifrado/descifrado y la triple validación añaden latencia y consumo de CPU en cada operación. También puede afectar a la mantenibilidad si la validación está duplicada en tres capas sin una única fuente de verdad.
Conclusión
Has aprendido a distinguir requisitos funcionales de no funcionales, a manejar un catálogo de atributos de calidad, a especificarlos de forma medible con escenarios de calidad de seis partes, a aplicar tácticas para lograrlos y a reconocer que casi siempre entran en conflicto entre sí. Precisamente ese choque permanente entre atributos —disponibilidad contra coste, rendimiento contra consistencia— es el corazón del trabajo arquitectónico. En la siguiente lección abordaremos de frente cómo se toman esas decisiones difíciles: las decisiones arquitectónicas y los compromisos (trade-offs), incluyendo métodos formales de evaluación como ATAM.
Curso de Arquitectura de Aplicaciones
Módulo 1: Fundamentos de la Arquitectura de Aplicaciones
- ¿Qué es la Arquitectura de Aplicaciones?
- El Rol del Arquitecto de Software
- Atributos de Calidad y Requisitos No Funcionales
- Decisiones Arquitectónicas y Compromisos (Trade-offs)
- Documentación de Arquitectura: Vistas y el Modelo C4
Módulo 2: Principios y Tácticas de Diseño
- Acoplamiento, Cohesión y Separación de Responsabilidades
- Principios SOLID Aplicados a la Arquitectura
- DRY, KISS, YAGNI y Otros Principios de Diseño
- Tácticas Arquitectónicas para los Atributos de Calidad
- Gestión de la Deuda Técnica
Módulo 3: Estilos y Patrones Arquitectónicos
- Arquitectura Monolítica
- Arquitectura en Capas (N-Tier)
- Arquitectura Cliente-Servidor
- Arquitectura Hexagonal (Puertos y Adaptadores)
- Arquitectura Limpia y Cebolla (Clean & Onion)
Módulo 4: Arquitecturas Distribuidas y Microservicios
- Introducción a los Sistemas Distribuidos
- Arquitectura de Microservicios
- Descomposición de Servicios y Bounded Contexts
- API Gateway, Service Discovery y Comunicación entre Servicios
- Patrones de Resiliencia: Circuit Breaker, Retry y Bulkhead
- El Teorema CAP y la Consistencia de Datos
Módulo 5: Arquitecturas Dirigidas por Eventos y Mensajería
- Fundamentos de la Arquitectura Orientada a Eventos
- Mensajería Asíncrona: Colas y Brokers
- Patrones de Eventos: Event Sourcing y CQRS
- Gestión de Transacciones Distribuidas: Patrón Saga
- Streaming de Datos en Tiempo Real
Módulo 6: Diseño Dirigido por el Dominio (DDD)
- Conceptos Fundamentales del DDD
- Diseño Estratégico: Bounded Contexts y Lenguaje Ubicuo
- Diseño Táctico: Entidades, Agregados y Repositorios
- Mapeo de Contextos (Context Mapping)
Módulo 7: Datos y Persistencia
- Estrategias de Persistencia: SQL vs NoSQL
- Patrones de Acceso a Datos: Repository, Unit of Work y DAO
- Base de Datos por Servicio y Gestión de Datos Distribuidos
- Caché y Estrategias de Invalidación
Módulo 8: Arquitectura en la Nube y Despliegue
- Fundamentos del Cloud Computing (IaaS, PaaS, SaaS)
- Contenedores y Orquestación con Docker y Kubernetes
- Arquitectura Serverless
- Patrones de Diseño Cloud-Native
- Infraestructura como Código (IaC)
Módulo 9: Calidad, Seguridad y Observabilidad
- Escalabilidad: Horizontal vs Vertical y Balanceo de Carga
- Alta Disponibilidad y Tolerancia a Fallos
- Seguridad por Diseño y Autenticación/Autorización
- Observabilidad: Logging, Métricas y Trazabilidad
- Rendimiento y Pruebas de Carga
