Documentare i flussi utente nell'architettura software

La segnalazione di bug sembrava semplice: "Il checkout fallisce a intermittenza."

Avevamo bellissimi diagrammi di architettura. Diagrammi C4 che mostravano ogni servizio, ogni database, ogni integrazione. Ma quando abbiamo provato a ricostruire il percorso di un utente da "aggiungi al carrello" a "ordine confermato", nessuno riusciva a mettersi d'accordo sulla sequenza esatta. Quali servizi erano coinvolti? In quale ordine? Dove avveniva il controllo delle scorte: prima o dopo il pagamento?

Tre ingegneri avevano tre modelli mentali diversi. I nostri diagrammi di architettura statici mostravano la struttura, ma non il comportamento. Vedevamo i box e le frecce, ma non come un utente si muoveva davvero nel sistema.

È lì che ho capito che ci servivano i flussi utente.

Cosa sono davvero i flussi utente

Un flusso utente documenta il percorso che un utente compie nel tuo sistema per raggiungere un obiettivo. Non la struttura statica (per quella ci sono i diagrammi C4), ma la sequenza dinamica, che il C4 stesso disegna come diagramma dinamico:

  1. L'utente fa X
  2. Il sistema risponde con Y
  3. L'utente sceglie Z
  4. E così via...

Sembra ovvio, ma è sorprendentemente raro trovarli documentati bene. La maggior parte dei team ha diagrammi di architettura (la struttura del sistema) e documentazione delle API (i dettagli degli endpoint), ma niente nel mezzo che mostri come questi pezzi lavorano insieme dal punto di vista dell'utente. Ora puoi descrivere un percorso e ottenere una bozza del flusso.

Il divario tra struttura e comportamento

Ecco una versione semplificata del nostro diagramma dei container C4 di allora:

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

Ti dice che i componenti esistono e come si collegano. Ma non risponde a: quando un utente fa il checkout, cosa succede per primo? L'API verifica le scorte prima di chiamare il pagamento? Cosa succede se il pagamento va a buon fine ma nel frattempo l'articolo non è più disponibile?

Queste domande richiedono di capire il flusso, non solo la struttura.

Anatomia di un flusso utente utile

Col tempo ho messo a punto un template che funziona bene per documentare i flussi:

1. Dichiarazione dell'obiettivo

Parti da ciò che l'utente sta cercando di fare:

Obiettivo: completare l'acquisto degli articoli nel carrello

Questo tiene il flusso a fuoco. Se ti ritrovi a documentare più obiettivi, dividilo in più flussi.

2. Precondizioni

Cosa deve essere vero prima che questo flusso inizi?

  • L'utente ha effettuato l'accesso
  • Il carrello contiene almeno un articolo
  • Gli articoli nel carrello sono disponibili (al caricamento della pagina)

Questo evita confusione sullo stato di partenza e chiarisce le ipotesi.

3. Il percorso felice

Documenta prima il percorso di successo previsto:

1. L'utente clicca sul pulsante "Checkout"
   → La Web App mostra il modulo dell'indirizzo di spedizione

2. L'utente inserisce l'indirizzo di spedizione e clicca "Continua"
   → L'API valida il formato dell'indirizzo
   → L'API calcola le opzioni di spedizione
   → La Web App mostra la scelta del metodo di spedizione

3. L'utente sceglie il metodo di spedizione e clicca "Continua"
   → L'API valida il metodo di spedizione
   → La Web App mostra il modulo di pagamento

4. L'utente inserisce i dati di pagamento e clicca "Effettua ordine"
   → L'API crea un ordine in sospeso nel database
   → L'API chiama il Payment Service con i dettagli dell'ordine
   → Il Payment Service chiama Stripe per addebitare la carta
   → Il Payment Service restituisce l'esito positivo all'API
   → L'API segna l'ordine come confermato
   → L'API avvia l'email di conferma
   → La Web App mostra la pagina di conferma dell'ordine

5. L'utente vede la conferma con il numero d'ordine

Nota alcune cose:

  • Ogni passo include cosa fa l'utente E come risponde il sistema
  • Specifichiamo quali componenti gestiscono ogni azione
  • Il livello di dettaglio basta a capire il flusso senza leggere il codice

4. Percorsi di errore e casi limite

Il percorso felice è solo l'inizio. Il vero valore arriva dal documentare cosa succede quando le cose vanno storte:

Pagamento rifiutato:

Al passo 4, se Stripe restituisce payment_declined:
→ Il Payment Service restituisce un errore all'API
→ L'API NON segna l'ordine come confermato
→ L'API elimina l'ordine in sospeso
→ La Web App mostra il messaggio "Pagamento rifiutato"
→ L'utente può riprovare con un altro metodo di pagamento

Scorte cambiate:

Al passo 4, prima di creare l'ordine in sospeso:
→ L'API ricontrolla la disponibilità delle scorte
→ Se l'articolo non è più disponibile:
  → L'API restituisce inventory_error
  → La Web App mostra "Articolo non più disponibile" con un link al carrello
  → L'utente deve rimuovere l'articolo e ricominciare il checkout

Timeout di rete:

Al passo 4, se il Payment Service non risponde entro 30 secondi:
→ L'API NON riprova (per evitare doppi addebiti)
→ L'API restituisce timeout_error
→ La Web App mostra "Controlla la tua email per verificare lo stato dell'ordine"
→ Un job in background controlla lo stato del pagamento dopo 5 minuti
→ Se il pagamento è andato a buon fine: segna l'ordine come confermato, invia l'email
→ Se il pagamento è fallito: elimina l'ordine in sospeso

È in questi percorsi di errore che si nascondono i bug. Ed è anche lì che si ferma la maggior parte della documentazione, motivo per cui i bug si nascondono proprio lì.

5. Note tecniche

Aggiungi il contesto tecnico rilevante:

Note tecniche:
- Controllo delle scorte e pagamento NON sono atomici. È possibile una race
  condition, accettabile vista la bassa probabilità e il processo di risoluzione manuale.
- Il webhook di Stripe fornisce una conferma di riserva se la risposta dell'API va persa.
- Gli ordini in sospeso più vecchi di 1 ora vengono eliminati da un job pianificato.

Collegare i flussi all'architettura

Ecco dove diventa potente: collegare i flussi utente ai tuoi diagrammi C4.

In Archyl possiamo annotare quali componenti sono coinvolti in ogni passo di un flusso. Questo crea una tracciabilità bidirezionale:

  • Guardi un flusso? Vedi quali componenti tocca.
  • Guardi un componente? Vedi quali flussi lo attraversano.

Quando è arrivato quel bug del checkout, avremmo potuto:

  1. Aprire il flusso di checkout
  2. Vedere esattamente quali servizi erano coinvolti
  3. Risalire al passo specifico che falliva
  4. Capire la gestione degli errori in quel punto

Invece abbiamo passato due giorni a riscoprire come funzionava il nostro stesso sistema.

Tipi diversi di flussi

Non tutti i flussi sono uguali. Noi li classifichiamo così:

Flussi utente

Sequenze avviate dall'utente dall'interfaccia:

  • Flusso di checkout
  • Flusso di registrazione
  • Flusso di reset della password
  • Flusso di aggiornamento del profilo

Iniziano con un'azione dell'utente e finiscono con un risultato visibile.

Flussi di sistema

Sequenze avviate dalla macchina:

  • Job di riconciliazione notturno
  • Elaborazione dei webhook
  • Cascate event-driven
  • Notifiche pianificate

Sono altrettanto importanti, ma spesso meno documentati perché non c'è un'interfaccia da guardare.

Flussi di integrazione

Sequenze tra sistemi:

  • Importazione di ordini da terze parti
  • Batch di regolamento dei pagamenti
  • Sincronizzazione dei dati con i partner

Di solito coinvolgono sistemi fuori dal tuo controllo e hanno più modi possibili di fallire.

Come documentiamo i flussi oggi

Dopo quel disastro di debug sul checkout, abbiamo definito un processo:

Ogni funzionalità importante ha il suo flusso

Quando costruiamo una nuova funzionalità, documentiamo il flusso prima di scrivere il codice. Serve come documento di design e resta come documentazione.

Il formato è semplice markdown:

# Funzionalità: recensioni degli utenti

## Obiettivo

L'utente invia una recensione per un prodotto acquistato

## Precondizioni

- L'utente ha effettuato l'accesso
- L'utente ha acquistato il prodotto
- Il prodotto accetta recensioni

## Flusso

1. L'utente clicca "Scrivi una recensione" nella pagina del prodotto
   ...

## Gestione degli errori

...

## Componenti coinvolti

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

## ADR correlati

- ADR-0023: strategia di moderazione delle recensioni

Revisione dei flussi nelle PR

Se una PR modifica un flusso documentato, richiediamo che la documentazione del flusso venga aggiornata. I template delle PR includono: "Questa modifica cambia qualche flusso utente? Se sì, aggiorna la documentazione dei flussi."

Audit trimestrale dei flussi

Ogni trimestre ripercorriamo insieme, come team, i flussi critici:

  1. Apriamo la documentazione del flusso
  2. La confrontiamo con il codice e il sistema reali
  3. Individuiamo le discrepanze
  4. Aggiorniamo la documentazione o correggiamo i bug

Sembra un costo aggiuntivo, ma ha fatto emergere problemi reali. Due volte abbiamo scoperto che delle modifiche al codice avevano rotto un comportamento documentato senza che nessuno se ne accorgesse.

Errori comuni

Errore 1: troppo dettaglio

Un documento di flusso non dovrebbe sembrare codice. Se stai documentando singole query al database, sei al livello sbagliato. Concentrati sui passi visibili all'utente e sulle interazioni a livello di servizio.

Errore 2: documentare solo i percorsi felici

Il percorso felice è facile. I bug vivono nei percorsi di errore. Costringiti a rispondere: "Cosa succede se questo passo fallisce?"

Errore 3: non aggiornare dopo le modifiche

Un flusso documentato che non corrisponde alla realtà è peggio di nessuna documentazione. Crea una falsa sicurezza e porta a ipotesi sbagliate durante il debug.

Errore 4: trattare i flussi come statici

I flussi utente evolvono. Le nuove funzionalità aggiungono passi. Le ottimizzazioni ne tolgono. Gli A/B test cambiano il comportamento. Tratta i flussi come documenti vivi, non come artefatti da produrre una volta sola.

Strumenti e formati

Non servono strumenti speciali per documentare i flussi. Il markdown nel tuo repository va benissimo. Ciò che conta è la coerenza e la facilità di trovarli.

Detto questo, i diagrammi di flusso visivi possono aiutare con le sequenze complesse. Strumenti come Mermaid ti permettono di scrivere diagrammi come codice:

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

    U->>W: Click "Place Order"
    W->>A: POST /orders
    A->>A: Create pending order
    A->>P: Process payment
    P->>S: Charge card
    S-->>P: Success
    P-->>A: Payment confirmed
    A->>A: Mark order confirmed
    A-->>W: Order details
    W-->>U: Confirmation page

La chiave è il controllo di versione. I diagrammi di flusso in Figma o Lucidchart tendono a scostarsi dalla realtà perché sono scollegati dal processo di sviluppo.

Conclusione

I diagrammi di architettura statici ti dicono di cosa è fatto il tuo sistema. I flussi utente ti dicono come si comporta. Ti servono entrambi.

La prossima volta che fai debug di un problema complesso che attraversa più servizi, chiediti: "Abbiamo un flusso documentato per questo?" Se la risposta è no, passerai ore a ricostruire come si incastrano i pezzi, ore che un semplice documento ti avrebbe fatto risparmiare.

Parti dal tuo flusso più critico. Per la maggior parte dei sistemi è probabilmente l'autenticazione o il percorso di conversione principale (checkout, registrazione, azione centrale). Documenta il percorso felice, poi costringiti a documentare almeno tre casi di errore.

Il te stesso del futuro, alle prese con un debug frenetico alle 2 di notte, ti ringrazierà.


Altro sulla documentazione dell'architettura: Guida al modello C4 | Architecture Decision Record | Perché la documentazione è importante