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:

  1. Cambiar código
  2. Esperar que las pruebas capturen problemas
  3. Verificar docs manualmente
  4. Quizás actualizar docs (probablemente no)
  5. Desplegar y rezar

Con Docs Vivas:

  1. Cambiar código
  2. Los ejemplos automáticamente fallan si el comportamiento cambió
  3. Actualizar ejemplos para coincidir con nuevo comportamiento
  4. Documentación automáticamente actual
  5. 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

HerramientaLenguajeFormatoCurva de AprendizajeMejor Para
CucumberMuchosGherkinMediaEquipos familiarizados con BDD
FitNesseJava, .NETTablas wikiBajaStakeholders no técnicos
ConcordionJava, .NETHTML/MarkdownMediaEquipos enfocados en documentación
SpecFlow.NET/C#GherkinMediaTiendas .NET haciendo BDD
GaugeMuchosMarkdownBajaEquipos queriendo especificaciones legibles
Robot FrameworkPythonKeyword-drivenMediaEquipos 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.