Become a member!

Manuale Pratico di Linguaggio DOT (Graphviz) per sviluppatori e analisti

Per sviluppatori, analisti e software architect che vogliono produrre diagrammi professionali, chiari e belli da vedere

  • 🇬🇧 This article is also available in english.
  • 🇪🇸 Este artículo también está disponible en español.

Introduzione

Nel lavoro quotidiano di chi sviluppa software — che tu sia analista, sviluppatore backend, frontend, database expert o architect — arriva sempre il momento in cui un diagramma diventa fondamentale.

Serve quando devi:

  • spiegare un flusso complesso,
  • disegnare la pipeline CI/CD,
  • raccontare l’architettura a un nuovo collega,
  • analizzare dipendenze tra moduli,
  • documentare un database,
  • preparare una presentazione tecnica,
  • ragionare su un refactoring,
  • identificare colli di bottiglia.

Graphviz e il suo linguaggio DOT sono strumenti ideali: testuali (versionabili), veloci da scrivere, belli da renderizzare, flessibili.

Installazione Graphviz

Prima di iniziare, assicurati di avere Graphviz installato:

  • Windows: Scarica l’installer da graphviz.org/download o usa winget install graphviz
  • macOS: brew install graphviz
  • Linux: sudo apt install graphviz (Debian/Ubuntu) o sudo dnf install graphviz (Fedora/RHEL)

Verifica l’installazione con dot -V — dovresti vedere la versione installata.

Questo manuale vuole essere la guida definitiva per chi nel software vuole usare il linguaggio DOT al massimo. Troverai:

  • spiegazione approfondita degli attributi con tutte le opzioni rilevanti,
  • esempi completi, riutilizzabili e commentati,
  • best practices per grafici professionali,
  • suggerimenti sull’uso dei layout engine,
  • scenari concreti dal mondo dello sviluppo (design, refactoring, analisi, architettura).

Il linguaggio DOT: basi solide

DOT descrive grafi con una sintassi molto semplice:

digraph Nome {
    nodoA -> nodoB;
}

Oppure non diretto:

graph Nome {
    nodoA -- nodoB;
}

Concetti chiave:

  • nodi: entità (funzioni, oggetti, microservizi, tabelle DB)
  • archi: relazioni, chiamate, flussi
  • attributi: aspetto visuale o metadati

Quick Start: il tuo primo diagramma in 30 secondi

Testa subito online (senza installare nulla)

Tutti gli esempi di questo articolo sono direttamente testabili online usando Edotor.net:

  1. Vai su edotor.net

  2. Copia il codice DOT di qualsiasi esempio da questo articolo

  3. Incollalo nell’area di sinistra (sostituendo il codice esistente)

  4. Vedi il rendering immediato nell’area di destra

È il modo più veloce per sperimentare senza installare Graphviz. Quando sei pronto per la produzione, installa Graphviz localmente.

Primo esempio da provare

Copia questo codice e testalo su edotor.net:

digraph MyFirstGraph {
    node [shape=box, style=rounded, fillcolor=lightblue, style="rounded,filled"];
    edge [color=blue];

    Start -> Process -> End;
    Process -> Error [style=dashed, label="on failure"];
    Error -> Process [label="retry"];
}

Oppure usa la command line locale

Crea un file hello.dot con il codice sopra e genera l’immagine SVG:

dot -Tsvg hello.dot -o hello.svg

Apri hello.svg nel browser e vedrai il tuo primo flowchart! Da qui in poi, tutto si basa su variazioni e combinazioni di questi concetti.


Attributi fondamentali (con opzioni complete)

Gli attributi possono essere applicati globalmente a:

  • graph
  • node
  • edge
  • a singoli elementi

Esempio:

digraph demo {
    graph [rankdir=LR];
    node [shape=box];
    edge [color=grey];

    A -> B;
}

Di seguito l’elenco degli attributi più importanti con le loro opzioni più utili in ambito software.


Attributi dei nodi (node)

shape — forma del nodo

Opzioni utili:

  • box
  • ellipse
  • circle
  • diamond (decisioni nei flow)
  • record (class diagrams, strutture dati)
  • plaintext (contenuti completamente personalizzati con HTML-label)
  • note
  • folder (disponibile in alcune build)

Esempio:

node [shape=box];

Usi tipici:

  • box → moduli software
  • ellipse → stati
  • diamond → decisioni

style — stile grafico

Opzioni comuni:

  • filled
  • dashed
  • dotted
  • bold
  • rounded
  • combinazioni: "filled,rounded"

Esempio:

node [style="filled,rounded"];

fillcolor — colore di riempimento

Formati:

  • nomi (e.g. "lightgrey")
  • HEX (e.g. "#AABBCC")
  • RGB ("#rrggbb")
  • HSL (in alcune build)

fontname, fontcolor, fontsize

Es.:

node [fontname="Arial", fontsize=12, fontcolor="#333333"];

margin

Margine interno del nodo.

node [margin="0.2,0.1"];

Attributi degli archi (edge)

arrowsize

Scala della freccia. Default ~1.0

edge [arrowsize=0.8];

arrowhead / arrowtail

Opzioni utili:

  • normal
  • empty (triangolo vuoto, molto leggibile)
  • diamond
  • onormal
  • crow (diagrammi ER)
  • tee
  • none

style e color

edge [style=dashed, color="#888888"];

label

Etichetta dell’arco.

A -> B [label="calls"];

Attributi del grafo (graph)

rankdir

Direzione del layout (solo dot):

  • TB (top → bottom)
  • BT (bottom → top)
  • LR (left → right)
  • RL (right → left)

Es.:

graph [rankdir=LR];

splines

Controlla la forma degli archi:

  • true (default)
  • false (linee dritte)
  • polyline
  • ortho (ortogonali, ottimo per diagrammi “da architetto”)

ranksep, nodesep

Spazi orizzontali/verticali.

graph [ranksep=0.8, nodesep=0.6];

Layout Engines: scegliere quello giusto

Graphviz non ha un solo motore di rendering: ne offre diversi, ognuno ottimizzato per tipologie specifiche di grafo. Scegliere l’engine giusto significa ottenere diagrammi più leggibili e professionali.

Si specifica l’engine usando il flag -K da CLI:

dot -Kdot -Tsvg file.dot -o output.svg
dot -Kneato -Tsvg file.dot -o output.svg

Oppure nel file DOT stesso:

graph G {
    layout=neato;
    // ...
}

Di seguito i principali engine e quando usarli.


Motori di layout disponibili

dot — layout gerarchico (default)

Cosa fa: Dispone i nodi in modo gerarchico, seguendo la direzione degli archi. È il più usato.

Perfetto per:

  • Flowchart e diagrammi di flusso
  • Pipeline CI/CD
  • Call graph (grafo delle chiamate tra funzioni)
  • Architetture a layer (presentation → business → data)
  • Processi sequenziali
  • Diagrammi di dipendenza con direzione chiara

Esempio di comando:

dot -Tsvg flowchart.dot -o flowchart.svg

Quando evitarlo: Se il grafo non ha una struttura gerarchica chiara o contiene molti cicli.

neato — layout a forza fisica

Cosa fa: Posiziona i nodi simulando forze fisiche (repulsione/attrazione), generando layout organici e simmetrici.

Utile per:

  • Grafi non diretti (senza frecce)
  • Reti concettuali e mappe mentali
  • Relazioni non gerarchiche tra entità
  • Grafi piccoli/medi dove vuoi evidenziare cluster naturali

Esempio di comando:

dot -Kneato -Tsvg concepts.dot -o concepts.svg

Quando evitarlo: Con grafi molto grandi (>100 nodi) o fortemente direzionali.

fdp — force-directed placement

Cosa fa: Simile a neato, ma usa un algoritmo diverso (Fruchterman-Reingold). Generalmente più veloce su grafi medi.

Utile per:

  • Grafi non diretti di dimensioni medie
  • Visualizzazioni di social network (amicizie, collegamenti)
  • Analisi di dipendenze senza direzione forte

Esempio di comando:

dot -Kfdp -Tsvg network.dot -o network.svg

sfdp — scalable force-directed placement

Cosa fa: Versione ottimizzata di fdp per grafi molto grandi (migliaia di nodi).

Ottimo per:

  • Analisi delle dipendenze su codebase complesse
  • Grafo delle classi di un progetto enterprise
  • Reti complesse (infrastrutture, microservizi)
  • Quando neato o fdp sono troppo lenti

Esempio di comando:

dot -Ksfdp -Tsvg dependencies.dot -o dependencies.svg

Tip: Usa sfdp quando hai più di 100-200 nodi.

circo — layout circolare

Cosa fa: Dispone i nodi in cerchi concentrici attorno a un nodo centrale.

Ideale per:

  • Visualizzare moduli satellite attorno a un core centrale
  • Architetture hub-and-spoke
  • Rappresentare componenti che dipendono da un servizio centrale

Esempio di comando:

dot -Kcirco -Tsvg modules.dot -o modules.svg

Esempio pratico: Un servizio API centrale con 10 microservizi che lo chiamano.

twopi — layout radiale

Cosa fa: Crea un layout ad albero radiale, con il nodo radice al centro e i livelli che si espandono verso l’esterno.

Perfetto per:

  • Alberi gerarchici (org chart, file system)
  • Tassonomie
  • Mind map strutturate
  • Visualizzare espansioni da un punto centrale

Esempio di comando:

dot -Ktwopi -Tsvg tree.dot -o tree.svg

Come scegliere in pratica

Tipo di grafo Engine consigliato
Flowchart, pipeline, processi dot
Architetture layered dot
Call graph, dependency tree dot
Rete concettuale, brainstorming neato
Social network, grafi medi non diretti fdp
Grafi grandi (>200 nodi) sfdp
Hub centrale con satelliti circo
Alberi gerarchici, org chart twopi

Regola pratica: Se hai frecce e una direzione chiara → usa dot. Altrimenti prova neato o fdp.


Tipologie di grafici e quando usarli nella vita reale di un developer

Questa è la sezione più corposa. Per ogni tipo di grafico troverai:

  • Quando usarlo nella vita reale
  • Attributi consigliati
  • Esempio completo

Flowchart: capire il comportamento

Nel lavoro quotidiano capita spesso di dover spiegare un flusso decisionale complesso: una procedura di validazione con molteplici branch, un processo di onboarding utente, o semplicemente il comportamento di una funzione con tanti if/else annidati. Il flowchart è lo strumento ideale per questo.

Quando ti serve un flowchart:

Sei in fase di analisi requisiti e devi capire tutte le casistiche possibili. Stai debuggando una logica che sembra impazzita e vuoi vedere visivamente dove il flusso si biforca. Devi scrivere documentazione per un processo aziendale complesso. Stai facendo onboarding di un nuovo collega e vuoi mostrargli come funziona il sistema di autenticazione.

Il flowchart mostra visivamente le decisioni (rombi), i processi (rettangoli arrotondati), e il flusso logico (frecce). È immediato, chiaro, universale.

Attributi consigliati per flowchart professionali:

Usa rankdir=TB (top-to-bottom) per seguire la convenzione standard dei flowchart. Usa shape=diamond per i nodi decisionali (le condizioni if/else). Usa style=rounded per gli step di processo, così si distinguono dai rombi. Usa colori tenui (fillcolor) per evidenziare start (verde chiaro), errori (rosso chiaro), fine (grigio).

Esempio completo:

digraph Flow {
    graph [rankdir=TB, nodesep=0.6];
    node [fontname="Arial"];

    Start   [shape=oval, style=filled, fillcolor="#C1F2C7"];
    Check   [shape=diamond, label="Valid input?"];
    Process [shape=box, style="filled,rounded", fillcolor="#F0F4FF"];
    Error   [shape=box, fillcolor="#FFEAEA", style=filled];
    End     [shape=oval, fillcolor="#DDDDDD", style=filled];

    Start -> Check;
    Check -> Process [label="yes"];
    Check -> Error   [label="no"];
    Process -> End;
}

Cosa fa questo esempio: Parte da uno stato iniziale (Start), passa attraverso una validazione (Check), e si biforca in due percorsi: successo (Process) o errore (Error). Usa colori per rendere immediatamente chiaro cosa è positivo e cosa negativo.


Grafi di dipendenza: capire il software come sistema

Quando lavori su un progetto esistente, una delle prime domande che ti fai è: “Cosa dipende da cosa?” Se devi fare refactoring di un modulo, vuoi sapere chi lo usa. Se devi aggiornare una libreria, vuoi capire l’impatto a cascata. Se stai progettando una nuova feature, vuoi vedere dove si inserisce nell’architettura esistente.

Il grafo delle dipendenze è la mappa del tuo sistema. Mostra moduli, servizi, classi, o microservizi come nodi, e le dipendenze come frecce. È fondamentale per:

Refactoring sicuro: Prima di toccare un modulo, vedi chi lo chiama. Analisi di impatto: Se modifichi un’API, vedi immediatamente tutti i consumatori. Documentazione automatica: Genera il grafo dal codice (con tool come Doxygen, Madge, o script custom) e mantienilo aggiornato. Dependency injection mapping: Visualizza come Spring, Angular o .NET iniettano le dipendenze.

Attributi utili:

Usa rankdir=LR (left-to-right) per avere un flusso orizzontale, tipico delle dependency chain. Usa shape=box per i moduli/servizi. Usa color e penwidth per evidenziare dipendenze critiche o problematiche (es. dipendenze circolari in rosso). Usa style=dashed per dipendenze opzionali o deboli.

Esempio:

digraph Deps {
    graph [rankdir=LR];
    node [shape=box, style=filled, fillcolor="#F7FAFF", fontname="Inter"];
    edge [color="#555555"];

    UI -> API;
    API -> Auth;
    API -> UserService;
    UserService -> Database [color="#FF5555", penwidth=2, label="critical"];
}

Cosa fa questo esempio: Mostra una classica architettura web: UI chiama API, API dipende da Auth e UserService, UserService parla col Database. La dipendenza critica (UserService → Database) è evidenziata in rosso con linea spessa: se il DB va giù, tutto crolla.


Architettura software: cluster e layer

Quando progetti un’architettura o documenti quella esistente, hai bisogno di mostrare raggruppamenti logici e separazione dei livelli. Un sistema web tipico ha Presentation, Business, Data. Un progetto a microservizi ha boundary logici (edge, services, datastores). Un sistema legacy potrebbe avere moduli separati per dominio.

Il diagramma di architettura con cluster ti permette di:

Visualizzare layer separati: Presentation Layer, Business Layer, Data Layer. Ogni layer è un box colorato che contiene i suoi componenti. Mostrare boundary dei microservizi: Edge Gateway, Services, Datastores. Ogni boundary è un cluster. Documentare moduli legacy: Isola i moduli per responsabilità (Auth, Orders, Reporting) così è chiaro chi fa cosa. Presentare l’architettura a stakeholder: Un diagramma layered è universale e comprensibile anche dai non-tecnici.

Attributi utili:

Usa subgraph cluster_* per creare raggruppamenti visivi. Usa compound=true per permettere archi che attraversano i cluster. Usa splines=ortho per linee ortogonali, tipiche dei diagrammi “da architetto”. Usa shape=cylinder per i database, così sono immediatamente riconoscibili.

Esempio architettura layered:

digraph Architecture {
    graph [
        rankdir=TB,
        ranksep=0.8,
        nodesep=0.6,
        overlap=false,
        splines=true,
        sep="+0.2"
    ];
    node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Arial"];

    subgraph cluster_presentation {
        label="Presentation Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#E8F4F8";
        UI;
    }

    subgraph cluster_business {
        label="Business Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#FFF4E6";
        ServiceA; ServiceB;
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#F0F0F0";
        DB [shape=cylinder, fillcolor="#D0E8FF"];
    }

    UI -> ServiceA;
    UI -> ServiceB;
    ServiceA -> DB;
    ServiceB -> DB;
}

Cosa fa questo esempio: Definisce tre layer con subgraph cluster_*. Presentation contiene UI, Business contiene due servizi, Data contiene il DB (con shape=cylinder). Le frecce mostrano il flusso: UI → Services → DB. L’architettura è immediatamente comprensibile.


Microservices Map: capire un ecosistema distribuito

Se lavori con microservizi, hai decine di servizi che comunicano tra loro: API Gateway, servizi di dominio (Orders, Users, Notifications), database, code, cache. Quando arriva un incident in produzione, la prima domanda è: “Chi parla con chi? Dov’è il collo di bottiglia?”

La mappa dei microservizi è il tuo GPS nel caos distribuito. Ti serve per:

Design architetturale: Prima di scrivere codice, disegna la mappa. Identifica i boundary logici (edge, core services, datastores). Documentazione API: Mostra chi chiama quale servizio e attraverso quale protocollo (REST, gRPC, eventi). Analisi di performance: Durante un incident, guardi la mappa e capisci subito se il problema è nell’API Gateway, in un servizio specifico, o nel DB condiviso. Post-mortem: Dopo un down, la mappa aiuta a ricostruire la catena di fallimento.

Attributi utili:

Usa cluster per separare i boundary logici (Edge, Services, Data). Usa shape=cylinder per database, shape=box per servizi. Usa label sugli archi per specificare il protocollo (HTTP, gRPC, Kafka). Usa shape=plaintext con HTML table per servizi complessi con porte multiple.

Esempio:

digraph Micro {
    graph [rankdir=LR, splines=true];
    node [shape=plaintext];

    subgraph cluster_gateway {
        label="Edge";
        Gateway [label="API Gateway"];
    }

    subgraph cluster_services {
        label="Services";
        Order; User; Notification;
    }

    subgraph cluster_data {
        label="Datastores";
        DB [shape=cylinder, label="Postgres"];
        Cache [shape=box, label="Redis"];
    }

    Gateway -> User;
    Gateway -> Order;
    Order -> DB;
    User -> Cache;
    Notification -> User;
}

Cosa fa questo esempio: Organizza l’ecosistema in tre cluster: Edge (Gateway), Services (Order, User, Notification), Datastores (DB, Cache). Le frecce mostrano le chiamate: Gateway → User/Order, Order → DB, User → Cache. È la mappa completa del sistema.


Diagrammi di stato: modellare comportamenti

Molti sistemi hanno un comportamento a stati: una richiesta HTTP può essere Idle, Loading, Success, Error. Un ordine e-commerce passa da Draft → Pending → Confirmed → Shipped. Un sistema embedded ha stati di accensione, standby, operativo, errore. Un’interfaccia UI ha stati di caricamento, pronta, errore.

Il diagramma di stato modella questi comportamenti come un grafo: ogni nodo è uno stato, ogni arco è una transizione etichettata con l’evento che la causa. È fondamentale per:

Progettare macchine a stati: Prima di implementare lo state pattern nel codice, disegna il diagramma. Documentare protocolli: I protocolli di rete (TCP, WebSocket, custom) hanno state machine precise. Il diagramma le rende esplicite. Modellare UI/UX flow: Quando progetti un’app, disegna gli stati dell’interfaccia: caricamento, pronta, errore, vuota. Debug di sistemi embedded: Se un device si blocca in uno stato, il diagramma ti aiuta a capire quali transizioni mancano.

Attributi utili:

Usa shape=circle per gli stati (convention standard delle FSM). Usa rankdir=LR per layout orizzontale, tipico degli state diagram. Usa label sugli archi per mostrare l’evento che causa la transizione. Usa shape=doublecircle per stati finali/terminali.

Esempio:

digraph States {
    graph [rankdir=LR];
    node [shape=circle, fontsize=12];

    Idle -> Loading   [label="start"];
    Loading -> Ready  [label="success"];
    Loading -> Error  [label="fail"];
    Error -> Idle     [label="reset"];
    Ready -> Idle     [label="finish"];
}

Cosa fa questo esempio: Modella il ciclo di vita di una richiesta asincrona: parte da Idle, va in Loading quando parte la chiamata, poi Success o Error a seconda del risultato. Da Error può tornare Idle con un reset. Da Ready può tornare Idle al completamento. Ogni transizione è etichettata con l’evento che la causa.


Diagrammi delle classi con record

Quando progetti un sistema object-oriented, o vuoi documentare il dominio di un’applicazione, il diagramma delle classi è lo standard. Mostra classi con attributi e metodi, e le relazioni tra loro (ereditarietà, composizione, dipendenza).

DOT non è UML, ma con shape=record ottieni qualcosa di molto simile e perfettamente leggibile. È utile per:

Progettazione iniziale: Prima di scrivere il codice, disegna le classi principali del dominio. Identifica attributi, metodi, relazioni. Refactoring: Quando devi ristrutturare un modulo, disegna lo stato attuale e quello desiderato. Confronta i due diagrammi. Domain-Driven Design (DDD): Modella le entità, value object, aggregati. Il diagramma aiuta a visualizzare i boundary del dominio. Documentazione: Genera il diagramma automaticamente dal codice (con tool come Doxygen) e mantienilo aggiornato.

Attributi utili:

Usa shape=record per creare box con sezioni separate (nome classe | attributi | metodi). Usa fontname="Courier New" o monospace per renderlo simile a codice. Usa arrowhead=onormal per ereditarietà (freccia vuota, standard UML). Usa \l (backslash-l) per allineare il testo a sinistra dentro i record.

Esempio:

digraph Classes {
    node [shape=record, fontname="Courier New"];

    Person [label="{Person|name: string\l age: int\l|greet()}"];
    Employee [label="{Employee|id: int\l role: string\l|work()}"];

    Person -> Employee [arrowhead="onormal"];
}

Cosa fa questo esempio: Definisce due classi: Person (con attributi nome, età, metodo greet) e Employee (con id, ruolo, metodo work). Person è la superclasse di Employee (freccia con arrowhead=onormal, standard UML per l’ereditarietà). Il \l allinea il testo a sinistra dentro i record.


Diagrammi ER professionali con HTML-label

Se lavori con database, prima o poi devi disegnare lo schema delle tabelle: chiavi primarie, foreign key, relazioni 1:N o N:N. Il diagramma Entity-Relationship (ER) è lo standard per questo.

DOT supporta tabelle HTML dentro i nodi con shape=plaintext, permettendoti di creare diagrammi ER puliti e professionali. È fondamentale per:

Progettazione database: Prima di scrivere le migration, disegna lo schema. Identifica le entità, gli attributi, le relazioni. Valida il design con il team. Data modeling: Quando progetti un nuovo modulo, parti dal modello dati. Il diagramma ER ti aiuta a ragionare su normalizzazione e performance. Reverse engineering: Quando erediti un DB legacy senza documentazione, genera il diagramma ER dal DB stesso (con tool come SchemaSpy o pg_dump + script) per capire la struttura. Documentazione: Il diagramma ER è comprensibile anche dai non-developer (product manager, analisti business).

Attributi utili:

Usa shape=plaintext per abilitare HTML label. Usa <TABLE> HTML per creare box strutturati con header (nome tabella) e righe (campi). Usa arrowhead=crow per relazioni 1:N (standard dei diagrammi ER). Usa label="1:N" sugli archi per rendere esplicita la cardinalità.

Esempio:

digraph ER {
    node [shape=plaintext];

    User [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD><B>User</B></TD></TR>
            <TR><TD>id PK</TD></TR>
            <TR><TD>email</TD></TR>
        </TABLE>
    >];

    Order [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD><B>Order</B></TD></TR>
            <TR><TD>id PK</TD></TR>
            <TR><TD>user_id FK</TD></TR>
        </TABLE>
    >];

    User -> Order [label="1:N", arrowhead="crow"];
}

Cosa fa questo esempio: Definisce due tabelle (User e Order) usando HTML. Ogni tabella ha un header in grassetto e righe per i campi. La freccia con arrowhead=crow e label="1:N" mostra la relazione: un User ha molti Order (chiave esterna user_id in Order).


Diagrammi CI/CD Pipeline

Se lavori in un team che fa continuous integration e deployment, hai una pipeline che esegue step automatici: build, test, analisi statica, packaging, deploy, monitoraggio. Quando qualcosa si rompe, o quando fai onboarding di un nuovo developer, serve un diagramma che mostri l’intera pipeline.

Il diagramma CI/CD visualizza il flusso automatico dal commit al deploy. È utile per:

DevOps e SRE: Documentare la pipeline esistente. Identificare colli di bottiglia (quale step richiede più tempo?). Onboarding team: Un nuovo developer guarda il diagramma e capisce subito cosa succede dopo un git push. Ottimizzazione: Vuoi parallelizzare alcuni step? Il diagramma ti mostra quali dipendono da quali. Debugging: La pipeline fallisce? Il diagramma ti aiuta a capire a che step e perché (freccia tratteggiata per i retry).

Attributi utili:

Usa rankdir=LR per flusso orizzontale (tipico delle pipeline). Usa shape=box con style=filled per gli step, colorandoli per tipo (build=blu, test=verde, deploy=rosso). Usa style=dotted con label="retry" per mostrare meccanismi di retry automatico. Usa label sugli archi per indicare condizioni (es. “only on master branch”).

Esempio:

digraph CICD {
    graph [rankdir=LR];
    node [shape=box, style=filled, fillcolor="#F8FBFF"];

    Code -> Build -> Test -> Package -> Deploy -> Monitor;

    Test -> Build [style=dotted, label="retry"];
}

Cosa fa questo esempio: Mostra una pipeline classica: Code → Build → Test → Package → Deploy → Monitor. La freccia tratteggiata da Test a Build mostra un retry automatico in caso di fallimento dei test. È un flusso lineare, immediatamente comprensibile.


Sottrarre complessità: mappe concettuali e analisi

Non tutti i diagrammi devono essere gerarchici o direzionali. A volte hai bisogno di visualizzare relazioni concettuali senza una struttura fissa: durante un brainstorming, quando fai design collettivo con il team, o quando vuoi mappare le dipendenze concettuali tra aree tecnologiche.

La mappa concettuale non ha un “inizio” o una “fine”: è una rete di nodi collegati organicamente. È utile per:

Brainstorming: Parti da un’idea centrale e aggiungi nodi collegati mentre discuti con il team. La mappa cresce naturalmente. Design collettivo: Durante una sessione di design, mappa i componenti e le loro relazioni. Non sai ancora la gerarchia, ma sai che “Backend parla con Database e API”. Analisi delle dipendenze concettuali: Vuoi capire quali aree tecnologiche sono collegate (es. Security → Logging → Observability). Documentazione di alto livello: Per stakeholder non-tecnici, una mappa concettuale è più accessibile di un grafo gerarchico.

Attributi utili:

Usa engine neato o fdp invece di dot, per ottenere un layout organico basato su forze fisiche. Usa shape=ellipse per nodi concettuali (non processi). Usa style=filled con colori tenui per raggruppamenti visivi. Usa grafi non diretti (graph invece di digraph) se le relazioni sono bidirezionali.

Esempio con engine neato:

graph Concepts {
    layout=neato;
    node [shape=ellipse, style=filled, fillcolor="#EFEFFF"];

    Backend -- Database;
    Backend -- API;
    API -- Security;
    Security -- Logging;
    Logging -- Observability;
}

Evitare sovrapposizioni: overlap e splines

Uno dei problemi più comuni quando si disegnano grafi complessi è la sovrapposizione di frecce, testi e nodi. Graphviz offre attributi specifici per controllare questo comportamento e rendere i diagrammi più leggibili.

Il problema: sovrapposizioni indesiderate

Quando hai molti nodi e frecce, specialmente con layout gerarchici o con splines=ortho, le frecce possono sovrapporsi ai label dei cluster o ai nodi. Ecco un esempio tipico del problema:

digraph OverlapProblem {
    graph [rankdir=TB, splines=ortho];
    node [shape=box, style=rounded];

    subgraph cluster_a {
        label="Component A";
        A1; A2;
    }

    subgraph cluster_b {
        label="Component B";
        B1; B2;
    }

    subgraph cluster_c {
        label="Component C";
        C1; C2;
    }

    A1 -> B1;
    A2 -> B2;
    B1 -> C1;
    B2 -> C2;
    A1 -> C1;
}

Problema: Con splines=ortho le frecce possono attraversare i label dei cluster rendendo il diagramma confuso.

La soluzione: overlap e splines

Graphviz offre diversi attributi per risolvere questo problema:

overlap — evita sovrapposizioni tra nodi

graph [overlap=false];

Opzioni principali:

  • false o voronoi — evita sovrapposizioni (migliore qualità, più lento)
  • scale — scala il grafo per evitare sovrapposizioni
  • scalexy — scala con proporzioni diverse su X e Y
  • true (default) — permette sovrapposizioni

splines — controlla la forma degli archi

graph [splines=true];

Opzioni:

  • true o spline — curve smooth che evitano nodi (raccomandato)
  • curved — archi leggermente curvi
  • polyline — linee spezzate
  • ortho — linee ortogonali (può causare sovrapposizioni!)
  • line o false — linee dritte

sep — margine extra tra elementi

graph [sep="+0.2"];

Aggiunge margine tra nodi e archi (in pollici). Il + significa “aggiungi al valore di default”.

ranksep e nodesep — spaziatura tra livelli e nodi

graph [ranksep=0.8, nodesep=0.6];

Aumenta lo spazio verticale (ranksep) e orizzontale (nodesep) tra gli elementi.

Esempio migliorato

Ecco lo stesso grafo con attributi ottimizzati per evitare sovrapposizioni:

digraph OverlapSolved {
    graph [
        rankdir=TB,
        ranksep=0.8,
        nodesep=0.6,
        overlap=false,
        splines=true,
        sep="+0.2"
    ];
    node [shape=box, style=rounded];

    subgraph cluster_a {
        label="Component A";
        style=filled;
        fillcolor="#E8F4F8";
        A1; A2;
    }

    subgraph cluster_b {
        label="Component B";
        style=filled;
        fillcolor="#FFF4E6";
        B1; B2;
    }

    subgraph cluster_c {
        label="Component C";
        style=filled;
        fillcolor="#F0F0F0";
        C1; C2;
    }

    A1 -> B1;
    A2 -> B2;
    B1 -> C1;
    B2 -> C2;
    A1 -> C1;
}

Risultato: Le frecce ora evitano i nodi e i label, il grafo è più spazioso e leggibile. I colori di sfondo aiutano a distinguere i cluster.

Quando usare cosa

Scenario Attributi consigliati
Diagrammi complessi con molti nodi overlap=false, splines=true
Grafi gerarchici (flowchart, architetture) ranksep=0.8, nodesep=0.6, splines=true
Grafi con cluster overlap=false, sep="+0.2"
Diagrammi “da architetto” con linee dritte splines=polyline (evita ortho)
Grafi piccoli e semplici default (non serve modificare)

Regola pratica: Inizia sempre con overlap=false e splines=true se hai più di 10 nodi o usi cluster.

Esempio completo con tutte le best practices

Ecco un esempio reale che combina tutti gli attributi consigliati: architettura a microservizi con 4 layer, molti nodi e archi, cluster colorati, spazi ottimizzati:

digraph CompleteExample {
    graph [
        rankdir=TB,
        ranksep=1.0,
        nodesep=0.7,
        overlap=false,
        splines=true,
        sep="+0.25"
    ];
    node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Arial", fontsize=11];
    edge [color="#555555", arrowsize=0.8];

    subgraph cluster_frontend {
        label="Frontend Layer";
        style=filled;
        fillcolor="#E8F4F8";
        color="#5A9FD4";

        WebUI [label="Web UI"];
        MobileApp [label="Mobile App"];
    }

    subgraph cluster_api {
        label="API Gateway Layer";
        style=filled;
        fillcolor="#FFF4E6";
        color="#E8A87C";

        Gateway [label="API Gateway"];
        LoadBalancer [label="Load Balancer"];
    }

    subgraph cluster_services {
        label="Microservices Layer";
        style=filled;
        fillcolor="#F0F8E8";
        color="#90C290";

        AuthService [label="Auth Service"];
        UserService [label="User Service"];
        OrderService [label="Order Service"];
        PaymentService [label="Payment Service"];
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        fillcolor="#F5F5F5";
        color="#999999";

        UsersDB [shape=cylinder, fillcolor="#D0E8FF", label="Users DB"];
        OrdersDB [shape=cylinder, fillcolor="#D0E8FF", label="Orders DB"];
        Cache [shape=box, fillcolor="#FFE8D0", label="Redis Cache"];
    }

    // Frontend to Gateway
    WebUI -> LoadBalancer [label="HTTPS"];
    MobileApp -> LoadBalancer [label="HTTPS"];

    // Gateway to Services
    LoadBalancer -> Gateway;
    Gateway -> AuthService [label="gRPC"];
    Gateway -> UserService [label="REST"];
    Gateway -> OrderService [label="REST"];

    // Service dependencies
    OrderService -> PaymentService [label="API call"];
    UserService -> AuthService [label="validate"];
    PaymentService -> AuthService [label="validate"];

    // Data access
    AuthService -> UsersDB;
    UserService -> UsersDB;
    UserService -> Cache [style=dashed, label="cache"];
    OrderService -> OrdersDB;
    OrderService -> Cache [style=dashed, label="cache"];
}

Command line:

dot -Tsvg overlap_complete.dot -o overlap_complete.svg

Cosa dimostra questo esempio:

  • overlap=false: Nessuna sovrapposizione tra nodi, anche con 13 nodi e 4 cluster
  • splines=true: Frecce curve che evitano elegantemente nodi e label
  • sep="+0.25": Margine extra che mantiene tutto leggibile
  • ranksep=1.0, nodesep=0.7: Spaziatura generosa tra layer e nodi
  • Cluster colorati: Ogni layer ha un colore distintivo per identificazione immediata
  • Label sugli archi: Protocolli (HTTPS, gRPC, REST) e tipo di connessione espliciti
  • Style dashed per cache: Dipendenze opzionali visualizzate diversamente
  • Cylinder shape per DB: Database immediatamente riconoscibili

Questo è il template perfetto per documentare architetture complesse in modo professionale e leggibile.


Color Schemes: palette professionali pronte all’uso

Graphviz include color schemes predefiniti basati su palette professionali di ColorBrewer. Invece di scegliere colori manualmente, puoi usare palette testate per leggibilità, accessibilità e professionalità.

Come funzionano i color schemes

Usa l’attributo colorscheme per selezionare una palette, poi usa i numeri 1-9 (o più, dipende dallo schema) invece dei codici hex:

node [colorscheme=set39, fillcolor=1, color=2];

I color schemes sono organizzati in categorie:

  • Qualitative (set1, set2, set3, pastel1, pastel2, dark2, paired, accent) — Per categorie distinte
  • Sequential (blues3-9, greens3-9, reds3-9, purples3-9, oranges3-9) — Per valori progressivi
  • Diverging (rdylgn3-11, spectral3-11, rdbu3-11) — Per dati con punto centrale

Riferimento completo: graphviz.org/docs/attrs/colorscheme/

Esempi pratici con color schemes professionali

Ogni esempio usa lo stesso diagramma (processo a 5 step) ma con palette diverse. Confronta e scegli quello più adatto al tuo caso d’uso.

Esempio 1: Set39 (qualitativo, vivace)

Ottimo per distinguere categorie diverse, presentazioni colorate, dashboard.

digraph ProcessSet39 {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=set39, fontname=Arial];
    edge [colorscheme=set39, penwidth=2];

    Start [fillcolor=1, label="Start"];
    Validate [fillcolor=2, label="Validate"];
    Process [fillcolor=3, label="Process"];
    Store [fillcolor=4, label="Store"];
    Notify [fillcolor=5, label="Notify"];

    Start -> Validate [color=1];
    Validate -> Process [color=2];
    Process -> Store [color=3];
    Store -> Notify [color=4];
}

Command line:

dot -Tsvg colorscheme_set39.dot -o colorscheme_set39.svg

Esempio 2: Pastel19 (qualitativo, soft)

Colori pastello per documentazione tecnica, wiki, blog post. Meno impattante ma più leggibile a lungo.

digraph ProcessPastel {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=pastel19, fontname=Arial, fontcolor="#333333"];
    edge [colorscheme=dark28, penwidth=2];

    Start [fillcolor=1, label="Start"];
    Validate [fillcolor=3, label="Validate"];
    Process [fillcolor=5, label="Process"];
    Store [fillcolor=7, label="Store"];
    Notify [fillcolor=9, label="Notify"];

    Start -> Validate [color=1];
    Validate -> Process [color=3];
    Process -> Store [color=5];
    Store -> Notify [color=7];
}

Command line:

dot -Tsvg colorscheme_pastel.dot -o colorscheme_pastel.svg

Esempio 3: Blues9 (sequential, progressione)

Ideale per mostrare intensità crescente, priorità, fasi di maturazione.

digraph ProcessBlues {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=blues9, fontname=Arial];
    edge [color="#2171B5", penwidth=2];

    Start [fillcolor=2, fontcolor=black, label="Start"];
    Validate [fillcolor=4, fontcolor=white, label="Validate"];
    Process [fillcolor=6, fontcolor=white, label="Process"];
    Store [fillcolor=8, fontcolor=white, label="Store"];
    Notify [fillcolor=9, fontcolor=white, label="Notify"];

    Start -> Validate -> Process -> Store -> Notify;
}

Command line:

dot -Tsvg colorscheme_blues.dot -o colorscheme_blues.svg

Esempio 4: RdYlGn9 (diverging, semaforo)

Perfetto per stati di successo/warning/errore, health checks, monitoring.

digraph ProcessStatus {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=rdylgn9, fontname=Arial, fontcolor=black];
    edge [penwidth=2, color="#666666"];

    Idle [fillcolor=5, label="Idle\n(neutral)"];
    Starting [fillcolor=7, label="Starting\n(ok)"];
    Running [fillcolor=9, label="Running\n(good)"];
    Warning [fillcolor=4, label="Warning"];
    Error [fillcolor=1, label="Error"];

    Idle -> Starting -> Running;
    Running -> Warning [style=dashed];
    Warning -> Error [style=dashed];
    Running -> Idle [label="stop"];
}

Command line:

dot -Tsvg colorscheme_rdylgn.dot -o colorscheme_rdylgn.svg

Esempio 5: Paired12 (qualitativo, coppie)

Usa coppie di colori coordinati. Ottimo per confronti, versioni A/B, relazioni.

digraph ProcessPaired {
    graph [rankdir=TB, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=paired12, fontname=Arial];
    edge [colorscheme=paired12, penwidth=2];

    subgraph cluster_v1 {
        label="Version 1.x";
        style=filled;
        fillcolor="#F0F0F0";
        V1_Start [fillcolor=1, label="Start v1"];
        V1_Process [fillcolor=1, label="Process v1"];
        V1_End [fillcolor=1, label="End v1"];
        V1_Start -> V1_Process -> V1_End;
    }

    subgraph cluster_v2 {
        label="Version 2.x";
        style=filled;
        fillcolor="#F8F8F8";
        V2_Start [fillcolor=2, label="Start v2"];
        V2_Process [fillcolor=2, label="Process v2"];
        V2_End [fillcolor=2, label="End v2"];
        V2_Start -> V2_Process -> V2_End;
    }

    V1_Start -> V2_Start [label="upgrade", color=4, style=dashed];
}

Command line:

dot -Tsvg colorscheme_paired.dot -o colorscheme_paired.svg

Esempio 6: Accent8 (qualitativo, contrasti forti)

Massimo contrasto tra elementi. Per evidenziare differenze importanti.

digraph ProcessAccent {
    graph [rankdir=LR, bgcolor="#F5F5F5"];
    node [shape=box, style="rounded,filled", colorscheme=accent8, fontname=Arial, fontcolor=black];
    edge [colorscheme=accent8, penwidth=2];

    Input [fillcolor=1, label="Input"];
    Parse [fillcolor=2, label="Parse"];
    Transform [fillcolor=3, label="Transform"];
    Validate [fillcolor=4, label="Validate"];
    Output [fillcolor=5, label="Output"];

    Input -> Parse [color=1];
    Parse -> Transform [color=2];
    Transform -> Validate [color=3];
    Validate -> Output [color=4];
    Validate -> Parse [color=6, label="retry", style=dashed];
}

Command line:

dot -Tsvg colorscheme_accent.dot -o colorscheme_accent.svg

Quando usare quale color scheme

Scenario Color Scheme Consigliato
Categorie diverse, presentazioni set39, set28, dark28
Documentazione tecnica, wiki pastel19, pastel28
Progressione, priorità, livelli blues9, greens9, purples9, oranges9
Stati (ok/warning/error) rdylgn9, rdylbu9, spectral9
Confronti, versioni A/B paired12, paired11
Massimo contrasto accent8, set39
Accessibilità (daltonismo) set2, dark2 (ColorBrewer safe)

Combinare color schemes

Puoi usare schemi diversi per nodi e archi:

node [colorscheme=pastel19, fillcolor=3];
edge [colorscheme=dark28, color=2];

Tip: Testa sempre i colori con ColorBrewer per verificare accessibilità e stampabilità.


Tecniche avanzate: ports, ranks, compound edges

Ports nei record — Collega archi a campi specifici di un record usando la sintassi nodo:porta:

ClassA:field1 -> ClassB:field2;

Forzare nodi allo stesso livello — Usa rank=same per posizionare più nodi sulla stessa riga orizzontale:

{ rank=same; A; B; C; }

Compound edges tra cluster — Collega cluster interi invece di singoli nodi con lhead e ltail:

edge [lhead=cluster_B, ltail=cluster_A];

Archi ortogonali — Crea archi con angoli retti per uno stile “da architetto”:

graph [splines=ortho];

Stile professionale: consigli pratici

  • Usa palette coerenti.
  • Evita gradienti troppo brillanti.
  • Usa Inter, Arial o Roboto per leggibilità.
  • Usa ortho per archi “da architetto”.
  • Mantieni margini adeguati (nodesep, ranksep).
  • Preferisci SVG per qualità nei blog.
  • Mantieni i file DOT versionati.

Stili grafici pronti all’uso

Qui trovi 5 varianti stilistiche per lo stesso state diagram, pronte da copiare e adattare ai tuoi diagrammi. Ogni stile definisce colori, font, dimensioni e forme per creare un look coerente.

Stile 1: Corporate Blue (professionale, formale)

Palette blu/grigio, font Arial, stile pulito per presentazioni aziendali.

digraph CorporateBlue {
    graph [
        rankdir=LR,
        bgcolor="#F8F9FA",
        fontname="Arial",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#E3F2FD",
        color="#1976D2",
        fontname="Arial",
        fontsize=11,
        fontcolor="#1565C0",
        penwidth=2
    ];
    edge [
        color="#1976D2",
        fontname="Arial",
        fontsize=10,
        fontcolor="#424242"
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_corporate.dot -o style_corporate.svg

Stile 2: Dark Mode (moderno, tech)

Sfondo scuro, testo chiaro, palette verde/ciano per UI moderne e developer tools.

digraph DarkMode {
    graph [
        rankdir=LR,
        bgcolor="#1E1E1E",
        fontname="Consolas",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#2D2D30",
        color="#00D9FF",
        fontname="Consolas",
        fontsize=11,
        fontcolor="#E0E0E0",
        penwidth=2
    ];
    edge [
        color="#00D9FF",
        fontname="Consolas",
        fontsize=10,
        fontcolor="#B0B0B0"
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_dark.dot -o style_dark.svg

Stile 3: Warm Minimal (soft, leggibile)

Palette calda arancio/beige, sans-serif, ottimo per documentazione tecnica.

digraph WarmMinimal {
    graph [
        rankdir=LR,
        bgcolor="#FFFBF5",
        fontname="Helvetica",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#FFE8CC",
        color="#FF8C42",
        fontname="Helvetica",
        fontsize=11,
        fontcolor="#6B4423",
        penwidth=1.5
    ];
    edge [
        color="#FF8C42",
        fontname="Helvetica",
        fontsize=10,
        fontcolor="#8B5A3C",
        penwidth=1.5
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_warm.dot -o style_warm.svg

Stile 4: Monochrome (elegante, stampabile)

Bianco e nero, gradazioni di grigio, perfetto per stampa e documentazione formale.

digraph Monochrome {
    graph [
        rankdir=LR,
        bgcolor="white",
        fontname="Times-Roman",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#F5F5F5",
        color="#333333",
        fontname="Times-Roman",
        fontsize=11,
        fontcolor="#000000",
        penwidth=2
    ];
    edge [
        color="#333333",
        fontname="Times-Roman",
        fontsize=10,
        fontcolor="#666666",
        penwidth=1.5
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_mono.dot -o style_mono.svg

Stile 5: Vibrant Gradient (creativo, impattante)

Colori vivaci con sfumature, ottimo per presentazioni e slide visivamente accattivanti.

digraph VibrantGradient {
    graph [
        rankdir=LR,
        bgcolor="#FAFAFA",
        fontname="Verdana",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#A8E6CF:#56CCF2",
        gradientangle=90,
        color="#2D6A9F",
        fontname="Verdana",
        fontsize=11,
        fontcolor="#1A3A52",
        penwidth=2.5
    ];
    edge [
        color="#9B59B6",
        fontname="Verdana",
        fontsize=10,
        fontcolor="#5B3A72",
        penwidth=2
    ];

    Idle [label="Idle"];
    Processing [label="Processing", fillcolor="#FFD93D:#FF6B9D", gradientangle=90];
    Complete [label="Complete", fillcolor="#6BCF7F:#4ECDC4", gradientangle=90];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_vibrant.dot -o style_vibrant.svg

Come usare questi stili

Copia il blocco graph, node, edge dello stile che preferisci e applicalo ai tuoi diagrammi. Puoi poi personalizzare:

  • Colori: sostituisci i codici hex con la tua palette
  • Font: usa fontname="NomeFont" (Arial, Helvetica, Courier, Times, Verdana, Consolas)
  • Dimensioni: fontsize per testo, penwidth per spessore bordi e frecce
  • Shape: box, ellipse, circle, diamond, cylinder, record
  • Gradienti: usa fillcolor="color1:color2" con gradientangle (solo alcuni output format)

Note sulla compatibilità dei font

I font devono essere installati sul sistema dove generi le immagini:

  • Font universali (funzionano ovunque): Arial, Helvetica, Times, Times-Roman, Courier
  • Font moderni (verificare disponibilità): Verdana, Consolas, Roboto, Inter
  • Windows: la maggior parte dei font sono già installati
  • macOS: ottimo supporto per font standard
  • Linux: installa fonts-liberation o fonts-dejavu per avere Arial/Helvetica equivalenti
  • CI/CD: usa font base o includi i font nel container Docker

Se un font non è disponibile, Graphviz usa un fallback (solitamente Times). Per essere sicuro, usa sempre font base o testa la generazione sull’ambiente di produzione.


Workflow: come integrare Graphviz nel lavoro reale

  1. Metti i file .gv nella repo.

  2. Genera gli SVG automaticamente nella CI:

    dot -Tsvg diagram.gv -o diagram.svg
    
  3. Inietta gli SVG nella documentazione (README, wiki, blog).

  4. Aggiorna i diagrammi ad ogni refactoring.

  5. Usa differ e versioning dei file DOT come faresti col codice.


Troubleshooting: errori comuni e soluzioni

Errore: “syntax error in line X near…”

  • Causa: Sintassi DOT non valida
  • Soluzione: Controlla punto e virgola mancanti, parentesi graffe non chiuse, virgolette non matchate
  • Esempio: A -> B deve terminare con ;A -> B;

Errore: “Warning: Unable to find font…”

  • Causa: Il font specificato non è installato sul sistema
  • Soluzione: Usa font universali (Arial, Helvetica, Times) o installa il font richiesto
  • Verifica font disponibili: dot -v mostra i font disponibili

Il diagramma è troppo grande/piccolo

  • Soluzione 1: Aggiungi graph [size="8,6"] per limitare dimensioni (in pollici)
  • Soluzione 2: Usa graph [ratio=compress] per comprimere automaticamente
  • Soluzione 3: Genera PNG con DPI custom: dot -Tpng -Gdpi=150 file.dot -o file.png

Le frecce si sovrappongono ai nodi

  • Soluzione: Aggiungi graph [overlap=false, splines=true] (vedi sezione “Evitare sovrapposizioni”)

I nodi sono tutti allineati orizzontalmente invece che verticalmente

  • Soluzione: Usa graph [rankdir=TB] per top-to-bottom (default è LR = left-to-right)

Il cluster non appare

  • Causa: Nome cluster non inizia con cluster_
  • Soluzione: Rinomina subgraph mygroup in subgraph cluster_mygroup

Output SVG troppo grande (file size)

  • Causa: SVG con molti elementi
  • Soluzione 1: Usa PNG invece di SVG per grafi molto complessi
  • Soluzione 2: Ottimizza con svgo: svgo input.svg -o output.svg

Grafo non si genera (nessun output, nessun errore)

  • Causa: Comando errato o redirect sbagliato
  • Verifica: Usa -v per verbose: dot -v -Tsvg input.dot -o output.svg
  • Test rapido: echo "digraph{A->B}" | dot -Tsvg > test.svg

Le label degli archi non si vedono

  • Causa: Label troppo lunghe o font troppo piccolo
  • Soluzione: Aumenta fontsize sugli edge o usa \n per spezzare label su più righe

Template DOT + Comandi Graphviz (CLI)

Ogni template include:

  1. snippet DOT

  2. comando CLI per generare l’immagine

Per coerenza uso il formato SVG, ma puoi sostituire -Tsvg con:

  • -Tpng
  • -Tpdf
  • -Tjpg
  • -Tgif

E puoi salvare l’input DOT in template.dot oppure usare pipe.


Flowchart

Template 1 – Processo base

digraph FlowBasic {
    graph [rankdir=TB];
    node [shape=rectangle, style=rounded, fontsize=12];

    Start [label="Start", shape=circle];
    Step1 [label="Input validation"];
    Step2 [label="Process request"];
    Step3 [label="Persist data"];
    End [label="End", shape=doublecircle];

    Start -> Step1 -> Step2 -> Step3 -> End;
}

Command line:

dot -Tsvg FlowBasic.dot -o FlowBasic.svg

Template 2 – Branching (if/else)

digraph FlowIfElse {
    graph [rankdir=TB];
    node [fontsize=12, style=rounded];

    Start [shape=circle];
    Check [shape=diamond, label="Is valid?"];
    A [label="Handle valid case"];
    B [label="Handle error"];
    End [shape=doublecircle];

    Start -> Check;
    Check -> A [label="Yes"];
    Check -> B [label="No"];
    A -> End;
    B -> End;
}

Command line:

dot -Tsvg FlowIfElse.dot -o FlowIfElse.svg

Template 3 – Processo con sezioni

digraph FlowSections {
    graph [rankdir=TB];
    node [fontsize=11, style=rounded];

    subgraph cluster_input {
        label="Input Stage";
        color=lightgrey;
        style=filled;

        A1 [label="Receive request"];
        A2 [label="Validate payload"];
        A1 -> A2;
    }

    subgraph cluster_processing {
        label="Processing Stage";
        color=lightblue;
        style=filled;

        P1 [label="Transform data"];
        P2 [label="Apply business rules"];
        P1 -> P2;
    }

    subgraph cluster_output {
        label="Output Stage";
        color=lightyellow;
        style=filled;

        O1 [label="Persist"];
        O2 [label="Return response"];
        O1 -> O2;
    }

    A2 -> P1 -> O1;
}

Command line:

dot -Tsvg FlowSections.dot -o FlowSections.svg

State Machine

Template 4 – State machine base

digraph StateMachine {
    graph [rankdir=LR];
    node [shape=circle, fontsize=12];

    Idle;
    Loading;
    Error;
    Success;

    Idle -> Loading [label="start"];
    Loading -> Success [label="ok"];
    Loading -> Error [label="fail"];
    Error -> Idle [label="retry"];
}

Command line:

dot -Tsvg StateMachine.dot -o StateMachine.svg

Template 5 – Stati annidati

digraph NestedStates {
    graph [rankdir=LR];
    node [fontsize=11];

    subgraph cluster_ready {
        label="Ready state";
        style=dashed;
        R1 [shape=circle, label="Idle"];
        R2 [shape=circle, label="Primed"];
        R1 -> R2 [label="prepare"];
    }

    subgraph cluster_active {
        label="Active state";
        style=dashed;
        A1 [shape=circle, label="Running"];
        A2 [shape=circle, label="Paused"];
        A1 -> A2 [label="pause"];
        A2 -> A1 [label="resume"];
    }

    R2 -> A1 [label="activate"];
}

Command line:

dot -Tsvg NestedStates.dot -o NestedStates.svg

Sequence Diagram (DOT)

Template 6 – Sequence orizzontale

digraph Sequence {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    Client -> API [label="POST /login"];
    API -> AuthService [label="Check credentials"];
    AuthService -> DB [label="Query user"];
    DB -> AuthService [label="Result"];
    AuthService -> API [label="Token"];
    API -> Client [label="200 OK"];
}

Command line:

dot -Tsvg Sequence.dot -o Sequence.svg

Template 7 – Sequence con attivazioni

digraph SequenceActivation {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    User -> Frontend [label="Login"];
    Frontend -> Backend [label="POST /login"];
    Backend -> Backend [label="validate()"];
    Backend -> DB [label="SELECT user"];
    DB -> Backend [label="row found"];
    Backend -> Frontend [label="JWT"];
    Frontend -> User [label="Welcome"];
}

Command line:

dot -Tsvg SequenceActivation.dot -o SequenceActivation.svg

Dependency Graph

Template 8 – Moduli

digraph DependencyTree {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=12];

    App -> ModuleA;
    App -> ModuleB;
    ModuleA -> LibA;
    ModuleA -> LibB;
    ModuleB -> LibB;
}

Command line:

dot -Tsvg DependencyTree.dot -o DependencyTree.svg

Template 9 – Microservizi

digraph MicroservicesDep {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Gateway -> Auth;
    Gateway -> Orders;
    Auth -> UsersDB;
    Orders -> ProductsService;
    Orders -> Payments;
    Payments -> BankAPI;
}

Command line:

dot -Tsvg MicroservicesDep.dot -o MicroservicesDep.svg

Architecture Diagram

Template 10 – Layered

digraph Layered {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=12];

    subgraph cluster_presentation {
        label="Presentation Layer";
        style=filled;
        color=lightyellow;
        UI;
        API;
    }

    subgraph cluster_business {
        label="Business Layer";
        style=filled;
        color=lightblue;
        Services;
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        color=lightgrey;
        DB;
        Cache;
    }

    UI -> API -> Services -> DB;
    Services -> Cache;
}

Command line:

dot -Tsvg Layered.dot -o Layered.svg

Template 11 – Esagonale

digraph Hexagonal {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    AppCore [label="Core Domain"];
    PortIn [label="Inbound Ports"];
    PortOut [label="Outbound Ports"];
    AdapterIn [label="Inbound Adapters"];
    AdapterOut [label="Outbound Adapters"];
    DB [label="Database"];
    UI [label="Frontend/UI"];

    UI -> AdapterIn -> PortIn -> AppCore;
    AppCore -> PortOut -> AdapterOut -> DB;
}

Command line:

dot -Tsvg Hexagonal.dot -o Hexagonal.svg

ER Diagrams

Template 12 – 1:N

digraph ER_OneToMany {
    graph [rankdir=LR];
    node [shape=record, fontsize=11];

    User [label="{User|id PK|name|email}"];
    Order [label="{Order|id PK|user_id FK|total}"];

    User -> Order [label="1:N"];
}

Command line:

dot -Tsvg ER_OneToMany.dot -o ER_OneToMany.svg

Template 13 – N:N

digraph ER_ManyToMany {
    graph [rankdir=LR];
    node [shape=record, fontsize=11];

    Student [label="{Student|id PK|name}"];
    Course [label="{Course|id PK|title}"];
    Enroll [label="{Enroll|student_id FK|course_id FK}"];

    Student -> Enroll;
    Course -> Enroll;
}

Command line:

dot -Tsvg ER_ManyToMany.dot -o ER_ManyToMany.svg

Call Graph

Template 14 – Base

digraph CallGraph {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=11];

    main -> init;
    main -> loadConfig;
    loadConfig -> readFile;
    readFile -> parseJson;
}

Command line:

dot -Tsvg CallGraph.dot -o CallGraph.svg

Template 15 – Con categorie

digraph CategorizedCalls {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=11];

    subgraph cluster_io {
        label="I/O Functions";
        color=lightgrey;
        readFile;
        writeFile;
    }

    subgraph cluster_logic {
        label="Business Logic";
        color=lightblue;
        compute;
        validate;
    }

    main -> compute -> validate;
    compute -> readFile;
    validate -> writeFile;
}

Command line:

dot -Tsvg CategorizedCalls.dot -o CategorizedCalls.svg

Network Diagram

Template 16 – Base

digraph Network {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Client -> LoadBalancer;
    LoadBalancer -> AppServer1;
    LoadBalancer -> AppServer2;
    AppServer1 -> DB;
    AppServer2 -> DB;
}

Command line:

dot -Tsvg Network.dot -o Network.svg

Template 17 – Con protocolli

digraph NetworkProto {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    Client -> API [label="HTTPS"];
    API -> Auth [label="gRPC"];
    API -> Orders [label="REST"];
    Orders -> DB [label="TCP"];
}

Command line:

dot -Tsvg NetworkProto.dot -o NetworkProto.svg

Timeline / Roadmap

Template 18 – Timeline

digraph Timeline {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Start -> Milestone1 -> Milestone2 -> Milestone3 -> Release;
}

Command line:

dot -Tsvg Timeline.dot -o Timeline.svg

Template 19 – Roadmap

digraph Roadmap {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    subgraph cluster_backend {
        label="Backend";
        B1 [label="Auth module"];
        B2 [label="Payments"];
    }

    subgraph cluster_frontend {
        label="Frontend";
        F1 [label="Login UI"];
        F2 [label="Dashboard"];
    }

    B1 -> B2;
    F1 -> F2;
}

Command line:

dot -Tsvg Roadmap.dot -o Roadmap.svg

Mind Map

Template 20 – Mind map

graph MindMap {
    layout=twopi;
    rankdir=LR;
    node [shape=box, style=rounded, fontsize=11];

    Central -- Idea1;
    Central -- Idea2;
    Central -- Idea3;
    Idea2 -- Sub1;
    Idea2 -- Sub2;
}

Command line:

dot -Ktwopi -Tsvg MindMap.dot -o MindMap.svg

Component Diagram

Template 21 – Components

digraph Components {
    graph [rankdir=LR];
    node [shape=component, fontsize=11];

    UI -> API;
    API -> Service;
    Service -> DB;
}

Command line:

dot -Tsvg Components.dot -o Components.svg

Class Diagram

Template 22 – UML class-like

digraph Classes {
    graph [rankdir=TB];
    node [shape=record, fontsize=11];

    Person [label="{Person|name:string|age:int}"];
    Student [label="{Student|grade:int}"];
    Person -> Student;
}

Command line:

dot -Tsvg Classes.dot -o Classes.svg

Layouts

Template 23 – Orizzontale

digraph Horizontal {
    graph [rankdir=LR];
    node [shape=box, style=rounded];
}

Command line:

dot -Tsvg Horizontal.dot -o Horizontal.svg

Template 24 – Verticale

digraph Vertical {
    graph [rankdir=TB];
    node [shape=box, style=rounded];
}

Command line:

dot -Tsvg Vertical.dot -o Vertical.svg

Template 25 – Circolare

graph Circular {
    layout=circo;
    node [shape=box, style=rounded];
}

Command line:

dot -Kcirco -Tsvg Circular.dot -o Circular.svg

Stili professionali

Template 26 – Modern theme

digraph Modern {
    graph [rankdir=LR];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#eef3f8",
        color="#6a8bbf",
        fontsize=11
    ];
    edge [color="#6a8bbf"];

    A -> B -> C;
}

Command line:

dot -Tsvg Modern.dot -o Modern.svg

Template 27 – Tema Scuro

digraph Dark {
    bgcolor="#1e1e1e";
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#333333",
        fontcolor="white",
        color="#777777",
        fontsize=11
    ];
    edge [color="#999999"];

    A -> B -> C;
}

Command line:

dot -Tsvg Dark.dot -o Dark.svg


Risorse utili

Documentazione ufficiale

Strumenti online

Integrazioni e librerie

  • Graphviz Visual Editor (VSCode): Estensione per preview live in Visual Studio Code
  • PlantUML: plantuml.com — Usa Graphviz per rendering di UML
  • Mermaid: mermaid.js.org — Alternativa JavaScript-based a Graphviz per grafici in Markdown
  • Python graphviz: graphviz.readthedocs.io — Libreria Python per generare grafi programmaticamente
  • Go graphviz: github.com/goccy/go-graphviz — Binding Go per Graphviz

Gallery ed esempi

Community e supporto

Tool complementari


Articolo scritto da Daniele Teti — danieleteti.it

Comments

comments powered by Disqus