Комментарии 79
Картинка оттуда для привлечения внимания.
Схемы просты, пока они маленькие. Я сам проектировал некоторые штуки в виде майндмапов, и они пригодны к работе только пока маленькие. Как только мапа становится большой, её становится сложнее применять. На самом деле читаемость больших схем ужасна.
Текстовый вид удобен тем, что для него выработаны некоторые приемы декомпозиции. Ну например, можно легко назвать две парадигмы — ООП и функциональное программирование. И мы знаем, на какие части надо разбивать, и как их компоновать друг с другом (шаблоны проектирования, или скажем монады).
В случае диаграмм почти ничего из этого нет.
Напомню, что прежде, чем императивный код стало проще писать/читать в виде текста, нежели в виде блок-схем — прошло довольно много времени и пришлось изрядно ограничить допустимые варианты кода (структурное программирование, ооп и т.п. — это именно ограничения, которые мы добровольно приняли, чтобы иметь возможность разбираться в своих программах). Так что в других областях (типа того же dataflow) графическое программирование может протянуть ещё долго, а то и остаться одним из самых удобных инструментов. С ограничением на размер одного модуля, естественно.
Как зависит цикломатическая сложность от способа предоставления? Цикломатическая сложность зависит от топологии (структуры).
Ведь можно разделить на много частей. Один блок — внутри еще куча блоков и так далее.
Впрочем иногда графическое представление удобно.
Я знаю о LabVIEW.
А я на нём «пишу» (на версии 2015). Нет практически никаких средств улучшения представления кода, даже аналогов команд из Altium Designer «выровнять по левому/правому/верхнему/нижнему» краю, из‐за чего бо́льшая часть времени тратится на то, чтобы «код» был поддерживаемым. Нет масштабирования! Проблема с «цикломатической сложностью на пиксель» элегантно «решается» блоками вроде «case structure», которые в принципе не позволяют увидеть весь код сразу.
LabVIEW позволяет размещать комментарии в произвольном месте, что даёт возможность подписывать длинные провода и неочевидные моменты. Плюс названия циклов и фреймов, если они не очевидны или если мне захотелось их назвать. Ну и необходимые вещи вроде названий VI’ек и их иконки.
Вообще‐то у LabVIEW есть какая‐то система документирования, но т.к. я, во‐первых, не знаю, как посмотреть документацию из свойств VI методом, отличным от «открыть VI и пойти смотреть свойства», и, во‐вторых, такая документация относится только к VI целиком и частично закрывается нормальным названием файла и иконкой, то мною эта функциональность как раз‐таки не используется.
А для упрощения, вроде бы хорошо подходит объединение элементов в блоки («виртуальные устройства»).
Про кнопку не знал, но проблемы она не снимает: клавиатурное сочетание на все действия по выравниванию одно. Буду на работе, посмотрю, нельзя ли назначить разные на разные действия, а не одно на повторение последнего действия.
Блоки не всегда подходят: в хосте можно что‐то сообразить на куче различных видов ссылок или с глобальными переменными, но на FPGA первого нет, а второе жрёт ресурсы, из‐за чего такое объединение получается менее оптимальным, чем хотелось бы (в смысле, либо жрёт ресурсы, либо требует выноса в основную VI того, что я на хосте выносить не стал бы). (Впрочем здесь есть возможность задействовать VHDL, только пока руки не дошли.)
Можно писать текст Verilog или VHDL, а можно рисовать схемы в CAD типа Quartus II.
И вот несколько причин, почему текст лучше:
marsohod.org/11-blog/251-sch-or-txt
Стандартный вопрос номер 1: как предлагается хранить графические схемы в системе версионирования, и как предлагается сравнивать две их версии между собой? Без истории кода ни один серьезный проект не выживает.
Что характерно — все подобные системы, что я видел (это конечно не все существующие в мире, но их было довольно много) сильно страдали от этой проблемы. Причем настолько сильно… приходишь на работу после недели отпуска, смотришь на схему — и не понимаешь, что именно там за неделю поменяли. И нет никаких вменяемых средств, чтобы это понять. А те что есть — уступают любому diff и текстовому представлению настолько, что даже и обсуждать тут нечего.
Да дело не в IDE даже. Меня лично отталкивает то, что не видно никаких особых попыток решить фундаментальные проблемы этих систем. Та же проблема с diff — она повсеместная, и при этом она ломает всю коллективную разработку напрочь. Ну т.е. понятно, что тут нужны какие-то другие средства, включая и IDE — но не очень пока понятно, какие. В визуальном представлении имеется куча семантического "мусора", т.е. не обязательных, или дополнительных свойств этого вида кода, который очень трудно фильтровать от свойств, нужных в первую очередь.
Ну т.е. например, диаграмма может скажем иметь разные цвета стрелок, и это хорошо. Это должно помогать в понимании назначения и логики — но это же одновременно мешает понимать другие свойства, зачастую более нужные. Мы в последней версии вот этот квадратик переставили влево на 10 пикселей, соединили с другим входом стрелкой, и перекрасили в другой цвет — что из этого важно? Почему оно не работает, что мы тут сломали, кто, когда, и какую задачу при этом решали?
Не очень понимаю эту проблему. У вас проблема в представлении дельт между графическими схемами? Ну, например, любую схему можно сериализовать в иерархический список (hello, LISP, ну или чуть более близкий современному разработчику XML), а построить дельту можно и в текстовом виде (хуже, все те же издержки потери структуры изменений в диффе, что и с текстовыми ЯП), и в графическом (лучше, потенциально граф может показать изменения во всех срезах представления).
> В визуальном представлении имеется куча семантического «мусора»
А я бы сказал наоборот, в текстовом представлении получается полно дублей имён объектов только лишь для показания связи между двумя сущностями или кусками логики. Там, где в графическом представлении было бы одно безымянное ребро графа, в текстовом возникает одно объявление переменной и два места её использования. (Это лишь один пример.)
> Мы в последней версии вот этот квадратик переставили влево на 10 пикселей, соединили с другим входом стрелкой, и перекрасили в другой цвет — что из этого важно?
Очевидно, что вы в графическом представлении объявили важным абсолютные координаты блоков, а теперь боретесь с этим чучелом графических ЯП. Посмотрите хотя бы пример из статьи — Blocky, графическое представление вовсе не обязано превращаться в векторный редактор, на котором можно рисовать картинки на абсолютно свободные сюжеты.
> соединили с другим входом стрелкой, и перекрасили в другой цвет — что из этого важно?
Очевидно, что это зависит от ЯП, и какие-то изменения в системе контроля версий отметятся как важные, какие-то как декоративные (и вообще не попадут в контроль версий, оставшись личной схемой раскраски на машине разработчика), а какие-то система просто не позволит сделать изначально, на уровне ограничений редактора.
Вот-вот. У вас схемы — а дельты вы мне предлагаете смотреть в XML? Скажем так — я практически три года занимался тем, что смотрел подобные вещи для BPMN, и это ужасно. Просто ужасно. Проблема тут простая — нет визуального представления именно дельты для схем. А когда мы переходим на другое представление — мы теряем всю визуальность. Я не говорю, что это понетциально не решаемая проблема, просто хороших решений, увы, не видать.
Насчет того, что в тексте свой мусор — соглашусь. Да, он есть — но его как-то научились фильтровать IDE и прочий инструмент. Ну и опять же… вы видели что-нибудь типа graphvizard? Вот вам вполне текстовый инструмент, который на выходе дает вполне красивые графы. И без лишнего мусора. Я это к чему — в тексте тоже можно без своего мусора, надо только язык придумать соответствующий задаче.
Ну и по последнему абзацу — я верю, что возможно есть такие системы, где все так хорошо, как вы рассказываете. И уж точно допускаю, что их можно сделать.
Мне просто их видеть пока ни разу не приходилось.
Нет, я вам предлагаю таким образом понять, как могут строиться графические дельты.
> смотрел подобные вещи для BPMN, и это ужасно
> но его как-то научились фильтровать IDE и прочий инструмент
> я верю, что возможно есть такие системы, где все так хорошо, как вы рассказываете.
> Мне просто их видеть пока ни разу не приходилось.
Если говорить «о том, что есть», то да, вы правы, системы визуального программирования на текущий момент значительно отстают по удобству и выразительности от современных текстовых ЯП и IDE с их поддержкой. Ежели говорить о потенциальных возможностях графического программирования («о том, что будет»), то это просто некий умозрительный предел (до которого ещё идти и идти, конечно) закономерного и неотвратимого сращивания средств анализа/исследования кода, менеджмента изменений, зависимостей и авторства и, собственно, самого представления разрабатываемой логики. Итого: графическое представление не хуже текстового, а прост ещё в процессе поиска эффективных форм.
По факту, все подобные вопросы могут быть решены в виде надстроек над библиотекой. Так как это не конечный продукт, то и нет смысла говорить об отсутствии чего-то «из коробки»
1. я умею его быстро читать, тогда дифф смотреть удобно, но тогда зачем мне схема?
2. читать его сложно, тогда какой смысл от диффа?
2. сам json читать не нужно. Повторюсь, он нужен только для хранения, а функционал diff'а и подобное любой может сделать так, как пожелает
Вьювера я пока не находил удобного. Вопрос с этим буду решать, может что подскажут
Я как‐то думал, как выглядело бы представление LabVIEW’шных виртуальных инструментов в формате, который производил бы относительно читаемые diff’ы. Основная суть идеи в том, что метаданные отдельно, логика отдельно, представление отдельно. Если правильно выбрать способ сортировки данных одного уровня иерархии и разбивки на строки, то можно получить относительно читаемые diff’ы. Правда, в моём примере ниже нужно больше внимания уделить алгоритму генерации имени проводов.
Если что, получилось что‐то вроде (мысленно удалите комментарии)
%YAML 1.2
---
description: Wait for delay milliseconds.
# …
# Other metadata from VI properties
# …
icon:
palette:
a: {A: 0x00, R: 0x00, G: 0xff, B: 0x00}
b: {A: 0x00, R: 0x00, G: 0xff, B: 0x00}
# “Image” key uses single-character ARGB colors from palette.
# UTF-8 in case ASCII is not enough.
image: |
bbbbbbbbbb
baaaaaaaab
bbbbbbbbbb
baaaaaaaab
baaaaaaaab
baaaaaaaab
bbbbbbbbbb
terminals:
pattern:
left: 3
top: 0
bottom: 0
right: 3
list:
- name: delay
caption: "delay (default 5000 ms)"
location: left 0
direction: input
type: I32
- name: error in
caption: "error in (no error)"
location: left 2
direction: output
type: error cluster
- name: error out
caption: error out
location: right 2
direction: output
type: error cluster
code:
# Code: contains all used nodes and their relations, but not their positions
# or positions of the wires.
#
# The code is created as following: first all node names are determined.
# Then AST is sorted so that if node B has inputs wired to outputs of node A
# then node A appears first. Should that not allow determining the order
# then nodes are sorted alphabetically.
#
# After sorting is complete all nodes are appended indexes to make them
# unique. Indexes are tracked in runtime and preserved so the below index
# order only keeps being perfect on the first save.
#
# Note: if node was replaced via “Replace” context menu it still keeps its
# index: this is one of the main points in having global incrementing indexes.
#
# Inputs/outputs are named after their nodes with terminal names appended.
# Should terminal name be not unique its position is appended.
#
# Only inputs/outputs which have wires receive their names: names in
# node dictionaries define connections.
- control/delay 0: {output: control/delay 0/output}
- control/error in 1: {output: control/error in 1/output}
- case structure 2:
selector: control/error in 1/output
# Terminal properties which do affect logic are defined here
use default if unwired:
- indicator/error out 5/input
cases:
Error:
# In some cases there is nothing, but wire; and it is significant
# for the logic.
- wire: !!set {control/error in 1/output, indicator/error out 5/input}
No Error:
# User VI: same as default ms waiter, just to show how it would look.
#
# Dictionary near the node maps terminals to connections.
- My Wait.vi 4: {wait: control/delay 0/output}
- indicator/error out 5: {input: indicator/error out 5/input}
# Define wire positions in a form [anchor (output terminal), relative
# x/y offset, anchor (input terminal)]. Wires without sources or with structure
# terminals as sources are listed from sink. Wires without sources or sinks just
# use [anchor, node name] with nearest anchor. No absolute positions used ever.
#
# Note: determining exact anchors still needs code above, pairs in wire
# position only reference nodes.
#
# Since wire may have more then one sink this is a list of lists of lists,
# innermost list is a 2-tuple (type, data).
#
# Structure terminal positions are also defined here.
wires:
control/delay 0/output:
- [[source, control/delay 0], [structure terminal, [case structure 2, +1, 0]], [case, No Error], [sink, MyWait.vi]]
control/error in 1/output:
- [[source, control/error in 1], [structure terminal, [case structure 2, +1, 0]], [case, Error], [structure terminal, [case structure 2, +5, 0]]]
indicator/error out 5/input:
- [[sink, indicator/error out 5], [structure terminal, [case structure 2, -1, 0]]]
# Node positions and properties that do not affect logic.
nodes:
control/delay 0:
type: control
terminal: delay
# Position is absolute
position: [0, 1]
label:
# label position relative to position
position: [-1, -1]
visible: true
view: icon
control/error in 1:
type: control
terminal: error in
position: [0, 0]
label:
position: [-1, -1]
visible: true
view: icon
case structure 2:
type: case structure
position: [1, 2]
size: [5, 2]
label:
text: Case Structure
visible: false
position: [0, 0]
# Case visible by default
selected case: No Error
MyWait.vi 4:
type: VI
# Logical location (which structure, which case) is defined by logic.
position: [2, 1]
label:
position: [-1, -1]
visible: false
view: icon
indicator/error out 5:
type: indicator
position: [6, 0]
label:
position: [-1, -1]
visible: true
view: icon
Пока сделал такой пример: codepen.io/Ni55aN/full/POWEvm
В нем можно подсвечивать узлы, которые удалены/добавлены/перемещен или в них изменены данные. Правая часть редактируемая
Еще сделаю подсветку соединений. Пока как не крутил, в таком виде получилось более приятно для восприятия (имхо).
Разумеется. Я просто написал, как бы я подошёл к представлению виртуальных инструментов LabVIEW для случая «нужно получить хотя бы относительно читаемый diff», а, возможно, иногда даже получать нормально работающее слияние виртуальных инструментов как текстовых файлов. Соответственно, и метаданные, и код, и представление должны быть все представлены в этом файле.
Текст, что выше должен описывать простейший виртуальный инструмент, который вызывает виртуальный инструмент My Wait.vi
с данными из терминала timeout
, в случае, если на входе нет ошибки, и пересылает ошибку на выход, если она есть. Правда, я уже заметил у себя ошибки, но на идею они не влияют.
Главное, что в вашем примере все данные о нодах хранятся в одном месте, и ещё это JSON. Получить нормальные diff’ы в текстовом виде вам так не светит¹: diff любит помещать скобочки не там, где нужно (с т.з. читаемости), у JSON принципиальная проблема с завершающей запятой (которая также плохо отражается на diff’ах), а часто повторяющиеся метаданные вроде "group": null
делают «проблему скобочек» ещё острее. Ну и при чтении diff’а положение узлов в графике не важно совершенно (пока не увидите, не поймёте, нормально ли получилось), а такие изменения будут перемешиваться с логикой.
А про «графический diff»: во‐первых, сложно сделать удобно. Во‐вторых, ну сделаете вы графический diff, а смотреть его как? Схемы хранятся в VCS, VCS обычно является частью чего‐то более крупного вроде github, а веб‐интерфейс «чего‐то крупного» показывать ваши diff’ы не умеет, и учиться не будет, пока вы не станете достаточно популярны (впрочем, в некоторых случаях вы можете научить его сами различными способами, в т.ч. дополнениями для браузера). Если придумать правильное представление, то можно хотя бы получить возможность делать review на уровне «а следует ли мне вообще идти смотреть графический diff», а в идеальном случае должно даже позволить себя читать.
¹ Плюс ещё LabVIEW позволяет размещать провода как вы хотите, а не «у нас соединение с нодой X, а провод проведём как‐нибудь сами»; и у того, и у другого варианта есть плюсы и минусы, но diff’ы в случае, если вы засунете описание пути провода к описанию соединений, станут ещё менее читаемыми.
Пример: codepen.io/Ni55aN/full/POWEvm
Правая часть редактируемая, внизу выбирается то, что нужно подсвечивать
Связи лучше подсвечивать, создавая жирный красный фон, а не перекрашивая их: в LabVIEW много недостатков, но разноцветные линии разной фактуры, соответствующие разным типам к ним не относятся. Но такая подсветка типов плохо совместима с перекрашиванием на diff’е. Ещё одна проблема для diff’ов (кстати, у меня также не решённая, нужно переделать предложение по нумерации узлов; только то, что я пока могу придумать сделает их названия сильно длиннее): если я удалил узел и вставил на место точно такой же, то они подсвечиваются также, как если бы я вставил другой узел (т.е. один удалён, один добавлен).
Практической пользы нет никакой, если вы уже умеете писать код.
Почему же никакой?
Конец и начало каждого логического блока становится очень легко найти.
Причём, цвет здорово помогает не запутаться, что случается в коде со множеством вложенных блоков с отступами без какого-либо цветного выделения.
Позиционировать блоки лучше через свойство transform — меньше тормозить будет.
Уточню вопрос как все это установить
Отсюда github.com/Ni55aN/D3-Node-Editor/wiki понял что установка делается так
npm install d3-node-editor
А дальше что?
Например CFC в ПЛК Siemens
Или же в контроллерах Metso
К тому же там достаточно простая «Бизнес-логика» и схемы как правило не перегружены (но конечно исключения бывают)
Однажды я создал графический язык программирования AnandamideAPI.
Мне удалось внедрить его в рамках одного проекта, и в некотором смысле, это было удачным внедрением. Но проблема в том, что нужно понимать, как извлечь пользу из использования таких языков. Время обучения разработчиков на этом языке — от двух дней (при условии, если человек делал лабы по программированию в универе). Если взять того же человека и начать учить его программированию с помощью текста — на это уйдут как минимум месяцы. Проблема лишь в том, что такие люди быстро скатываются к обычному текстовому программированию и теряют интерес к диаграммам. Выгода состоит в том, что затраты на такого программиста сравнительно низкие, при результате, который работает, и с которым смогут разобраться другие визуальные разработчики
На практике, облегчить необходимо нечто, называемое «коннектинг». Но не формально, ради красивых «блокки». А инструментально. Для того, чтобы быстро заполнять сложные структуры соответствий. Это то, что создает много нудной рутины разработчику- сопоставление между собой сложных структур. Вот где хороша визуализация.
Там где форматированный текст прост и нагляден нужно совсем немного визуализации и она не должна быть излишне плотной или излишне рыхлой. Манипуляции с простыми данными легко читаются и простым текстом, его можно лишь оформить в легко декомпозируемые структуры.
Нужен гений высокого уровня, чтобы исправить этот UX и сделать визуализацию удобнее, чем привычный структурированный текст
Попробую сделать сравнение производительности прямой обработки и через движок
Не осознал, что за сущность "модуль"?
Ага. Поигрался — врубился.
Была бы очень полезна возможность выделить группу узлов и сказать "сделай модуль".
И ещё, если не трудно (мне пока некогда код читать, плотно занят на работе), в каком формате у Вас хранится структура программы? Она как-то сериализуется?
Вы имеете в виду что-то вроде UML? Есть только простые диаграммы и mindmap'ы, нарисованные на скорую руку. Но может есть какие-то сервисы для создания диаграмм классов из JS
Вы не возражаете, если я-динозавр поучусь на примере Вашего проекта собирать проекты современными методами? Чем Вы его собираете?
Начинайте читать с файла package.json, а именно — с секции scripts.
В показательном примере (который откроется автоматически) есть узел Module, а в нем вложены узлы для создания цветной текстуры. Кроме этого, можно делать неограниченное вложение самих модулей (пример в Hub'е)
Почему визуальное программирование и D3NE могут быть Вам полезны