- PVSM.RU - https://www.pvsm.ru -

Network diagram as code – Схема сети как код

В последние пару лет стал больше заниматься документацией. Написать поясняющий текст о том, как работает та или иная система — в целом, это достаточно просто. Нарисовать схему, на которой будут отображены все ключевые объекты, связи между этими объектами, тоже вполне легко.

Но самый проблемный момент — это поддерживать эту документацию в актуальном состоянии. И ладно бы текст, но схемы… Т.к. вся документация онлайн, т.е. в формате html, то к тексту прилагаются картинки gif/jpeg/png, на которых собственно изображены схемы. А схемы рисуются в различных программах типа Visio или онлайн-сервисах а-ля draw.io. Затем экспортируешь схему в графический формат и прилагаешь к html. Все просто.

В чем проблема?

Схемы обычно простые. Точнее, не сильно сложные. Да, количество объектов десяток-два, количество связей примерно столько же. Плюс подписи, какие-то обозначения. Простые схемы и на словах описать можно, а слишком сложные, кх-м… (с) «не поймут-с». Схем много, изменения в них нужно вносить периодически-эпизодически, т.е. постоянно, т.к. они идут вслед за разработкой наших продуктов.

Можно же встраивать html сервиса. Пробовал?

Да, конечно. Мне, например, нравятся графики gliffy.com. Но для изменений надо идти в сторонний сервис, там править. И сложнее делегировать сделать поправки коллеге.

Что делать?

Недавно на гитхабе мне попался в рекомендациях репозиторий github.com/RaoulMeyer/diagram-as-code [1]. Диаграмма как код. Т.е. мы описываем на js нужную нам схему. Этот js мы пишем прямо в том же html, где и прочий текст документации.

К слову сказать, но я пишу документацию не совсем в html. Обычно документация — это набор файлов с markdown-текстом, который затем конвертируется в полноценный сайт документации каким-нибудь движком, например wintersmith. Или wiki-система.

Получается очень удобно: вот мы написали текст, затем открывается тег script и в нем описан js код схемы.

Что опять не так?

Этот репозиторий мне понравился, но это не единственный пример когда диаграмму рисуют с помощью кода или текстового представления. (В конце статьи будут ссылки проектов и статей, которые нагуглил по теме diagram as code.)

И ведь я не один правлю документацию. Иногда свою лепту вносят и коллеги — слово поправить, описание изменить, новые картинки вставить. 

Поэтому хотелось бы диаграмму видеть в читаемом понятном текстовом формате, которому бы не пришлось долго обучаться. А местами даже просто copy-paste сделать для ускорения добавления новой схемы. 

А еще один коллега заметил, что код это, конечно, хорошо, но если использовать структуру, все может быть очень строго и выразительно.

Поэтому я попробовал представить схему как набор нескольких небольших массивов, которые описывают узлы, связи, группы узлов, а также расположение узлов. Получилось на мой скромный взгляд достаточно удобно, хотя, конечно, на вкус и цвет…

Как это диаграмма в массиве?

Каждый узел описывается идентификатором, который однозначно определяет узел. Также к узлу можно добавить иконку, добавить надпись. Между двумя узлами можно указать связь. Для связи на схеме можно задать цвет, надпись. Направление связи определяется как от источника к цели. А источник и цель указываются идентификаторами узла. Один и более узлов можно добавить в группу. Связь также можно указать и от группы, и к группе.

Пользуясь этими простыми правилами получается вот такая схема. Просто? Вполне.

Network diagram as code - Схема сети как код - 1

А описывается она следующим js-кодом. Основное здесь — это объект elements. В котором указаны nodes — узлы, edges — связи.
 

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

Конечно, отрисовку схемы я придумал не сам, а воспользовался библиотекой cytoscape.js [2] — очень мощный инструмент визуализации. Толику возможностей которой в своем решении использую лишь. 

Понятно, это простой пример. Можно посложнее?

Да, пожалуйста. Для указания позиций — мы используем positions, для указания групп — указываем список групп в groups, а у самих элементов атрибут group.

Network diagram as code - Схема сети как код - 2

А это код:

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

Такая схема с одной стороны — это почти пара экранов кода на ноуте, с другой структура а-ля json позволяет заполнять все данные по аналогии.

А почему positions вынесены отдельно от узлов?

Так удобнее. Сначала мы указываем nodes. Затем можем указать пару-тройку групп и указать их в узлах. Затем обозначаем связи. А уж затем, когда основные объекты и связи между ними есть, беремся за расположение этих объектов на схеме. Или наоборот.

А можно без positions?

Можно и без positions. Но это будет немного скомкано, в примерах можно посмотреть такой вариант. Это обусловлено тем, что для cytoscape есть алгоритм расположения узлов fcose [3], который также учитывает наличие групп. Указание positions делает схему более контролируемой, но на стадии первого наброска схемы можно и без positions.

Также positions можно указывать в стиле Морского боя. Т.е. один узел располагается в a1, а другой в d5. Особенно помогает, что cytoscape формирует объекты на canvas подвижными, т.е. мы можем их подвигать, посмотреть разные варианты расположения, а затем зафиксировать в коде понравившееся расположение элементов.

В целом, понятно. Можно попробовать?
 
Конечно, для быстрого создания схем сделал себе небольшой редактор [4], который сам обновляет схему и в браузере хранит последний вариант (в localStorage).

Попробовали? Можно теперь и к себе на страницу добавить.

Тогда еще раз:

1. Подключаем скрипт

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

2. Добавляем в 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. правим код до нужной нам схемы (думаю, это проще чем нарисовать сову :)

Еще подробнее на странице проекта [5] на гитхабе.

Что в итоге?

Своих целей я достиг — сделать добавление схем inline в документацию, формат достаточно простой и понятный. Для суперсхем не подойдет, а для небольших схем, поясняющих структуру связей — очень даже ничего. Всегда можно быстро подправить и что-то с течением времени поменять. Да, и коллеги могут в доке сами что-то подправить, как минимум подписи к объектам без особого обучения ))

Что можно улучшить?

Тут вариантов, конечно, масса. Сделать добавление дополнительных иконок (все имеющиеся добавлены inline в скрипт). Подобрать более выразительный набор иконок. Сделать возможность указания стиля линии связей. Добавить фоновое изображение.

А что думаете вы?
 
У меня уже есть несколько идей на реализацию в issues, вы также добавьте свои в комментарии.

Мое решение определенно применимо в узком спектре задач, и возможно вы найдете более удобный инструмент для рисования диаграмм, просто закодировав их — как говорится 'show me your diagram as code'

  1. Хорошая подборка [8]
  2. Шикарный сервис [9] (9 типов графиков онлайн-редактор)
  3. Конечно, mermaid.js [10]
  4. И если вам любы супер детальные и сложные схемы — то вас определенно восхитит этот проект: go.drawthe.net [11]

Автор: Дмитриев Сергей

Источник [12]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/349215

Ссылки в тексте:

[1] github.com/RaoulMeyer/diagram-as-code: https://github.com/RaoulMeyer/diagram-as-code

[2] cytoscape.js: https://js.cytoscape.org/

[3] fcose: https://ivis-at-bilkent.github.io/cytoscape.js-fcose/demo-compound.html

[4] редактор: https://antirek.github.io/network-diagram-editor/

[5] странице проекта: https://github.com/antirek/network-diagram

[6] Репозиторий: https://github.com/antirek/network-diagram/

[7] Примеры: https://antirek.github.io/network-diagram/

[8] Хорошая подборка: https://open.evry.blog/2020/01/05/diagram-as-code.html

[9] Шикарный сервис: https://www.diagram.codes/

[10] Конечно, mermaid.js: https://mermaid-js.github.io/mermaid/

[11] go.drawthe.net: http://go.drawthe.net/

[12] Источник: https://habr.com/ru/post/491814/?utm_source=habrahabr&utm_medium=rss&utm_campaign=491814