Diagramma di rete come codice

Negli ultimi anni mi sono dedicato di più alla documentazione. Scrivere un testo esplicativo su come funziona un sistema è generalmente abbastanza semplice. Anche disegnare un diagramma che rappresenti tutti gli oggetti chiave e le connessioni tra di essi è piuttosto facile.

Ma il problema principale è mantenere questa documentazione aggiornata. E va bene per il testo, ma i diagrammi... Poiché tutta la documentazione è online, quindi in formato HTML, le immagini gif/jpg/png sono allegate al testo, che mostrano effettivamente i diagrammi. I diagrammi vengono realizzati in diversi programmi come Visio o servizi online come draw.io. Poi esporti il diagramma in un formato grafico e lo alleghi all'HTML. È tutto abbastanza semplice.

Qual è il problema?

Gli schemi sono generalmente semplici. Più precisamente, non molto complicati. Sì, il numero di oggetti è una dozzina o due, il numero di collegamenti è più o meno lo stesso. Aggiungiamo delle etichette, alcune notazioni. Schemi semplici possono essere descritti anche a parole, mentre quelli troppo complessi, ehm… (s) «non saranno compresi». Ci sono molti schemi, e i cambiamenti devono essere apportati periodicamente, cioè costantemente, poiché seguono lo sviluppo dei nostri prodotti.

È possibile incorporare HTML nei servizi. Hai provato?

Sì, certo. A me piacciono, per esempio, i grafici di gliffy.com. Ma per apportare modifiche bisogna andare su un servizio esterno, modificare lì. E risulta più difficile delegare la correzione a un collega.

Cosa fare?

Di recente, su GitHub, mi è capitato tra le raccomandazioni un repository github.com/RaoulMeyer/diagram-as-code. Diagramma come codice. Cioè, descriviamo in JS lo schema di cui abbiamo bisogno. Questo JS lo scriviamo direttamente nello stesso HTML in cui si trova il resto del testo della documentazione.

A proposito, ma io non scrivo la documentazione interamente in HTML. Di solito, la documentazione è un insieme di file con testo Markdown, che poi viene convertito in un sito completo di documentazione tramite qualche motore, ad esempio Wintersmith. O una wiki.

È molto comodo: abbiamo scritto il testo, poi si apre il tag script e all'interno c'è il codice JavaScript dello schema.

Cosa non va di nuovo?

Questo repository mi è piaciuto, ma non è l'unico esempio di quando una diagramma viene disegnata tramite codice o rappresentazione testuale. (Alla fine dell'articolo ci saranno link a progetti e articoli che ho trovato riguardo al tema diagram as code.)

E non sono l'unico a modificare la documentazione. A volte anche i colleghi contribuiscono — correggendo parole, modificando descrizioni, inserendo nuove immagini. 

Perciò mi piacerebbe vedere la diagramma in un formato testuale leggibile e comprensibile, che non richieda lungo apprendimento. E in alcuni casi sarebbe anche utile fare semplicemente copy-paste per velocizzare l'aggiunta di un nuovo schema. 

Un altro collega ha notato che il codice va bene, ma se si usa una struttura, tutto può essere molto rigoroso ed espressivo.

Quindi ho provato a rappresentare lo schema come un insieme di piccoli array che descrivono nodi, connessioni, gruppi di nodi e la disposizione dei nodi. A mio modesto parere, è piuttosto comodo, anche se, naturalmente, ognuno ha i propri gusti...

Come può essere una diagramma in un array?

  • Ogni nodo è descritto da un identificatore che lo definisce in modo univoco.
  • È possibile aggiungere un'icona e un'etichetta al nodo.
  • Tra due nodi si può indicare una connessione.
  • Per la connessione nello schema si può specificare colore ed etichetta.
  • La direzione della connessione è definita dall'origine alla destinazione. L'origine e la destinazione sono indicate dagli identificatori del nodo.
  • Uno o più nodi possono essere aggiunti a un gruppo.
  • La connessione può essere specificata sia dal gruppo che verso il gruppo.

Utilizzando queste semplici regole, si ottiene uno schema come questo. Facile? Assolutamente.

Diagramma di rete come codice

È descritto dal seguente codice js. La parte principale è l'oggetto elements. In cui sono specificati nodes — nodi, edges — connessioni.
 

  const elements = {
    nodes: [       // descriviamo i nodi
      { id: 'client', type: 'smartphone', label: 'Mobile App'},
      { id: 'server', type: 'server', label: 'Main Server'},
      { id: 'db1', type: 'database', label: 'DB 1'},
      { id: 'db2', type: 'database', label: 'DB 2'},
    ],
    edges: [       // specifichiamo le connessioni
      { source: 'client', target: 'server', label: 'request' },
      { source: 'server', target: 'db1', label: 'request' },
      { source: 'server', target: 'db2', label: 'request' },
    ],
  };
  Diagram('scheme1', elements);

Certo, non ho inventato io il rendering dello schema, ma ho utilizzato una libreria. cytoscape.js — uno strumento di visualizzazione molto potente. Alcune delle sue funzionalità vengono utilizzate solo nel mio progetto. 

Capisco, questo è un esempio semplice. Possiamo fare qualcosa di più complesso?

Sì, certo. Per indicare le posizioni — utilizziamo positions, per indicare i gruppi — forniamo un elenco di gruppi in groups, e gli attributi group per gli elementi stessi.

Diagramma di rete come codice

Ecco il codice:

<div id="scheme5" style="height:500px;width:800px;"></div>
<script>
  const elements5 = {
    groups: [
      { id: 'g1', label: 'Группа сервисов 1'},
      { id: 'g2', label: 'Группа сервисов 2'},
    ],
    nodes: [
      { id: 'man1', type: 'person', label: 'Человек'},
      { id: 'client', type: 'smartphone', label: 'Смартфон'},
      { id: 'agent-backend', type: 'server', group: 'g1', label: 'agent-backend'},
      { id: 'web', type: 'server', group: 'g1', label: 'Приложение admin'},
      { id: 'www', type: 'server', group: 'g1', label: 'страница загрузки'},
      { id: 'mongodb1', type: 'database', group: 'g1', label: 'Mongo DB 1'},
      { id: 'mongodb2', type: 'database', group: 'g1', label: 'Mongo DB 2'},
      { id: 'runner-integration1', type: 'worker', group: 'g1', label: 'отправка'},
      { id: 'runner-integration2', type: 'worker', group: 'g1', label: 'отправка'},
      { id: 'api', type: 'server', group: 'g1', label: 'API'},
      { id: 'server2', type: 'server', group:'g2', label: 'сервер'},
      { id: 'otherServer', type: 'server', group:'g2', label: 'сервер'},
      { id: 'firebase', type: 'cloud', label: 'Google Firebase'},
    ],
    edges: [
      { source: 'client', target: 'agent-backend', label: 'json', color: 'red' },
      { source: 'agent-backend', target: 'mongodb1', color: 'red' },
      { source: 'agent-backend', target: 'mongodb2',  color: 'red' },
      { source: 'mongodb1', target: 'runner-integration1', label: 'данные' },
      { source: 'mongodb2', target: 'runner-integration2', label: 'данные' },
      { source: 'mongodb1', target: 'web', label: 'данные для отображения' },
      { source: 'runner-integration1', target: 'server2', label: 'данные' },
      { source: 'runner-integration2', target: 'otherServer', label: 'данные' },
      { source: 'api', target: 'firebase', label: 'запросы', color: 'blue', },
      { source: 'firebase', target: 'client', label: 'push', color: 'blue'},
      { source: 'server2', target: 'api', label: 'уведомления', color: 'blue'},
      { source: 'man1', target: 'client', },
    ],
    positions: [
      { id: 'client', row: 2, col: 1,},
      { id: 'agent-backend', row: 2, col: 3,},
      { id: 'web', row: 6, col: 3,},
      { id: 'www', row: 1, col: 3,},
      { id: 'mongodb1', row: 1, col: 4,},
      { id: 'mongodb2', row: 2, col: 5,},
      { id: 'runner-integration1', row: 3, col: 3,},
      { id: 'runner-integration2', row: 4, col: 3,},
      { id: 'api', row: 5, col: 3,},
      { id: 'server2', row: 6, col: 7,},
      { id: 'otherServer', row: 4, col: 7,},
      { id: 'firebase', row: 5, col: 1,},
      { id: 'logger', row: 2, col: 7,},
      { id: 'crm', row: 5, col: 8,},
    ],
};
  Diagram('scheme5', elements5, {layout: 'grid'});
</script>

Questo schema è, da un lato, quasi come due schermi di codice su un portatile, dall'altro, una struttura simile a json permette di riempire tutti i dati per analogia, in modo veloce e con la possibilità di copia e incolla.

Perché positions sono separati dai nodi?

È più comodo. Prima indichiamo i nodes. Poi possiamo specificare un paio di gruppi e indicarli nei nodi. Successivamente, definiamo le relazioni. Solo dopo aver stabilito gli oggetti principali e le relazioni tra di essi, ci occupiamo della disposizione di questi oggetti nello schema. O viceversa.

E se volessimo farne a meno di positions?

È possibile anche senza positions. Ma risulterebbe un po' confuso; negli esempi puoi vedere un'opzione del genere. Questo è dovuto al fatto che per cytoscape esiste un algoritmo per la disposizione dei nodi. fcose, che tiene anche conto della presenza di gruppi. Specificare positions rende lo schema più controllabile, ma nella fase di primo abbozzo dello schema si può anche procedere senza positions.

Puoi anche specificare le posizioni in stile Battaglia Navale. Cioè, un nodo si trova in a1 e un altro in d5. È particolarmente utile che Cytoscape posizioni gli oggetti su un canvas in modo mobile, quindi possiamo spostarli, vedere diverse configurazioni e poi fissare nel codice la disposizione che ci piace.

In generale, è chiaro. Possiamo provare?
 
Certo, per creare rapidamente schemi ho realizzato un piccolo editor, che aggiorna automaticamente lo schema e salva l'ultima versione nel browser (in localStorage).

Hai provato? Ora puoi aggiungerlo anche alla tua pagina.

Allora, ancora una volta:

1. Colleghiamo lo script

<script src="https://unpkg.com/@antirek/network-diagram@0.1.4/dist/code-full.min.js"></script>

2. Aggiungiamo al codice html

<div id="scheme1" style="height:300px;width:800px;"></div>
<script>      
  const elements = {    
    nodes: [
      { id: 'client', type: 'smartphone', label: 'Mobile App'},
      { id: 'server', type: 'server', label: 'Main Server'},
      { id: 'db1', type: 'database', label: 'DB 1'},
      { id: 'db2', type: 'database', label: 'DB 2'},
    ],
    edges: [
      { source: 'client', target: 'server', label: 'request' },
      { source: 'server', target: 'db1', label: 'request' },
      { source: 'server', target: 'db2', label: 'request' },
    ],
  };
  Diagram('scheme1', elements);
</script>

3. modifichiamo il codice secondo lo schema desiderato (credo sia più semplice che disegnare un gufo 🙂

Ulteriori dettagli su pagina del progetto su GitHub.

Quali sono i risultati finali?

Ho raggiunto i miei obiettivi: inserire schemi inline nella documentazione, un formato abbastanza semplice e chiaro. Non è adatto per schemi complessi, ma per piccoli schemi che spiegano la struttura delle relazioni è molto utile. Si può sempre modificare rapidamente e cambiare qualcosa nel tempo. Inoltre, i colleghi possono anche apportare modifiche nel documento, almeno le didascalie degli oggetti senza bisogno di una formazione particolare. ))

Cosa si può migliorare?

Ci sono molte opzioni, ovviamente. Potremmo aggiungere ulteriori icone (tutte quelle disponibili sono già state aggiunte inline nello script). Scegliere un set di icone più espressivo. Implementare la possibilità di specificare lo stile delle linee di collegamento. Aggiungere un'immagine di sfondo.

E voi che ne pensate?
 
Ho già alcune idee per l'implementazione nei problemi , aggiungete anche le vostre nei commenti.

La mia soluzione è sicuramente applicabile in un ambito ristretta di attività, e probabilmente troverete uno strumento più conveniente per disegnare diagrammi, semplicemente codificandoli — come si suol dire 'show me your diagram as code'

  1. Ottima selezione
  2. Servizio eccezionale (9 tipi di grafici nell'editor online)
  3. Конечно, mermaid.js
  4. E se amate schemi super dettagliati e complessi, questo progetto vi stupirà sicuramente: go.drawthe.net

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster