El Problema con los Requisitos Tradicionales
Los documentos de requisitos tradicionales sufren de fallas fundamentales:
- Ambigüedad: “El sistema debería ser amigable para el usuario” significa cosas diferentes para diferentes personas
- Obsolescencia: La documentación queda desactualizada en el momento que el código cambia
- Brechas de comunicación: Stakeholders de negocio y desarrolladores interpretan requisitos diferentemente
- Falta de validación: No hay forma de verificar si la implementación coincide con la intención
Specification by Example (SbE) aborda estos problemas usando ejemplos concretos como el artefacto primario para especificar, implementar y probar software.
¿Qué es Specification by Example?
Specification by Example es un enfoque colaborativo para definir requisitos y pruebas. En lugar de escribir especificaciones abstractas, los equipos crean documentación viva consistente en ejemplos ejecutables que ilustran el comportamiento del sistema.
Principios Centrales
1. Derivar alcance de metas: Comenzar con metas de negocio, no features 2. Especificar colaborativamente: Negocio, desarrollo y testing trabajan juntos 3. Ilustrar usando ejemplos: Escenarios concretos, no descripciones abstractas 4. Refinar la especificación: Iterar en ejemplos hasta que sean claros y testeables 5. Automatizar validación: Convertir ejemplos en pruebas ejecutables 6. Validar frecuentemente: Los ejemplos sirven como pruebas de regresión 7. Evolucionar la documentación: Actualizar ejemplos a medida que evoluciona el sistema
El Proceso SbE
1. Talleres de Ejemplos (Tres Amigos)
Representantes de tres perspectivas colaboran:
Negocio (Product Owner): ¿Qué valor estamos entregando? Desarrollo (Ingeniero): ¿Cómo lo construiremos? Testing (QA): ¿Qué podría salir mal?
Agenda del Taller:
- Presentar user story/feature
- Lluvia de ideas de escenarios de ejemplo
- Identificar rutas felices, casos límite, condiciones de error
- Refinar ejemplos hasta que todos estén de acuerdo
- Documentar en formato estructurado
2. Formato de Ejemplo
Los ejemplos típicamente siguen formato Given-When-Then (sintaxis Gherkin):
Escenario: Cliente premium recibe descuento de lealtad
Dado un cliente con membresía premium
Y han sido miembro por 3 años
Cuando compran un artículo por valor de $100
Entonces reciben un descuento del 15%
Y el total es $85
3. Automatización
Los ejemplos se automatizan usando herramientas como:
- Cucumber: Framework BDD para especificaciones Gherkin
- FitNesse: Framework de acceptance testing basado en wiki
- Concordion: Convierte especificaciones en lenguaje plano en pruebas ejecutables
- SpecFlow: Implementación .NET de Cucumber
4. Validación
Los ejemplos automatizados corren continuamente:
- Durante desarrollo (feedback rápido)
- En pipeline CI/CD (seguridad de regresión)
- Como documentación viva (siempre actualizada)
Ejemplo Concreto: Descuentos E-Commerce
Documento de Requisitos Tradicional
El sistema aplicará descuentos basados en el tier de lealtad del cliente.
Los clientes premium reciben descuentos más altos que clientes estándar.
Los descuentos varían según duración de membresía y monto de compra.
Problemas:
- ¿Cuáles son exactamente los porcentajes de descuento?
- ¿Qué define a un cliente “premium”?
- ¿Cómo afecta la duración de membresía a los descuentos?
- ¿Qué sucede en condiciones límite?
Versión Specification by Example
Feature: Descuentos Basados en Lealtad
Como dueño de negocio
Quiero recompensar clientes leales con descuentos
Para que continúen comprando con nosotros
Background:
Dado los siguientes tiers de descuento:
| Tipo de Membresía | Años | Descuento |
| Estándar | 0-1 | 0% |
| Estándar | 2-4 | 5% |
| Estándar | 5+ | 10% |
| Premium | 0-1 | 10% |
| Premium | 2-4 | 15% |
| Premium | 5+ | 20% |
Escenario: Cliente estándar nuevo no recibe descuento
Dado un cliente estándar que se unió hace 6 meses
Cuando compra artículos por un total de $100
Entonces el descuento aplicado es $0
Y el precio final es $100
Escenario: Cliente premium de largo plazo recibe descuento máximo
Dado un cliente premium que se unió hace 6 años
Cuando compra artículos por un total de $100
Entonces el descuento aplicado es $20
Y el precio final es $80
Escenario: Cliente mejoró a premium a mitad de tenure
Dado un cliente que fue estándar por 3 años
Y luego mejoró a premium hace 2 años
Cuando compra artículos por un total de $100
Entonces su tenure total es 5 años
Y recibe el descuento premium 5+ años del 20%
Y el precio final es $80
Escenario: Descuento no excede monto de compra
Dado un cliente premium con 6 años de membresía
Cuando compra artículos por un total de $10
Entonces el descuento aplicado es $2
Y el precio final es $8
Pero el descuento nunca excede el total de compra
Beneficios:
- No ambiguo: Porcentajes exactos y condiciones especificadas
- Comprehensivo: Casos límite (cambios de membresía, valores límite) cubiertos
- Testeable: Puede ser automatizado inmediatamente
- Validado: Ejemplos verificados por los tres amigos
FitNesse: Especificaciones Basadas en Wiki
FitNesse convierte páginas wiki en pruebas ejecutables, haciendo especificaciones accesibles a stakeholders no técnicos.
Ejemplo FitNesse: Carrito de Compras
Página Wiki (Legible por Stakeholders de Negocio):
!3 Cálculo del Carrito de Compras
Dados estos artículos en un carrito:
|script |
|start|shopping cart |
|add item|Widget |price|10.00 |
|add item|Gadget |price|25.00 |
|add item|Doohickey |price|15.00 |
|check |subtotal |50.00 |
|apply tax|8% |
|check |tax amount | 4.00 |
|check |total |54.00 |
¿Qué pasa si aplicamos un cupón?
|script |
|start |shopping cart |
|add item|Widget |price|10.00 |
|add item|Gadget |price|25.00 |
|apply coupon|SAVE10 |
|check |subtotal |50.00 |
|check |discount | 5.00 |
|check |subtotal after discount|45.00|
|apply tax|8% |
|check |total |48.60 |
Implementación Java (Fixture):
public class ShoppingCart {
private BigDecimal subtotal = BigDecimal.ZERO;
private BigDecimal taxRate = BigDecimal.ZERO;
private BigDecimal discount = BigDecimal.ZERO;
public void start() {
subtotal = BigDecimal.ZERO;
discount = BigDecimal.ZERO;
}
public void addItem(String name, BigDecimal price) {
subtotal = subtotal.add(price);
}
public BigDecimal subtotal() {
return subtotal;
}
public void applyTaxPercent(BigDecimal percent) {
taxRate = percent.divide(new BigDecimal("100"));
}
public BigDecimal taxAmount() {
return subtotalAfterDiscount().multiply(taxRate)
.setScale(2, RoundingMode.HALF_UP);
}
public void applyCoupon(String code) {
if ("SAVE10".equals(code)) {
discount = subtotal.multiply(new BigDecimal("0.10"));
}
}
public BigDecimal discountAmount() {
return discount;
}
public BigDecimal subtotalAfterDiscount() {
return subtotal.subtract(discount);
}
public BigDecimal total() {
return subtotalAfterDiscount().add(taxAmount());
}
}
Ejecución:
- Stakeholders de negocio escriben ejemplos en wiki
- Desarrolladores implementan fixtures
- FitNesse ejecuta ejemplos contra código
- Verde = especificación coincide con implementación
- Rojo = desajuste entre especificación y código
Beneficios de Documentación Viva
La documentación tradicional queda desactualizada. La documentación viva evoluciona con el codebase:
Docs Tradicionales:
Última actualización: Marzo 2024
Estado: Desconocido si aún preciso
Pruebas: Separadas de la documentación
Documentación Viva:
Última ejecución: Hace 2 minutos (CI build #4523)
Estado: Todos los 127 ejemplos pasando
Pruebas: La documentación SON las pruebas
Documentación como Red de Seguridad
Cuando los desarrolladores cambian código:
Sin Docs Vivas:
- Cambiar código
- Esperar que las pruebas capturen problemas
- Verificar docs manualmente
- Quizás actualizar docs (probablemente no)
- Desplegar y rezar
Con Docs Vivas:
- Cambiar código
- Los ejemplos automáticamente fallan si el comportamiento cambió
- Actualizar ejemplos para coincidir con nuevo comportamiento
- Documentación automáticamente actual
- Desplegar con confianza
Specification by Example vs. BDD
SbE y Behavior-Driven Development (BDD) están estrechamente relacionados:
BDD es una metodología de desarrollo de software que enfatiza colaboración y usa ejemplos. Es el “cómo” de construir software.
SbE es una técnica para capturar requisitos usando ejemplos. Es el “qué” estamos construyendo.
Relación:
- BDD usa SbE como su práctica central
- Puedes practicar SbE sin adopción completa de BDD
- BDD agrega prácticas adicionales (lenguaje ubicuo, desarrollo de afuera hacia adentro)
Ejemplo:
Feature: Reseteo de Contraseña # SbE: Qué estamos construyendo
Escenario: Usuario solicita reseteo de contraseña # SbE: Especificación de ejemplo
Dado un usuario con email "alice@example.com"
Cuando solicita un reseteo de contraseña
Entonces recibe un email de reseteo
Y el email contiene un enlace de reseteo válido
La sintaxis Gherkin sirve tanto como documentación SbE como automatización de pruebas BDD.
Implementación del Mundo Real: Feature de Transferencia Bancaria
Enfoque Tradicional
Doc de Requisitos:
El sistema permitirá a los usuarios transferir dinero entre cuentas.
Las transferencias deben validar fondos suficientes.
Se aplican límites diarios de transferencia.
Casos de Prueba Separados:
TC-001: Probar transferencia exitosa
TC-002: Probar fondos insuficientes
TC-003: Probar límite diario excedido
Resultado: Desconexión entre requisitos, pruebas e implementación.
Enfoque Specification by Example
Taller Colaborativo de Ejemplos:
Product Owner: “Queremos permitir transferencias de fondos hasta $10,000 por día.” Desarrollador: “¿Qué sucede si alguien intenta transferir $9,000 dos veces en un día?” Tester: “¿Qué pasa con transferencias entre diferentes monedas?” PO: “La segunda transferencia debería fallar. Por ahora, solo USD.” Desarrollador: “¿Las transferencias pendientes cuentan para el límite?” Tester: “¿Qué pasa si alguien transfiere exactamente $10,000.00 versus $10,000.01?”
Especificación Resultante:
Feature: Transferencias de Cuenta con Límites Diarios
Background:
Dado que el límite diario de transferencia es $10,000 USD
Y los límites se resetean a medianoche hora del Pacífico
Escenario: Transferencia exitosa dentro del límite
Dado que Alice tiene $5,000 en su cuenta corriente
Y no ha hecho transferencias hoy
Cuando transfiere $1,000 a la cuenta de Bob
Entonces la transferencia tiene éxito
Y el balance de Alice es $4,000
Y su límite diario restante es $9,000
Escenario: Transferencia rechazada por fondos insuficientes
Dado que Alice tiene $500 en su cuenta corriente
Cuando intenta transferir $1,000 a Bob
Entonces la transferencia falla
Y el error es "Fondos insuficientes"
Y el balance de Alice permanece en $500
Escenario: Múltiples transferencias acercándose al límite diario
Dado que Alice tiene $20,000 en su cuenta
Y no ha hecho transferencias hoy
Cuando transfiere $6,000 a Bob
Y transfiere $3,000 a Carol
Entonces ambas transferencias tienen éxito
Y su límite diario restante es $1,000
Escenario: Transferencia rechazada al exceder límite diario
Dado que Alice tiene $20,000 en su cuenta
Y ya ha transferido $9,500 hoy
Cuando intenta transferir $1,000 a Bob
Entonces la transferencia falla
Y el error es "Límite diario de transferencia excedido"
Y su límite diario restante es $500
Escenario: Prueba de límite en valor exacto
Dado que Alice tiene $15,000 en su cuenta
Y ya ha transferido $9,999.99 hoy
Cuando transfiere $0.01 a Bob
Entonces la transferencia tiene éxito
Y su límite diario restante es $0.00
Escenario: Transferencias pendientes cuentan para el límite
Dado que Alice tiene $15,000 en su cuenta
Y tiene una transferencia pendiente de $8,000
Cuando intenta transferir $3,000 a Bob
Entonces la transferencia falla
Y el error es "Límite diario de transferencia excedido (incluyendo pendientes)"
Resultados:
- Claridad: Todos saben exactamente cómo funcionan los límites
- Casos límite: Valores límite (ej., $9,999.99 + $0.01) identificados
- Validación: Lógica de negocio codificada en pruebas ejecutables
- Documentación: Siempre refleja comportamiento actual del sistema
Errores Comunes y Cómo Evitarlos
1. Escribir Detalles de Implementación en Ejemplos
Malo:
Dado que la tabla de base de datos "users" contiene una fila con id=123
Y la columna "premium_member" es true
Y la "membership_date" es "2019-01-01"
Bueno:
Dado un cliente premium que se unió el 1 de enero de 2019
Solución: Usar lenguaje de negocio, ocultar detalles de implementación.
2. Demasiados Ejemplos
Problema: 50 escenarios para un feature, mayormente redundantes.
Solución:
- Enfocarse en ejemplos clave ilustrando comportamientos diferentes
- Usar tablas de datos para testing combinatorial
- Extraer patrones comunes a sección Background
3. Ejemplos Sin Assertions
Malo:
Cuando el usuario hace clic en el botón submit
Entonces el formulario es enviado
Bueno:
Cuando el usuario hace clic en el botón submit
Entonces ve un mensaje de confirmación "Gracias por su envío"
Y recibe un email de confirmación
Y el envío aparece en el panel de admin
Solución: Incluir resultados observables, no solo acciones.
4. Solo Stakeholders Técnicos
Problema: Desarrolladores escriben todos los ejemplos en aislamiento.
Solución: Siempre incluir tres amigos (negocio, dev, QA) en talleres.
5. Tratar Ejemplos Solo Como Pruebas
Problema: Ejemplos escritos después de que el código está hecho, solo para testing.
Solución: Los ejemplos impulsan el desarrollo—escribirlos ANTES de codificar (como TDD/BDD).
Comparación de Herramientas
Herramienta | Lenguaje | Formato | Curva de Aprendizaje | Mejor Para |
---|---|---|---|---|
Cucumber | Muchos | Gherkin | Media | Equipos familiarizados con BDD |
FitNesse | Java, .NET | Tablas wiki | Baja | Stakeholders no técnicos |
Concordion | Java, .NET | HTML/Markdown | Media | Equipos enfocados en documentación |
SpecFlow | .NET/C# | Gherkin | Media | Tiendas .NET haciendo BDD |
Gauge | Muchos | Markdown | Baja | Equipos queriendo especificaciones legibles |
Robot Framework | Python | Keyword-driven | Media | Equipos de automatización de pruebas |
Comenzando con Specification by Example
Semana 1: Feature Piloto
- Elegir un feature pequeño
- Ejecutar taller de tres amigos
- Escribir 3-5 ejemplos clave
- Automatizar con herramienta elegida
- Reflexionar sobre qué funcionó
Semana 2-4: Expandir
- Agregar SbE a nuevos features
- Refinar proceso de taller
- Construir biblioteca de fixtures
- Entrenar miembros del equipo
Mes 2-3: Práctica Madura
- Retrospectiva de features existentes con ejemplos
- Integrar en CI/CD
- Medir cobertura de documentación
- Celebrar éxito de docs vivas
Conclusión: Ejemplos como la Fuente de Verdad
Specification by Example transforma requisitos de documentos estáticos en artefactos vivos y validados. Al hacer que los ejemplos sean:
- Concretos: Sin ambigüedad sobre comportamiento esperado
- Colaborativos: Negocio, dev y QA se alinean temprano
- Ejecutables: Los ejemplos verifican implementación
- Vivos: La documentación evoluciona con el código
El resultado es software que demostrablemente hace lo que stakeholders esperan, documentado en un formato que todos entienden, validado continuamente y siempre actualizado.
Los requisitos tradicionales preguntan “¿Lo construimos correctamente?” Specification by Example asegura que construimos lo correcto, de la manera correcta, con prueba de que funciona.
Comienza pequeño, colabora activamente y deja que los ejemplos impulsen tu desarrollo. La claridad y confianza que traen transformarán cómo tu equipo construye software.