Documentando flujos de usuario en tu arquitectura de software - Archyl Blog

Nuestros diagramas de arquitectura se veían perfectos. Luego llegó un reporte de bug, y nos dimos cuenta de que nadie realmente entendía cómo un usuario se movía a través del sistema. Así es como lo arreglamos.

Documentando flujos de usuario en tu arquitectura de software

El reporte de bug parecía simple: "El checkout falla intermitentemente."

Teníamos hermosos diagramas de arquitectura. Diagramas C4 mostrando cada servicio, cada base de datos, cada integración. Pero cuando tratamos de trazar el viaje de un usuario desde "agregar al carrito" hasta "orden confirmada", nadie podía ponerse de acuerdo en la secuencia exacta. ¿Qué servicios estaban involucrados? ¿En qué orden? ¿Dónde ocurría la verificación de inventario — antes o después del pago?

Tres ingenieros tenían tres modelos mentales diferentes. Nuestros diagramas de arquitectura estáticos mostraban la estructura, pero no el comportamiento. Podíamos ver las cajas y las flechas, pero no podíamos ver cómo un usuario realmente se movía a través del sistema.

Ahí fue cuando me di cuenta de que necesitábamos flujos de usuario.

Qué son realmente los flujos de usuario

Un flujo de usuario documenta el viaje que un usuario toma a través de tu sistema para lograr un objetivo. No la estructura estática (para eso están los diagramas C4), sino la secuencia dinámica:

  1. El usuario hace X
  2. El sistema responde con Y
  3. El usuario elige Z
  4. Y así sucesivamente...

Suena obvio, pero es sorprendentemente raro tener esto bien documentado. La mayoría de los equipos tienen diagramas de arquitectura (estructura del sistema) y documentación de API (detalles de endpoints), pero nada en medio que muestre cómo estas piezas trabajan juntas desde la perspectiva del usuario.

La brecha entre estructura y comportamiento

Aquí hay una versión simplificada de nuestro diagrama C4 de containers en ese momento:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Web App   │────▶│     API     │────▶│  Database   │
└─────────────┘     └──────┬──────┘     └─────────────┘
                           │
                    ┌──────▼──────┐
                    │   Payment   │
                    │   Service   │
                    └──────┬──────┘
                           │
                    ┌──────▼──────┐
                    │   Stripe    │
                    └─────────────┘

Esto te dice que los componentes existen y cómo se conectan. Pero no responde: Cuando un usuario hace checkout, ¿qué pasa primero? ¿La API valida inventario antes de llamar al pago? ¿Qué pasa si el pago tiene éxito pero el inventario ya no está disponible?

Estas preguntas requieren entender el flujo, no solo la estructura.

Anatomía de un flujo de usuario útil

Con el tiempo, desarrollé un template que funciona bien para documentar flujos:

1. Declaración del objetivo

Empieza con lo que el usuario está tratando de lograr:

Objetivo: Completar una compra de artículos en el carrito

Esto mantiene el flujo enfocado. Si te encuentras documentando múltiples objetivos, sepáralos en múltiples flujos.

2. Precondiciones

¿Qué debe ser verdad antes de que este flujo comience?

  • El usuario está conectado
  • El carrito contiene al menos un artículo
  • Los artículos en el carrito están en stock (al momento de cargar la página)

Esto previene confusión sobre el estado inicial y clarifica suposiciones.

3. El camino feliz

Documenta primero el camino de éxito esperado:

1. El usuario hace clic en el botón "Checkout"
   → Web App muestra formulario de dirección de envío

2. El usuario ingresa dirección de envío, hace clic "Continuar"
   → API valida formato de dirección
   → API calcula opciones de envío
   → Web App muestra selección de método de envío

3. El usuario selecciona método de envío, hace clic "Continuar"
   → API valida método de envío
   → Web App muestra formulario de pago

4. El usuario ingresa detalles de pago, hace clic "Realizar pedido"
   → API crea orden pendiente en base de datos
   → API llama a Payment Service con detalles de orden
   → Payment Service llama a Stripe para cobrar tarjeta
   → Payment Service retorna éxito a API
   → API marca orden como confirmada
   → API dispara email de confirmación
   → Web App muestra página de confirmación de orden

5. El usuario ve confirmación con número de orden

Nota algunas cosas:

  • Cada paso incluye lo que el usuario hace Y cómo responde el sistema
  • Especificamos qué componentes manejan cada acción
  • El nivel de detalle es suficiente para entender el flujo sin leer código

4. Caminos de error y casos límite

El camino feliz es solo el comienzo. El verdadero valor viene de documentar qué pasa cuando las cosas salen mal:

Pago rechazado:

En el paso 4, si Stripe retorna payment_declined:
→ Payment Service retorna error a API
→ API NO marca orden como confirmada
→ API elimina orden pendiente
→ Web App muestra mensaje "Pago rechazado"
→ El usuario puede reintentar con otro método de pago

Inventario cambió:

En el paso 4, antes de crear orden pendiente:
→ API re-verifica disponibilidad de inventario
→ Si artículo ahora no disponible:
  → API retorna inventory_error
  → Web App muestra "Artículo ya no disponible" con enlace al carrito
  → El usuario debe remover artículo y reiniciar checkout

Timeout de red:

En el paso 4, si Payment Service no responde en 30 segundos:
→ API NO reintenta (para prevenir cargos dobles)
→ API retorna timeout_error
→ Web App muestra "Por favor revisa tu email para confirmar estado del pedido"
→ Job en background verifica estado de pago después de 5 minutos
→ Si pago exitoso: marcar orden confirmada, enviar email
→ Si pago falló: limpiar orden pendiente

Estos caminos de error son donde se esconden los bugs. También son donde la mayoría de la documentación se detiene, por eso los bugs se esconden ahí.

5. Notas técnicas

Agrega cualquier contexto técnico que sea relevante:

Notas técnicas:
- La verificación de inventario y el pago NO son atómicos. Race condition
  posible pero aceptable dada baja probabilidad y proceso de resolución manual.
- El webhook de Stripe proporciona confirmación de respaldo si se pierde
  respuesta de API.
- Órdenes pendientes de más de 1 hora son limpiadas por job programado.

Conectando flujos a la arquitectura

Aquí es donde se vuelve poderoso: vincular flujos de usuario a tus diagramas C4.

En Archyl, podemos anotar qué componentes están involucrados en cada paso de un flujo. Esto crea trazabilidad bidireccional:

  • ¿Mirando un flujo? Ve qué componentes toca.
  • ¿Mirando un componente? Ve qué flujos pasan por él.

Cuando llegó ese bug de checkout, podríamos haber:

  1. Abierto el flujo de checkout
  2. Visto exactamente qué servicios estaban involucrados
  3. Trazado hasta el paso específico que estaba fallando
  4. Entendido el manejo de errores en ese punto

En cambio, pasamos dos días redescubriendo cómo funcionaba nuestro propio sistema.

Diferentes tipos de flujos

No todos los flujos son iguales. Los categorizamos:

Flujos de usuario

Secuencias iniciadas por el usuario desde la UI:

  • Flujo de checkout
  • Flujo de registro
  • Flujo de restablecimiento de contraseña
  • Flujo de actualización de perfil

Estos empiezan con una acción del usuario y terminan con un resultado visible.

Flujos de sistema

Secuencias iniciadas por máquinas:

  • Job de reconciliación nocturno
  • Procesamiento de webhooks
  • Cascadas event-driven
  • Notificaciones programadas

Estos son igualmente importantes pero frecuentemente menos documentados porque no hay UI que ver.

Flujos de integración

Secuencias cross-sistema:

  • Importación de órdenes de terceros
  • Lotes de liquidación de pagos
  • Sincronización de datos con socios

Estos típicamente involucran sistemas fuera de tu control y tienen más modos de falla potenciales.

Cómo documentamos flujos ahora

Después de ese fiasco de debugging de checkout, establecimos un proceso:

Cada funcionalidad mayor tiene un flujo

Cuando construimos una nueva funcionalidad, documentamos el flujo antes de escribir código. Esto sirve como documento de diseño y persiste como documentación.

El formato es simple markdown:

# Funcionalidad: Reseñas de usuario

## Objetivo

El usuario envía una reseña para un producto comprado

## Precondiciones

- El usuario está conectado
- El usuario ha comprado el producto
- El producto permite reseñas

## Flujo

1. El usuario hace clic "Escribir reseña" en página de producto
   ...

## Manejo de errores

...

## Componentes involucrados

- Web App
- API Gateway
- Review Service
- Product Service
- Notification Service

## ADRs relacionados

- ADR-0023: Estrategia de moderación de reseñas

Revisión de flujos en PRs

Si un PR cambia un flujo documentado, requerimos que la documentación del flujo sea actualizada. Los templates de PR incluyen: "¿Este cambio modifica algún flujo de usuario? Si es así, actualiza los docs de flujos."

Auditoría trimestral de flujos

Cada trimestre, recorremos flujos críticos como equipo:

  1. Abrir la documentación del flujo
  2. Trazar a través del código/sistema real
  3. Identificar discrepancias
  4. Actualizar documentación o arreglar bugs

Esto suena como overhead, pero ha atrapado problemas reales. Dos veces descubrimos que cambios de código habían roto comportamiento documentado sin que nadie se diera cuenta.

Errores comunes

Error 1: Demasiado detalle

Un documento de flujo no debería leerse como código. Si estás documentando queries de base de datos individuales, estás en el nivel equivocado. Enfócate en pasos visibles al usuario e interacciones a nivel de servicio.

Error 2: Documentar solo caminos felices

El camino feliz es fácil. Los caminos de error son donde viven los bugs. Forzate a responder: "¿Qué pasa si este paso falla?"

Error 3: No actualizar después de cambios

Un flujo documentado que no coincide con la realidad es peor que no tener documentación. Crea falsa confianza y lleva a suposiciones erróneas durante el debugging.

Error 4: Tratar flujos como estáticos

Los flujos de usuario evolucionan. Nuevas funcionalidades agregan pasos. Optimizaciones remueven pasos. Tests A/B cambian comportamiento. Trata los flujos como documentos vivos, no artefactos de una sola vez.

Herramientas y formatos

No necesitas herramientas especiales para documentación de flujos. Markdown en tu repositorio funciona bien. Lo que importa es consistencia y descubribilidad.

Dicho eso, los diagramas visuales de flujo pueden ayudar para secuencias complejas. Herramientas como Mermaid te permiten escribir diagramas como código:

sequenceDiagram
    participant U as Usuario
    participant W as Web App
    participant A as API
    participant P as Payment Service
    participant S as Stripe

    U->>W: Clic "Realizar pedido"
    W->>A: POST /orders
    A->>A: Crear orden pendiente
    A->>P: Procesar pago
    P->>S: Cobrar tarjeta
    S-->>P: Éxito
    P-->>A: Pago confirmado
    A->>A: Marcar orden confirmada
    A-->>W: Detalles de orden
    W-->>U: Página de confirmación

La clave es el control de versiones. Los diagramas de flujo en Figma o Lucidchart tienden a alejarse de la realidad porque están desconectados del proceso de desarrollo.

Conclusión

Los diagramas de arquitectura estáticos te dicen de qué está hecho tu sistema. Los flujos de usuario te dicen cómo se comporta. Necesitas ambos.

La próxima vez que estés debuggeando un problema complejo a través de múltiples servicios, pregúntate: "¿Tenemos un flujo documentado para esto?" Si la respuesta es no, pasarás horas reconstruyendo cómo las piezas encajan — horas que podrían haberse ahorrado con un simple documento.

Empieza con tu flujo más crítico. Para la mayoría de los sistemas, eso es probablemente autenticación o el camino de conversión principal (checkout, registro, acción core). Documenta el camino feliz, luego forzate a documentar al menos tres casos de error.

Tu yo futuro — debuggeando frenéticamente a las 2 AM — te lo agradecerá.


Más sobre documentación de arquitectura: Introducción al modelo C4 | Architecture Decision Records | Por qué la documentación importa