Network diagram as code

In the last couple of years I have become more involved in documentation. Writing an explanatory text about how a particular system works is generally quite simple. It is also quite easy to draw a diagram that will display all the key objects, the connections between these objects.

But the most problematic moment is to keep this documentation up to date. And the text would be fine, but the schemes ... all documentation online, i.e. in html format, then gif/jpeg/png pictures are attached to the text, which actually show the diagrams. And diagrams are drawn in various programs like Visio or online services a la draw.io. Then you export the diagram to a graphical format and attach it to html. Everything is simple.

What's the problem?

The schemes are usually simple. More precisely, not very complicated. Yes, the number of objects is a dozen or two, the number of connections is about the same. Plus signatures, some designations. Simple schemes can be described in words, but too complex ones, hmm ... (c) "they won't understand, sir." There are many schemes, changes to them need to be made periodically-episodic, i.e. constantly, because they follow the development of our products.

You can also embed the html service. Tried?

Yes, sure. I like gliffy.com charts, for example. But for changes, you need to go to a third-party service, edit there. And it is more difficult to delegate to make amendments to a colleague.

What to do?

Recently on github I came across a repository in the recommendations github.com/RaoulMeyer/diagram-as-code. Diagram as code. Those. we describe the scheme we need in js. We write this js directly in the same html as the rest of the documentation text.

By the way, but I write documentation not quite in html. Documentation is usually a set of files with markdown text, which is then converted into a full-fledged documentation site by some engine, such as wintersmith. Or a wiki system.

It turns out very convenient: here we wrote the text, then the script tag opens and the schema js code is described in it.

What's wrong again?

I liked this repository, but this is not the only example where a diagram is drawn using code or text representation. (At the end of the article there will be links to projects and articles that I googled on the topic diagram as code.)

And I'm not the only one editing the documentation. Sometimes colleagues also contribute - to correct the word, change the description, insert new pictures. 

Therefore, I would like to see the diagram in a readable, understandable text format, which would not take a long time to learn. And sometimes even just copy-paste to speed up the addition of a new scheme. 

And another colleague noted that the code is, of course, good, but if you use the structure, everything can be very strict and expressive.

So I tried to represent the diagram as a set of several small arrays that describe nodes, links, groups of nodes, as well as the location of nodes. It turned out, in my humble opinion, quite convenient, although, of course, the taste and color ...

How is it a chart in an array?

  • Each node is described by an identifier that uniquely identifies the node.
  • You can also add an icon to the node, add an inscription.
  • You can specify a relationship between two nodes.
  • For communication on the diagram, you can set the color, the inscription.
  • The direction of the link is defined as from the source to the target. And the source and target are specified by node identifiers.
  • One or more nodes can be added to a group.
  • The relationship can also be specified both from the group and to the group.

Using these simple rules, we get the following scheme. Just? Quite.

Network diagram as code

And it is described by the following js code. The main thing here is the elements object. In which nodes are specified - nodes, edges - connections.
 

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

Of course, I did not come up with the drawing of the circuit myself, but used the library cytoscape.js is a very powerful visualization tool. I use only a fraction of the possibilities of which in my decision. 

Obviously, this is a simple example. Can it be more difficult?

Yes please. To specify positions, we use positions, to specify groups, we specify a list of groups in groups, and the elements themselves have the group attribute.

Network diagram as code

And this is the code:

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

On the one hand, such a scheme is almost a couple of screens of code on a laptop, on the other hand, a json structure allows you to fill in all the data by analogy, quickly and you can copy-paste.

And why positions are taken out separately from nodes?

It is more comfortable. First we specify nodes. Then we can specify a couple of groups and specify them in the nodes. Then we define connections. And only then, when the main objects and the connections between them are, we take up the location of these objects on the diagram. Or vice versa.

Is it possible without positions?

It is possible without positions. But it will be a little crumpled, in the examples you can see this option. This is due to the fact that for cytoscape there is an algorithm for the location of nodes fcose, which also takes into account the presence of groups. Specifying positions makes the schema more controllable, but at the stage of the first sketch of the schema, it is possible without positions.

Also, positions can be specified in the Naval battle style. Those. one node is located at a1 and the other at d5. It is especially helpful that cytoscape renders the objects on the canvas movable, i.e. we can move them around, look at different layout options, and then fix the layout of the elements we like in the code.

In general, it's understandable. You can also try?
 
Of course, to quickly create circuits, I made myself a small editor, which updates the schema itself and stores the latest version in the browser (in localStorage).

Have you tried? You can now add to your page.

Then again:

1. We connect the script

<script src="https://unpkg.com/@antirek/[email protected]/dist/code-full.min.js"></script>

2. Adding code to 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. we edit the code to the scheme we need (I think it's easier than drawing an owl πŸ™‚

More details at project page on github.

The result?

I achieved my goals - to add inline schemas to the documentation, the format is quite simple and understandable. Not suitable for super-schemes, but for small schemes that explain the structure of connections - very much even nothing. You can always quickly correct and change something over time. Yes, and colleagues can correct something in the dock themselves, at least the signatures for objects without much training ))

What can be improved?

There are plenty of options, of course. Make adding additional icons (all existing ones are added inline to the script). Choose a more expressive set of icons. Make it possible to specify the style of the link line. Add a background image.

What do you think?
 
I already have several ideas for implementation in issues, you can also add yours in the comments.

My solution is definitely applicable in a narrow range of tasks, and perhaps you will find a more convenient tool for drawing diagrams by simply coding them - as they say 'show me your diagram as code'

  1. Good selection
  2. Great service (9 types of charts online editor)
  3. Of course mermaid.js
  4. And if you like super detailed and complex schemes, then this project will definitely delight you: go.drawthe.net

Source: habr.com

Add a comment