Визуальное программирование позволяет описывать процессы в графическом виде, в отличии от текстового представления, где нужно приложить дополнительные усилия, чтобы мыслить так, как это должен выполнять компьютер. Звучит многообещающе, но попробуем разобраться в сути и выяснить, почему Вам стоит это попробовать.
Само по себе программирование подразумевает не только процесс написания кода, но зачастую на это тратится большая часть времени при разработке. Только представьте, сколько усилий приходится тратить на то, чтобы держать в голове множество правил и спецификаций к конкретному языку программирования, вместо того, чтобы сосредоточиться на решаемой проблеме. Особенно может раздражать разнообразие синтаксиса в языках: где-то нужна точка с запятой, где-то не нужны фигурные скобки, где-то вообще ни одно выражение не обходится без скобок. Что уж и говорить о холиварах, напоминающие религиозные споры.
Кадр из сериала "Кремниевая долина"
Часто советуют начать разработку ПО с графического описания будущей системы, ее компонентов и связей между ними, чтобы на ранних стадиях определить более выгодную структуру системы и минимизировать возможные проблемы в будущем. Графическое представление легче для понимания, чем текстовый вариант, но может иметь свои ограничения, к тому же это все равно придется переводить в понятный компилятору код. Конечно, на маленькие приложения (какими они могут казаться вначале) это не распространяется, можно сразу приступить к написанию кода, но проблема все равно остается — нужно думать в рамках определенного языка программирования. Тем более, когда вы это делаете в давно приевшемся вам императивном стиле.
Программисты по своей сути должны быть ленивыми, чтобы находить выгодные способы решения задач и не тратить силы на рутину, тем более, глядя на тенденции увеличения сложности ПО. Именно это стимулирует рождение парадигм, языков программирования и абсолютно новых, казалось бы, и малоизвестных инструментов визуального программирования.
Зачем и где применяют визуальное программирование
Одним из первых инструментов, более известных и дружелюбных для рядового гражданина, можно считать Scratch. Он предназначен исключительно для образовательных целей, так как представляет собой те же блоки кода, только обернутые в разноцветные пазлы. Практической пользы нет никакой, если вы уже умеете писать код.
Похожий инструмент от Google под название Blocky
Существует другой вид визуального программирования, более полезный на мой взгляд, это Data-flow programming. Он не такой гибкий как предыдущий и служит некоторой надстройкой для программирования процессов определенной тематики. Его суть состоит в манипуляции данными, передаваемыми между блоками (узлами).
Пример редактора узлов из Blender
Преимущество такого подхода в следующем: не нужно думать о том, что происходит с данными в узлах, а лишь знать, что они делают, получают на вход и отдают на выходе. Остается лишь выбрать нужные узлы и соединить их между собой линиями, по которым без особого затруднения можно понять, что и с чем связано.
Редактор узлов в Blender — именно тот случай, когда используется программирование потоков данных для управления рендерингом, создания шейдеров и текстур. Такой подход в 3D моделировании и рендеринге достаточно популярен, так как никому не хочется писать код, а создавать инструкции для нелинейного управления данными необходимо.
Также известный всем в сообществе 3D моделлеров это Substance Designer, который позволяет создавать 3D материалы по принципу, описанному выше.
Редактор для создания материала в Substance Designer
Хотя в официальных источниках упоминания о программировании нету, в нем используется самый настоящий data-flow. Наверное, это такой маркетинговый ход — не говорить о том, что может отпугнуть.
Итак, разобрались в том, почему визуальное программирование используется в 3D моделировании, но как насчет тех сфер деятельности, где без умения писать код не получится сделать достаточно функциональный продукт? Казалось бы, если умеешь писать код, то просто нужно развивать этот навык, но нет — именно в геймдеве одними из первых стали применяться инструменты для программирования без кодинга. С одной стороны, это было выгодно для популяризации геймдева среди тех, кого отпугивает код лишь одним видом, с другой — прогресс не стоит на месте и даже гуру программирования надоело ставить пробелы вместо табов чтение тысяч строк кода и его поддержка, и они решили попробовать новые методики описания логики и процессов.
Многие знают UE4 с его Blueprint'ом. Это уже не просто data-flow, а что-то большее, так как позволяет формировать инструкции, которые будут выполняться не за один проход, а в течении всего жизненного цикла.
Пример вывода строки по событию
Например, в нем есть узлы для отправки событий. Подключенные к ним узлы выполняются только в тот момент, когда срабатывает событие. Получается очень удобно, не нужно оперировать какими-то объектами и методами, а просто провести соединение от выхода к входу.
Существует еще много отдельных инструментов для визуального программирования (чаще их позиционируют как среда графического программирования), но они не так привлекательны, имеют узкую направленность или вовсе более похожи на конструкторы, чем на инструменты программирования.
Общие аспекты разработки редакторов узлов
Допустим, однажды вы увидели как делают магию программируют с использованием какого-то редактора с блоками и линиями. К вашему удивлению это оказалось именно тем, что позволит воплотить вашу идею (скажем, какой-то продвинутый генератор диалогов, которые представить в виде обычного графа не получится).
Главное, от чего будет зависеть процесс разработки — платформа и технологии. В последнее время много чего можно сделать прямо в браузере, пусть даже пожертвовав производительностью, что в большинстве случаев никак не отразится на качестве приложения (в ином случае asm.js/wasm в помощь). Одна из особенностей таких приложений — они могут быть встроены в другие нативные приложения. Выбор инструментов и языков программирования должен быть в интересах разработчика, чтобы сделать процесс разработки более комфортным и эффективным и снизить вероятность выстрелить себе в ногу появления проблем.
Определившись с платформой и языком, было бы хорошо использовать готовые решения (в нашем случае речь идет о редакторе узлов), но и здесь не все гладко.
Есть несколько вариантов:
- вы используете готовое решение, которое вскоре окажется не таким подходящим и удобным, в придачу к этому вам
леньне под силу подправлять его под себя - написать свою реализацию, заодно изучив как это все работает изнутри и куда прикручивать колеса.
- использовать готовое решение, которое достаточно гибкое и позволяет без проблем настроить его под себя, не жертвуя при этом выгодными фичами для вашего продукта.
Проблема последнего в том, что это достаточно редкое явление, возникающее в последствии немалых усилий. Собственно, суть этой статьи и является в стимулирование достижения такого результата на примере представленной далее библиотеки.
Что такое D3NE
D3 Node editor (D3NE) — это JS библиотека для создания редакторов узлов для решения задач визуального программирования. Библиотека полностью берет на себя работу по отображению и обработке узлов. Использует D3.js и Angular Light
На GitHub Wiki доступен туториал, а также подробное описание всех компонентов и терминологии, используемой в библиотеке (вики на англ. и возможны грамматические ошибки, поэтому буду рад помощи в их исправлении)
Все началось с одного проекта (так он и лежит в draft'ах), в котором появилась идея применить что-то похожее на UE4 Blueprint, только с поправкой на то, что нужен просто data-flow. Среди готовых open source решений на JS не оказалось подходящих: критериями были внешний вид и необходимые возможности (например, разные типы сокетов, чтобы ограничить подключение несовместимых выходов и входов). Если первое еще можно было как-то подправить извне, то добавление второго могло бы вызвать проблемы, тем более если структура и исходный код оставляют желать лучшего.
Так и началось написание кода и формировании этого как отдельной библиотеки. Да, да, именно написание кода, без планирования и проектирования, хотя заранее было неизвестно что в итоге это будет из себя представлять (из-за чего не раз приходилось исправлять свои же ошибки).
К счастью, спустя несколько месяцев после начала разработки удалось дойти до полностью работоспособной версии с необходимыми компонентами для обеспечения гибкости при создании редакторов. Но это не значит, что это финал. Скорее, контрольная точка, после которой нужно стремиться к улучшению того, что уже имеется, и внедрению необходимых возможностей.
Как применить в своем проекте
Для начала нужно выяснить, необходимо ли это вам. Конечно, попробовать для себя кое-что новое никогда не помешает (если это не навредит здоровью :) ), но при решении реальных проблем стоит подумать.
Лучше один раз увидеть, чем… в общем посмотрите примеры:
- Data-flow programming — пример сложения чисел
- События и условное управление данными — примерно так это делается в UE4
- Кастомизация — возможность изменять не только стили, но и структуру узлов и способ соединений
- Allmatter — проект, основанный на этой библиотеке
Пример кастомизации в стиле UE4
Рассмотрим основные компоненты, которые нужны для создания минимально работоспособного редактора
Это такие разъемы, которые могут представлять собой входы или выходы и необходимы для соблюдения правильности их подключения между собой. Назначив входам и выходам этот сокет, можно быть уверенными, что пользователь не сможет передать туда не те данные (вернее, он только назначает связи). Также есть возможность совместить сокеты для подключения между входами и выходами разного типа.
Узлы обычно представляют прямоугольниками (но можно это изменить в пределах вашей фантазии и возможностей CSS и HTML). Они могут иметь входы, выходы и контролы. Входы и выходы представляют сокеты и расположены в левой и правой части узла соответственно (опять таки вы можете их расположить как угодно, используя шаблоны).
Контролы нужны для того, чтобы добавлять в узлы произвольные элементы, а из них можно назначать данные к узлу на момент работы в редакторе (не при обработке данных). Например, с помощью простого поля ввода можно положить значение в узел, которое потом использовать при обработке.
Компоненты нужны для того, чтобы редактор знал какие в нем можно добавлять узлы и как их обрабатывать, а именно необходимы для поддержки импорта/экспорта. Используются так называемые билдеры и воркеры, обычные функции с соответствующим ключом, которые задаются при создании компонента (и должны находиться в одном месте).
Билдер отвечает за создание экземпляра узла — в функции вы создаете экземпляр, добавляете к нему нужные входы, выходы и контролы. Создается это именно программным путем, а не через конфиги (обычно такие реализации находил), чтобы позволить повторное использование, к примеру, контролов, а то и наследование узлов.
Воркер в качестве параметров дает вам входы, выходы и объект с данными узла (не экземпляр, который создается в билдере, а то, что из него достали через toJSON). Входной массив содержит данные, которые пришли на вход из другого узла и массив с выходными данными, в который вы должны положить данные, зависимо от того, что должен делать узел)
Один из основных объектов, который управляет всем вышеперечисленным с целью отображения и взаимодействия с пользователем. Ему передаются идентификатор, компоненты, контекстное меню.
Служит для обработки данных в узлах. Особенность в том, что ему нужны только данные, экспортированные из редактора, таким образом можно выполнять обработку узлов вовсе без наличия редактора (например, есть его реализация на С++). Именно этот компонент библиотеки отвечает за обход узлов, определяя с какого нужно начать обработку, вызывает ваши воркеры, передавая в них входные данные, полученные от предыдущих узлов. Может работать с асинхронными функциями, что не может не радовать на фоне поддержки браузерами async/await. Более того, за счет асинхронной обработки может параллельно выполнять несколько узлов.
Заключение
Как видим, визуальное программирование хоть и призвано заменить написание кода, но довольно редко используется в настоящий момент. Наверное потому, что многие скептически относятся к идее программирования мышкой. Это отчасти справедливо, так как большинство задач в разработке ПО привычнее будет решить на каком-либо языке программирования, чем использовать недостаточно проверенный инструмент.
Суть прогресса состоит в том, чтобы находить более выгодные пути в решении каких-либо задач. Так и в случае с визуальным программированием предоставляется возможность описывать процессы в легком для понимания представлении и достаточном уровне абстракции. Но в это же время нельзя избавиться от исходного кода, так как он является основой для всего этого.
Чтобы убедиться в этом и проверить, как говорится, на себе все описанные возможности, вы можете построить на основе D3NE свой редактор визуального программирования.