Diagrama de red como código

En los últimos años, he estado dedicando más tiempo a la documentación. Escribir un texto explicativo sobre cómo funciona un sistema u otro — en general, es bastante sencillo. Dibujar un esquema que muestre todos los objetos clave, las relaciones entre ellos también es bastante fácil.

Pero el problema más grande es mantener esta documentación actualizada. Y no solo el texto, sino también los esquemas… Dado que toda la documentación está en línea, es decir, en formato html, se incluyen imágenes gif/jpeg/png que muestran los esquemas. Y los esquemas se dibujan en varios programas como Visio o servicios en línea como draw.io. Luego exportas el esquema a un formato gráfico y lo adjuntas al html. Todo es simple.

¿Cuál es el problema?

Los esquemas suelen ser sencillos. Más bien, no son muy complejos. Sí, el número de objetos es de una docena o dos, y el número de relaciones es aproximadamente el mismo. Además, hay etiquetas y algunas designaciones. Se pueden describir esquemas simples con palabras, pero los demasiado complejos, eh… (c) 'no serán entendidos'. Hay muchos esquemas, y es necesario realizar cambios en ellos periódicamente, es decir, constantemente, ya que siguen el desarrollo de nuestros productos.

¿Se pueden integrar html de servicios? ¿Lo has probado?

Sí, claro. A mí, por ejemplo, me gustan los gráficos de gliffy.com. Pero para realizar cambios, hay que ir a un servicio externo y editarlos. Y es más complicado delegar a un colega para hacer correcciones.

¿Qué hacer?

Recientemente, me encontré en GitHub con un repositorio que me recomendaron. github.com/RaoulMeyer/diagram-as-code. Diagrama como código. Es decir, describimos el esquema que necesitamos en js. Este js lo escribimos directamente en el mismo html donde se encuentra el resto del texto de la documentación.

Dicho sea de paso, no escribo la documentación completamente en html. Generalmente, la documentación es un conjunto de archivos con texto en markdown, que luego se convierte en un sitio web completo de documentación mediante algún motor, como wintersmith. O un sistema wiki.

Es muy conveniente: hemos escrito el texto, luego se abre la etiqueta script y en ella se describe el código js del esquema.

¿Qué está mal esta vez?

Me gustó este repositorio, pero no es el único ejemplo donde se dibuja un diagrama usando código o una representación textual. (Al final del artículo habrá enlaces a proyectos y artículos que encontré sobre el tema diagram as code.)

Y no soy el único que edita la documentación. A veces, mis colegas también aportan: corrigen palabras, cambian descripciones, insertan nuevas imágenes. 

Por lo tanto, me gustaría ver el diagrama en un formato de texto legible y comprensible, que no requiera mucho tiempo de aprendizaje. A veces, incluso se podría hacer simplemente un copy-paste para agilizar la adición de un nuevo esquema. 

Además, un colega notó que el código está bien, pero si se utiliza una estructura, todo puede ser muy riguroso y expresivo.

Por eso intenté representar el esquema como un conjunto de varios arrays pequeños que describen los nodos, las conexiones, los grupos de nodos y la disposición de los nodos. Desde mi humilde perspectiva, resultó bastante cómodo, aunque, por supuesto, sobre gustos y colores...

¿Cómo es ese diagrama en un array?

  • Cada nodo se describe con un identificador que lo define de manera única.
  • También se puede agregar un ícono al nodo, añadir una etiqueta.
  • Entre dos nodos puede indicarse una conexión.
  • Para la conexión en el esquema se puede asignar un color, una etiqueta.
  • La dirección de la conexión se determina desde la fuente hacia el objetivo. Y la fuente y el objetivo se especifican con los identificadores de los nodos.
  • Se puede añadir uno o más nodos a un grupo.
  • La conexión también se puede especificar desde un grupo hacia otro grupo.

Siguiendo estas reglas simples se obtiene un esquema como este. ¿Sencillo? Definitivamente.

Diagrama de red como código

Y se describe con el siguiente código js. Lo principal aquí es el objeto elements. En el que se especifican los nodes — nodos, edges — conexiones.
 

  const elements = {
    nodes: [       // describimos nodos
      { id: 'client', type: 'smartphone', label: 'Aplicación móvil'},
      { id: 'server', type: 'server', label: 'Servidor principal'},
      { id: 'db1', type: 'database', label: 'DB 1'},
      { id: 'db2', type: 'database', label: 'DB 2'},
    ],
    edges: [       // indicamos conexiones
      { source: 'client', target: 'server', label: 'solicitud' },
      { source: 'server', target: 'db1', label: 'solicitud' },
      { source: 'server', target: 'db2', label: 'solicitud' },
    ],
  };
  Diagram('scheme1', elements);

Por supuesto, no inventé la representación del esquema, sino que utilicé una biblioteca. cytoscape.js — una herramienta de visualización muy poderosa. Solo utilizo una fracción de sus capacidades en mi solución. 

Entiendo, este es un ejemplo simple. ¿Se puede hacer algo más complicado?

Sí, por favor. Para especificar posiciones, usamos positions, para indicar grupos, listamos los grupos en groups, y para los propios elementos, el atributo group.

Diagrama de red como código

Y este es el código:

<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>

Tal esquema, por un lado, es casi un par de pantallas de código en un portátil, y por otro lado, la estructura estilo json permite llenar todos los datos por analogía, de manera rápida y se puede hacer copy-paste.

¿Y por qué positions se destaca separadamente de los nodos?

Es más conveniente. Primero indicamos los nodos. Luego podemos especificar un par o tres grupos y señalarlos en los nodos. Después marcamos las conexiones. Y ya luego, cuando tengamos los objetos principales y las relaciones entre ellos, nos ocupamos de la disposición de estos objetos en el esquema. O viceversa.

¿Se puede hacer sin posiciones?

Se puede hacer sin posiciones. Pero será un poco apresurado, en los ejemplos se puede ver una variante así. Esto se debe a que para cytoscape hay un algoritmo para la disposición de los nodos fcose, que también tiene en cuenta la presencia de grupos. Indicar posiciones hace que el esquema sea más controlable, pero en la etapa del primer boceto del esquema se puede prescindir de las posiciones.

También se pueden indicar posiciones al estilo de Batalla Naval. Es decir, un nodo se coloca en a1, y otro en d5. Es especialmente útil que cytoscape crea objetos en el canvas que son movibles, es decir, podemos moverlos, ver diferentes opciones de disposición, y luego fijar en el código la disposición que nos agrada.

En general, está claro. ¿Podemos intentarlo?
 
Por supuesto, para crear esquemas rápidamente hice un pequeño se puede encontrar en el repositorio del proyecto en GitHub., que actualiza el esquema por sí mismo y guarda la última variante en el navegador (en localStorage).

¿Lo han probado? Ahora se puede añadir también a su página.

Entonces, una vez más:

1. Conectamos el script

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

2. Añadimos al código 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. ajustamos el código a nuestro esquema deseado (creo que es más fácil que dibujar un búho 🙂

Más detalles en la página del proyecto en GitHub.

¿Cuál es el resultado?

He alcanzado mis objetivos: hacer que la adición de esquemas en línea a la documentación sea bastante simple y comprensible. No es adecuado para superesquemas, pero para esquemas pequeños que explican la estructura de relaciones, está muy bien. Siempre se puede ajustar rápidamente y cambiar algo con el tiempo. Además, los colegas pueden corregir algo en la doc sin mucha formación, como mínimo las etiquetas de los objetos :)

¿Qué se puede mejorar?

Aquí hay muchas opciones, por supuesto. Hacer la adición de íconos adicionales (todos los existentes se han agregado en línea en el script). Seleccionar un conjunto de íconos más expresivo. Hacer posible indicar el estilo de las líneas de conexión. Añadir una imagen de fondo.

¿Y qué piensan ustedes?
 
Ya tengo algunas ideas para implementar en los problemas, también pueden agregar las suyas en los comentarios.

Mi solución definitivamente es aplicable en un espectro limitado de tareas, y posiblemente encuentres una herramienta más conveniente para dibujar diagramas, simplemente codificándolos — como se dice, ‘muéstrame tu diagrama como código’

  1. Buena selección
  2. Un servicio excelente (9 tipos de gráficos en el editor en línea)
  3. Конечно, mermaid.js
  4. Y si te gustan los esquemas súper detallados y complejos, este proyecto definitivamente te impresionará: go.drawthe.net

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster