Desde La Capa De Dominio
← Volver al blog

Testeabilidad vs observabilidad: no compiten, se complementan

La testeabilidad te da feedback antes de producción; la observabilidad te explica qué pasa cuando el sistema ya está vivo. Entender la diferencia cambia cómo diseñas software.

Testing Observability Arquitectura Diseño de Software Calidad Buenas Prácticas

Hay dos conceptos que mucha gente mezcla como si fueran sinónimos: testeabilidad y observabilidad.

Y no, no son lo mismo. Se relacionan, sí. Pero cumplen papeles distintos en la arquitectura de un sistema.

La testeabilidad reduce incertidumbre antes de producción. La observabilidad reduce incertidumbre durante producción.

Si confundes esas dos ideas, terminas diseñando sistemas que parecen sólidos… pero solo hasta que algo falla de verdad.


🧪 ¿Qué es la testeabilidad?


La testeabilidad es la facilidad con la que puedes provocar estados, controlar dependencias y verificar resultados en tu software.

O dicho más directo: qué tan fácil es demostrar, de forma automatizada, que una pieza del sistema se comporta como esperas.

Un sistema testeable no es el que “tiene muchos tests”. Es el que está diseñado para que testear sea natural.


📡 ¿Qué es la observabilidad?


La observabilidad es la capacidad de entender qué está pasando dentro de un sistema a partir de las señales que emite mientras corre en entornos reales.

No se trata solo de tener logs. Se trata de poder responder preguntas como estas sin rezar:

Para eso necesitas logs con contexto, métricas útiles, trazas y, sobre todo, señales pensadas desde el diseño.


❌ El error común: enfrentarlas


Aquí viene la confusión típica: pensar que si un sistema es muy observable entonces no hace falta que sea tan testeable. O al revés.

No. Es como tener tipado estático y logs en producción. El tipado previene clases enteras de bugs antes de que el código corra; los logs te explican qué hizo el sistema cuando los datos no eran los que esperabas. Nadie discute cuál elegir, porque atacan momentos distintos del ciclo de vida.

Testeabilidad

  • Actúa antes del despliegue
  • Reduce el coste de cambio
  • Ayuda a diseñar mejor
  • Valida comportamiento esperado

Observabilidad

  • Actúa con el sistema en marcha
  • Reduce el coste de diagnóstico
  • Ayuda a operar mejor
  • Explica comportamiento real

🧠 La diferencia, dibujada


flowchart TB
    A[Diseño del sistema]
    A --> B{¿Qué incertidumbre<br/>quieres reducir?}

    B -->|Antes de<br/>producción| T[Testeabilidad]
    B -->|Durante<br/>producción| O[Observabilidad]

    T --> T1[Dependencias explícitas]
    T1 --> T2[Entradas y salidas controlables]
    T2 --> T3[Tests rápidos y deterministas]
    T3 --> T4[Feedback barato antes de desplegar]

    O --> O1[Logs con contexto]
    O1 --> O2[Métricas]
    O2 --> O3[Tracing]
    O3 --> O4[Feedback real en ejecución]

    T4 --> C[Confianza para cambiar]
    O4 --> C
    C --> D[Menos tiempo persiguiendo errores]

    style A fill:#0f172a,stroke:#818cf8,color:#e0e7ff
    style B fill:#1e1b4b,stroke:#818cf8,color:#e0e7ff
    style T fill:#1e3a1e,stroke:#4ade80,color:#dcfce7
    style O fill:#082f49,stroke:#38bdf8,color:#e0f2fe
    style C fill:#3b0764,stroke:#a855f7,color:#f3e8ff
    style D fill:#0f172a,stroke:#818cf8,color:#e0e7ff

⚖️ Casos reales: qué pasa cuando te falta una


Alta testeabilidad + baja observabilidad

Tu pipeline está en verde, pero en producción no entiendes por qué falla un flujo. Cambias con seguridad, pero operas a ciegas.

Baja testeabilidad + alta observabilidad

Ves perfectamente el incendio en producción, pero cada fix es caro y arriesgado porque el sistema está acoplado y cuesta aislarlo.

Baja testeabilidad + baja observabilidad

Caos total: no previenes errores antes ni los entiendes después. Cada cambio se siente como apostar a ciegas.

Alta testeabilidad + alta observabilidad

Este es el punto sano: cambias con confianza y, si algo ocurre en producción, tienes señales para entenderlo rápido.


🛠️ Una decisión, dos beneficios


En lugar de listar buenas prácticas genéricas, mejor un caso concreto. Imaginemos un caso de uso del estilo de los que tengo en Code Finances: registrar un ingreso de un usuario.

La decisión de diseño es simple: el caso de uso recibe sus dependencias por constructor (puerto del repositorio + publicador de eventos) y, al completar la operación, emite un RevenueRegistered.

class RevenueRegistrar {
  constructor(
    private readonly repository: RevenueRepository,
    private readonly publisher: DomainEventsPublisher,
  ) {}

  async execute(request: RequestRevenueRegistrar): Promise<void> {
    const revenue = Revenue.create(input);

    await this.repository.save(revenue);

    await this.publisher.publish(revenue.pullDomainEvents());
  }
}

Esa misma decisión te paga en los dos frentes:

Ese es el patrón a perseguir: una sola decisión de diseño que mejora ambas cualidades a la vez. De ahí salen tres principios que conviene tener siempre en la cabeza:


💸 Los trade-offs reales


Ojo: ninguna de las dos es gratis.

Por eso la conversación madura no es “¿cuál elijo?”. La conversación madura es: ¿qué nivel de testeabilidad y observabilidad necesita este sistema según su criticidad y coste de fallo?


💬 Conclusión


La testeabilidad y la observabilidad no son rivales. Son dos mecanismos distintos para bajar incertidumbre en momentos diferentes de la vida del software.

Si tu sistema solo es testeable, sufrirás cuando llegue a producción. Si tu sistema solo es observable, sufrirás cada vez que necesites cambiarlo.

El punto serio de ingeniería está en construir software que pueda probarse bien y también explicarse bien cuando ya está corriendo.

Porque la calidad no aparece por magia. Se diseña.