У апошнія пару гадоў пачаў больш займацца дакументацыяй. Напісаць які тлумачыць тэкст аб тым, як працуе тая ці іншая сістэма - у цэлым, гэта досыць проста. Намаляваць схему, на якой будуць адлюстраваны ўсе ключавыя аб'екты, сувязі паміж гэтымі аб'ектамі, таксама лёгка.
Але самы праблемны момант - гэта падтрымліваць гэтую дакументацыю ў актуальным стане. І добра б тэкст, але схемы… Т.к. уся дакументацыя анлайн, г.зн. у фармаце html, то да тэксту прыкладаюцца малюнкі gif/jpeg/png, на якіх уласна намаляваны схемы. А схемы малююцца ў розных праграмах тыпу Visio або анлайн-сэрвісах а-ля draw.io. Затым экспартуеш схему ў графічны фармат і прыкладаеш да html. Усё проста.
У чым праблема?
Схемы звычайна простыя. Дакладней, не надта складаныя. Так, колькасць аб'ектаў дзясятак-два, колькасць сувязяў прыкладна столькі ж. Плюс подпісы, нейкія абазначэнні. Простыя схемы і на словах апісаць можна, а занадта складаныя, кх-м… (з) "не зразумеюць-с". Схем шмат, змены ў іх трэба ўносіць перыядычна-эпізодычна, г.зн. стала, т.к. яны ідуць услед за распрацоўкай нашых прадуктаў.
Можна ж убудоўваць html сэрвісу. Спрабаваў?
Так, вядома. Мне, напрыклад, падабаюцца графікі gliffy.com. Але для змен трэба ісці ў іншы сэрвіс, тамака кіраваць. І складаней дэлегаваць зрабіць папраўкі калегу.
Што рабіць?
Нядаўна на гітхабе мне трапіўся ў рэкамендацыях рэпазітар . Дыяграма як код. Г.зн. мы апісваем на js патрэбную нам схему. Гэты js мы пішам прама ў тым жа html, дзе і іншы тэкст дакумэнтацыі.
Дарэчы сказаць, але я пішу дакументацыю не зусім у html. Звычайна дакументацыя - гэта набор файлаў з markdown-тэкстам, які затым канвертуецца ў паўнавартасны сайт дакументацыі якім-небудзь рухавіком, напрыклад wintersmith. Ці wiki-сістэма.
Атрымліваецца вельмі зручна: вось мы напісалі тэкст, затым адчыняецца тэг script і ў ім апісаны js код схемы.
Што зноў не так?
Гэты рэпазітар мне спадабаўся, але гэта не адзіны прыклад, калі дыяграму малююць з дапамогай кода або тэкставага прадстаўлення. (У канцы артыкула будуць спасылкі праектаў і артыкулаў, якія нагуглілі па тэме diagram as code.)
І бо я не адзін праўлю дакументацыю. Часам сваю лепту ўносяць і калегі - слова паправіць, апісанне змяніць, новыя карцінкі ўставіць.
Таму хацелася б дыяграму бачыць у чытэльным зразумелым тэкставым фармаце, якому б не прыйшлося доўга навучацца. А месцамі нават проста copy-paste зрабіць для паскарэння дадання новай схемы.
А яшчэ адзін калега заўважыў, што код гэта, канешне, добра, але калі выкарыстоўваць структуру, усё можа быць вельмі строга і выразна.
Таму я паспрабаваў уявіць схему як набор некалькіх невялікіх масіваў, якія апісваюць вузлы, сувязі, групы вузлоў, а таксама размяшчэнне вузлоў. Атрымалася на мой сціплы погляд дастаткова зручна, хоць, вядома, на густ і колер…
Як гэта дыяграма ў масіве?
- Кожны вузел апісваецца ідэнтыфікатарам, які адназначна вызначае вузел.
- Таксама да вузла можна дадаць абразок, дадаць надпіс.
- Паміж двума вузламі можна пазначыць сувязь.
- Для сувязі на схеме можна задаць колер, надпіс.
- Кірунак сувязі вызначаецца як ад крыніцы да мэты. А крыніца і мэта ўказваюцца ідэнтыфікатарамі вузла.
- Адзін і больш вузлоў можна дадаць у групу.
- Сувязь таксама можна ўказаць і ад групы, і да групы.
Карыстаючыся гэтымі простымі правіламі, атрымліваецца вось такая схема. Проста? Суцэль.

А апісваецца яна наступным 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);
Вядома, адмалёўку схемы я прыдумаў не сам, а скарыстаўся бібліятэкай - Вельмі магутны інструмент візуалізацыі. Крыху магчымасцяў якой у сваім рашэнні выкарыстоўваю толькі.
Зразумела, гэта просты прыклад. Можна больш складана?
Ды калі ласка. Для ўказання пазіцый - мы выкарыстоўваем positions, для ўказання груп - паказваем спіс груп у groups, а ў саміх элементаў атрыбут group.

А гэта код:
<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 дазваляе запаўняць усе дадзеныя па аналогіі, хутка і можна copy-paste.
А чаму positions вынесены асобна ад вузлоў?
Так зручней. Спачатку мы паказваем nodes. Затым можам паказаць пару-тройку груп і паказаць іх у вузлах. Затым абазначаем сувязі. А ўжо затым, калі асноўныя аб'екты і сувязі паміж імі ёсць, бярэмся за размяшчэнне гэтых аб'ектаў на схеме. Ці наадварот.
А ці можна без positions?
Можна і без positions. Але гэта будзе крыху скамечана, у прыкладах можна паглядзець такі варыянт. Гэта абумоўлена тым, што для cytoscape ёсць алгарытм размяшчэння вузлоў. , які таксама ўлічвае наяўнасць груп. Указанне positions робіць схему больш кантраляванай, але на стадыі першага накіда схемы можна і без positions.
Таксама positions можна ўказваць у стылі Марскога бою. Г.зн. адзін вузел размяшчаецца ў a1, а іншы ў d5. Асабліва дапамагае, што cytoscape фармуе аб'екты на canvas рухомымі, г.зн. мы можам іх падштурхоўваць, паглядзець розныя варыянты размяшчэння, а затым зафіксаваць у кодзе ўпадабанае размяшчэнне элементаў.
У цэлым зразумела. Можна паспрабаваць?
Вядома, для хуткага стварэння схем зрабіў сабе невялікі , які сам абнаўляе схему і ў браўзэры захоўвае апошні варыянт (у 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. правім код да патрэбнай нам схемы (думаю, гэта прасцей чым намаляваць саву 🙂
Яшчэ падрабязней на на гітхабе.
Што ў выніку?
Сваіх мэт я дасягнуў - зрабіць даданне схем inline у дакументацыю, фармат досыць просты і зразумелы. Для суперсхем не падыдзе, а для невялікіх схем, якія тлумачаць структуру сувязяў – вельмі нават нічога. Заўсёды можна хутка падправіць і нешта з цягам часу памяняць. Так, і калегі могуць у доку самі нешта падправіць, як мінімум подпісы да аб'ектаў без асаблівага навучання))
Што можна палепшыць?
Тут варыянтаў, канешне, маса. Зрабіць даданне дадатковых абразкоў (усе наяўныя дададзеныя inline у скрыпт). Падабраць больш выразны набор абразкоў. Зрабіць магчымасць указання стылю лініі сувязяў. Дадаць фонавы малюнак.
А што вы думаеце?
У мяне ўжо ёсць некалькі ідэй на рэалізацыю ў issues, вы таксама дадайце свае ў каментары.
Маё рашэнне вызначана дастасавальна ў вузкім спектры задач, і магчыма вы знойдзеце зручнейшую прыладу для малявання дыяграм, проста закадаваўшы іх — як той казаў 'show me your diagram as code'
- (9 тыпаў графікаў анлайн-рэдактар)
- І калі вам любы супер дэталёвыя і складаныя схемы - то вас вызначана захапіць гэты праект:
Крыніца: habr.com
