Когда вы пишите графическую программу на каком либо языке программирования то с помощью кодов
В предыдущей части мы затронули азы программирования, где рассказали о машинном языке, преобразователях, языках программирования и работе с CLI. Двигаемся дальше.
Исходным кодом называется основной файл вроде Microsoft (.doc), но немного другой. Это текстовый файл, написанный с помощью простых редакторов, таких как Windows Блокнот. В предыдущем разделе мы перечислили, что нужно, чтобы интерпретаторы или компиляторы конвертировали исходный код в двоичный. Первый должен быть сохранен в файле, что передается для ввода в переводчик (преобразователь).
В зависимости от выбранного языка, есть назначенные расширения для сохранения файла: Python – .py. Java – .java. PHP – .php, PERL – .pl и т. д.
Когда вы закончите писать код, запустите его через переводчик. Рассмотрим в качестве примера запуск кода на языке Python с использованием команды python.
Начало работы: ваша первая программа
- Следуйте приведенным здесь инструкциям, чтобы настроить Python в вашей компьютерной системе.
- Установите простой редактор, чтобы ввести исходный код. Для начала можете использовать этот текстовый редактор.
3. Откройте в нем новый файл и введите следующее:
- Не забудьте сохранить файл как main.py.
- Найдите путь к файлу через CLI и введите следующую команду:
Результат должен выглядеть так:
Анатомия типичного кода
Теперь мы рассмотрим содержимое типичного файла исходного кода. Ниже приведены регулярные компоненты.
Ключевые слова
Короткие человекочитаемые слова, обычно называемые ключевыми. Они свойственны изучаемому вами языку и они особенны. Их просто нужно знать. Вот небольшой набор ключевых слов, часто используемых в Python.
Идентификаторы
Слова, изобретенные вами. Да, не удивляйтесь! Вы, программист. Эти слова обычно называются идентификаторами. Они могут быть созданы вами или другими программистами. Они упакованы в плагины, более известные как библиотеки.
Примером является библиотека Math. Она позволяет получить доступ к функциям, таким как квадратный корень (Math.sqrt), используемый в JavaScript.
Многие языки программирования поставляются со множеством библиотек. Они обычно называются SDK (комплекты разработки программного обеспечения). Загружаются вместе с компилятором для дальнейшего создания технологий, приложений и проектов. Также существуют фреймворки, созданные, чтобы облегчить разработку проекта и объединить его различные составляющие.
Некоторые идентификаторы в комплекте с выбранным языком не могут использоваться в качестве идентификатора пользователя. Примером является слово string в Java. Такие идентификаторы вместе с ключевыми словами называются Зарезервированными Словами. Они также являются особыми.
Все ключевые слова являются зарезервированными. Также слова, которые вы выбираете, должны иметь смысл для тех, кто впервые их видит.
Основные типы данных
Исходный код – сосредоточение разных типов даннх: числа (3, 5.7, -100, 3.142) и символы (M, A). В некоторых языках программирования числа разбиваются на подтипы, такие как integers (целые числа).
Целые числа могут быть знаковыми и беззнаковыми, большими и малыми. Последние фактически зависят от объема памяти, зарезервированного для таких чисел. Есть числа с десятичными частями, обычно называемые double и float, в зависимости от языка, который вы изучаете.
Также существуют логические типы данных boolean, которые имеют значение true или false.
Сложные типы данных
Указанные выше типы известны как элементарные, первичные или базовые. Мы можем создавать более сложные типы данных из приведенных базовых.
Массив (Array) – это простейшая форма сложного типа. Строка (String) – это массив символов. Мы не можем обойтись без этих данных и часто используем их при написании кода.
Комбинация символов – это строка. Чтобы использовать аналогию, строка для компьютера означает, что слово принадлежит человеку. Слово «термометр» состоит из 9 символов – мы просто называем это строкой символов. Обработка строк – это обширная тема, которая должна изучаться каждым начинающим программистом.
Сложные типы данных поставляются с большинством языков программирования, которые используются. Есть и другие, такие как системы классов. Это явление также известно как объектно-ориентированное программирование (ООП).
Переменные
Переменные – это просто имена областей памяти. Иногда нужно сохранить данные в исходном коде в месте, откуда их можно вызвать, чтобы использовать. Обычно это место памяти, которое резервирует компилятор/интерпретатор. Нам нужно дать имя этим ячейкам памяти, чтобы потом их вспомнить. Рассмотрим фрагмент кода Python ниже:
pet_name – пример переменной, и тип данных, хранящихся в pet_name, является строкой, что делает переменную строковой. Существуют также числовые. Таким образом, переменные классифицируются по типам данных.
Константы
Константы – это значения, которые не изменяются на протяжении всего жизненного цикла программы. Чаще всего в их именах используются заглавные буквы. Некоторые языки поддерживают создание постоянных значений, а некоторые – нет.
Существуют строго типизированные языки программирования, в которых каждая переменная должна быть определенного типа. Выбрав тип один раз, вы больше не сможете его изменить. Java – хороший пример такого ЯП.
Другие же не предоставляют эти функции. Они являются свободно типизированными или динамическими языками программирования. Пример – Python.
Вот как объявить постоянное значение в JavaScript:
Литералы
В каждом исходном коде существуют типы данных, которые используются повсюду и изменяются только в том случае, если их отредактировали. Это литералы, которые не следует путать с переменными или константами. Ни один исходный код не обходится без них. Литералы могут быть строками, числами, десятичными знаками или любыми другими типами данных.
В приведенном выше фрагменте слово «Hippo» является строковым литералом. Это всегда будет «Hippo», пока вы не отредактируете исходный код. Когда вы научитесь кодить, узнаете, как управлять литералами таким образом, чтобы оставлять неизменной большую часть кода.
Пунктуация/Символы
В большинстве написанных программ вы найдете различные знаки препинания в зависимости от выбранного языка программирования. Например, в Java используется больше знаков препинания, чем в Python.
Основные знаки включают в себя запятую (,), точку с запятой (;), двоеточие (:), фигурные скобки (<>), обычные круглые скобки (()), квадратные скобки ([]), кавычки ("" или ''), вертикальную черту (|), слэш (\), точку (.), знак вопроса (?), карет (^) и процент (%).
Операторы
Шансы, что вы будете писать исходный код для выполнения какой-нибудь операции, крайне высоки. Любые языки программирования, которые мы используем, включают в себя множество операторов. Среди применяемых выделяют сложение (+), деление (/) умножение (*), вычитание (-) и знак больше (>).
Операторы обычно классифицируются следующим образом:
- Операторы присваивания. Они иногда истолковываются как equals, что неправильно. Равенство используется для сравнения двух значений. А вот оператор присваивания присваивает значение переменной, например pet_name = 'Hippo'
- Арифметические операторы. Состоят из операторов для выполнения арифметических задач, таких как сложение и вычитание. Некоторые языки программирования предоставляют арифметические операторы, когда другие могут их не иметь в своем арсенале. Например, оператор модуля/остатка (%) возвращает остаточное значение в операциях деления.
- Реляционные операторы. Используются для сравнения значений. Они включают в себя больше, меньше, равно, не равно. Их представление также зависит от того, какой язык программирования вы изучаете. Для некоторых ЯП не равно – это <>, для других же – != или !==.
- Логические операторы. Применяются для произведения логических операций. Обычно используемыми логическими операторами являются и, или, нет. Некоторые языки представляют эти операторы в виде специальных символов. Например, && для представления логического и, || – для или, и ! – для нет. Логические значения принято оценивать с помощью булевых значений true или false.
Комментарии
Документация будет важным аспектом деятельности в сфере программирования. Это то, как вы объясняете свой код другим программистам. Подобное делается с помощью комментариев, которые добавляются к различным частям кода. С помощью комментариев вы можете направлять других программистов через написанную программу.
Компилятор игнорирует строки кода, которые являются комментариями.
Вот пример комментария в Python:
Пробелы и вкладки
Это пробелы, созданные между кодом, который вы пишете. Они ставятся при нажатии пробела или клавиши табуляции на клавиатуре.
Двигаемся дальше
Вы познакомились с исходным кодом и изучили его содержимое. Скомпилированный или преобразованный код может не запускаться по ряду причин. Эти причины обычно связаны с ошибками. Действие поиска и удаления ошибок называется отладкой и является навыком, который вы должны изучить. Ошибки мы рассмотрим в следующей части.
Убедитесь, что вы правильно настроили Python в своей компьютерной системе, и запустите свою первую программу.
Викторина
Определите элементы, которые мы изучили, в приведенном ниже фрагменте кода Java:
Визуальное программирование позволяет описывать процессы в графическом виде, в отличии от текстового представления, где нужно приложить дополнительные усилия, чтобы мыслить так, как это должен выполнять компьютер. Звучит многообещающе, но попробуем разобраться в сути и выяснить, почему Вам стоит это попробовать.
Само по себе программирование подразумевает не только процесс написания кода, но зачастую на это тратится большая часть времени при разработке. Только представьте, сколько усилий приходится тратить на то, чтобы держать в голове множество правил и спецификаций к конкретному языку программирования, вместо того, чтобы сосредоточиться на решаемой проблеме. Особенно может раздражать разнообразие синтаксиса в языках: где-то нужна точка с запятой, где-то не нужны фигурные скобки, где-то вообще ни одно выражение не обходится без скобок. Что уж и говорить о холиварах, напоминающие религиозные споры.
Кадр из сериала "Кремниевая долина"
Часто советуют начать разработку ПО с графического описания будущей системы, ее компонентов и связей между ними, чтобы на ранних стадиях определить более выгодную структуру системы и минимизировать возможные проблемы в будущем. Графическое представление легче для понимания, чем текстовый вариант, но может иметь свои ограничения, к тому же это все равно придется переводить в понятный компилятору код. Конечно, на маленькие приложения (какими они могут казаться вначале) это не распространяется, можно сразу приступить к написанию кода, но проблема все равно остается — нужно думать в рамках определенного языка программирования. Тем более, когда вы это делаете в давно приевшемся вам императивном стиле.
Программисты по своей сути должны быть ленивыми, чтобы находить выгодные способы решения задач и не тратить силы на рутину, тем более, глядя на тенденции увеличения сложности ПО. Именно это стимулирует рождение парадигм, языков программирования и абсолютно новых, казалось бы, и малоизвестных инструментов визуального программирования.
Зачем и где применяют визуальное программирование
Одним из первых инструментов, более известных и дружелюбных для рядового гражданина, можно считать 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 доступен туториал, а также подробное описание всех компонентов и терминологии, используемой в библиотеке (вики на англ. и возможны грамматические ошибки, поэтому буду рад помощи в их исправлении)
Так и началось написание кода и формировании этого как отдельной библиотеки. Да, да, именно написание кода, без планирования и проектирования, хотя заранее было неизвестно что в итоге это будет из себя представлять (из-за чего не раз приходилось исправлять свои же ошибки).
К счастью, спустя несколько месяцев после начала разработки удалось дойти до полностью работоспособной версии с необходимыми компонентами для обеспечения гибкости при создании редакторов. Но это не значит, что это финал. Скорее, контрольная точка, после которой нужно стремиться к улучшению того, что уже имеется, и внедрению необходимых возможностей.
Как применить в своем проекте
Для начала нужно выяснить, необходимо ли это вам. Конечно, попробовать для себя кое-что новое никогда не помешает (если это не навредит здоровью :) ), но при решении реальных проблем стоит подумать.
Лучше один раз увидеть, чем… в общем посмотрите примеры:
-
— пример сложения чисел — примерно так это делается в UE4 — возможность изменять не только стили, но и структуру узлов и способ соединений — проект, основанный на этой библиотеке
Пример кастомизации в стиле UE4
Рассмотрим основные компоненты, которые нужны для создания минимально работоспособного редактора
Это такие разъемы, которые могут представлять собой входы или выходы и необходимы для соблюдения правильности их подключения между собой. Назначив входам и выходам этот сокет, можно быть уверенными, что пользователь не сможет передать туда не те данные (вернее, он только назначает связи). Также есть возможность совместить сокеты для подключения между входами и выходами разного типа.
Контролы нужны для того, чтобы добавлять в узлы произвольные элементы, а из них можно назначать данные к узлу на момент работы в редакторе (не при обработке данных). Например, с помощью простого поля ввода можно положить значение в узел, которое потом использовать при обработке.
Компоненты нужны для того, чтобы редактор знал какие в нем можно добавлять узлы и как их обрабатывать, а именно необходимы для поддержки импорта/экспорта. Используются так называемые билдеры и воркеры, обычные функции с соответствующим ключом, которые задаются при создании компонента (и должны находиться в одном месте).
Билдер отвечает за создание экземпляра узла — в функции вы создаете экземпляр, добавляете к нему нужные входы, выходы и контролы. Создается это именно программным путем, а не через конфиги (обычно такие реализации находил), чтобы позволить повторное использование, к примеру, контролов, а то и наследование узлов.
Один из основных объектов, который управляет всем вышеперечисленным с целью отображения и взаимодействия с пользователем. Ему передаются идентификатор, компоненты, контекстное меню.
Служит для обработки данных в узлах. Особенность в том, что ему нужны только данные, экспортированные из редактора, таким образом можно выполнять обработку узлов вовсе без наличия редактора (например, есть его реализация на С++). Именно этот компонент библиотеки отвечает за обход узлов, определяя с какого нужно начать обработку, вызывает ваши воркеры, передавая в них входные данные, полученные от предыдущих узлов. Может работать с асинхронными функциями, что не может не радовать на фоне поддержки браузерами async/await. Более того, за счет асинхронной обработки может параллельно выполнять несколько узлов.
Заключение
Как видим, визуальное программирование хоть и призвано заменить написание кода, но довольно редко используется в настоящий момент. Наверное потому, что многие скептически относятся к идее программирования мышкой. Это отчасти справедливо, так как большинство задач в разработке ПО привычнее будет решить на каком-либо языке программирования, чем использовать недостаточно проверенный инструмент.
Суть прогресса состоит в том, чтобы находить более выгодные пути в решении каких-либо задач. Так и в случае с визуальным программированием предоставляется возможность описывать процессы в легком для понимания представлении и достаточном уровне абстракции. Но в это же время нельзя избавиться от исходного кода, так как он является основой для всего этого.
Чтобы убедиться в этом и проверить, как говорится, на себе все описанные возможности, вы можете построить на основе D3NE свой редактор визуального программирования.
В работе со студентами и учениками я заметила, что при изучении какого-либо языка программирования большой интерес вызывает работа с графикой. Даже те студенты, которые скучали на заданиях про числа Фибоначчи, и уже казалось бы у них пропадал интерес к изучению языка, активизировались на темах, связанных с графикой.
Поэтому предлагаю потренироваться в написании небольшой графической програмки на Python с использованием tkinter (кроссплатформенная библиотека для разработки графического интерфейса на языке Python).
Код в этой статье написан для Python 3.5.
Задание: написание программы для рисования на холсте произвольного размера кругов разных цветов.
Не сложно, возможно программа «детская», но я думаю, для яркой иллюстрации того, что может tkinter самое оно.
Хочу рассказать сначала о том, как указать цвет. Конечно удобным для компьютера способом. Для этого в tkinter есть специальный инструмент, который можно запустить таким образом:
Пояснения к коду:
- rom tkinter import * — импорт библиотеки, вернее всех ее методов, на что указывает звездочка (*);
- window = Tk() — создание окна tkinter;
- colorchooser.askcolor() — открывает окно выбора цвета и возвращает кортеж из двух значений: кортеж из трех элементов, интенсивность каждой RGB цвета, и строка. цвет в шестнадцатиричной системе.
Примечание: как сказано в коментариях ниже — звёздочка не все импортирует, надёжнее будет написать
from tkinter import colorchooser
Можно для определения цвета рисования использовать английские название цветов. Здесь хочу заметить, что не все они поддерживаются. Тут говорится, что без проблем вы можете использовать цвета «white», «black», «red», «green», «blue», «cyan», «yellow», «magenta». Но я все таки поэкспериментировала, и вы увидите дальше, что из этого вышло.
Для того, чтобы рисовать в Python необходимо создать холст. Для рисования используется система координат х и у, где точка (0, 0) находится в верхнем левом углу.
В общем хватит вступлений — начнем.
Пояснения к коду:
- from random import * — импорт всех методов модуля random;
- from tkinter import * — это вы уже знаете;
- переменная size понадобится потом;
- root = Tk() — создаем окно;
- canvas = Canvas(root, width=size, height=size) — создаем холст, используя значение переменной size (вот она и понадобилась);
- canvas.pack() — указание расположить холст внутри окна;
- переменная diapason понадобится потом для использования в условии цикла.
Здесь хочу остановиться на выборе цвета. Мне хотелось добавить как можно больше вариантов выбора цвета, поэтому я воспользовалась таблицей названий цветов в английском языке. Но вскоре поняла, что многие английские названия не поддерживаются — программа переставала работать. Поэтому определение цвета в шестнадцатиричной системе будет для этих целей более подходящим вариантом.
x0 = randint(0, size) и y0 = randint(0, size) — случайный выбор координат х и у в рамках холста размером size.
d randint(0, size/5) — произвольный выбор размера круга, ограниченный size/5.
canvas.create_oval(x0, y0, x0+d, y0+d, fill=colors) — собственно говоря рисуем круги, в точках с координатами x0 и y0, размерами по вертикали и горизонтали x0+d и y0+d, заливкой цветом, который выбирается случайным образом из списка colors.
root.update() — update() — обрабатывает все задачи, стоящие в очереди. Обычно эта функция используется во время «тяжёлых» расчётов, когда необходимо чтобы приложение оставалось отзывчивым на действия пользователя.
Без этого в итоге отобразятся круги, но процесс их появления будет вам не виден. А именно это придает шарм этой програмке.
diapason += 1 — шаг цикла, счетчик.
В результате получается такая картинка:
Мне не понравилось, что справа и вверху какие-то пустые места образовываются, поэтому я немного изменила условие цикла while diapason < 2000 или 3000. Так холст получился более заполненным.
Также можно сделать цикл бесконечным:
Я думаю, можно было бы еще поиграться со скоростью рисования кругов или их движением по холсту. Можно было увеличить варианты выбора цветов. Поставить условие для остановки бесконечного цикла, например по нажатию пробела. Это все задания для будущих программ.
Студенты еще спросили, а можно ли запускать это как заставку на рабочем столе Windows? Пока не нашла как это можно было бы сделать.
Внимание.
Первоначальная версия этой публикации получила большой отклик на Reddit в виде более чем 300 комментариев. После этого я решил дописать к ней небольшой апдейт, чтобы ответить на некоторые критические замечания из множества поступивших.
Язык визуального программирования — это такой язык, который позволяет программисту создавать программы, манипулируя графическими элементами, а не печатая текстовые команды. Известным примером является Scratch, язык визуального программирования родом из MIT, который используется для обучения детей. Его преимущества заключаются в том, что он делает программирование более доступным для новичков и не-программистов.
В 1990-х годах было очень популярное движение по внедрению визуального программирования в корпоративную среду с помощью так называемых CASE-инструментов, где корпоративные системы можно было бы определять с помощью UML и генерировать [их код] без необходимости в привлечении обученных разработчиков программного обеспечения. Это связано с концепцией «round tripping» («туда и обратно»), где система может быть смоделирована визуально, программный код будет генерироваться из полученных моделей, а любые изменения кода могут быть возвращены обратно в модель. Увы, подобные инструменты так и не смогли выполнить свою миссию, и большинство из экспериментов [по их внедрению] в настоящее время в значительной степени заброшены.
Таким образом, визуальное программирование не завоевало популярность, кроме некоторых очень ограниченных областей. Подобная ситуация во многом объясняется следующими заблуждениями о программировании:
- Языки текстового программирования запутывают то, что по существу является простым процессом.
- Абстракция и декупликация (decoupling, уменьшение связности) играют небольшую периферийную роль в программировании.
- Инструменты, которые были разработаны для помощи программированию, не важны.
Я предполагаю, что это заблуждение проистекает из неспособности фактически прочитать типичную программу, написанную на стандартном языке текстового программирования, и представить, как она преобразуется в графические элементы из «кубиков» и стрелок. Если вы все же сможете вообразить себе это, то сразу станет очевидно, что одна строка кода часто сопоставляется с несколькими «кубиками». Поскольку даже для простейшей программы наличие сотни-другой строк кода не является чем-то необычным, то ее код превратится в сотни или даже тысячи графических элементов. Попытка мысленно разобрать такую сложную картину окажется намного сложнее, чем просто чтение эквивалентного ей текста программы.
Решение для большинства языков визуального программирования состоит в том, чтобы сделать «блоки» более сложными, чтобы каждый визуальный элемент был эквивалентен большому блоку текстового кода. Визуальные инструменты рабочего процесса являются здесь непосредственным камнем преткновения.
Проблема в том, код должен все равно должен быть где-то определен. Поэтому процесс кодинга [на крупных визуальных элементах] превращается в «программирование свойств диалогов». Визуальные элементы сами по себе представляют собой лишь самый высокий уровень движения программы при исполнении, и большая часть работы теперь выполняется в стандартном текстовом коде, скрытом в визуальных «кубиках». В итоге мы взяли худшее из обоих миров и получили текстовое программирование, не поддерживаемое современными инструментами.
Диалоги свойств обычно являются нестандартными средами разработки и навязывают конкретный выбор языка, обычно язык сценариев какого-либо типа. Сами базовые визуальные элементы могут быть созданы только опытными программистами, а досконально понять их можно, только путем считывания их базового кода, поэтому большинство предполагаемых преимуществ визуального представления теряются и здесь.
Между визуальным «кодом» и текстовым кодом существует рассогласование импеданса (набор концептуальных и технических трудностей), и программисту приходится перемещаться по интерфейсу между ними, часто затрачивая больше усилий на усовершенствование самого графического инструмента программирования, чем на решение изначальной задачи [по написанию программы].
И теперь мы подошли ко второму заблуждению, что абстракция и декупликация играют небольшую роль в программировании. Визуальное программирование исходит из предположения, что большинство программ являются простыми процедурными последовательностями, несколько похожими на блок-схему. Как правило, большинство начинающих программистов считают, что программное обеспечение именно так и работает.
Однако, как только программа становится больше, чем довольно тривиальный пример, ее сложность скоро сокрушает программиста новичка. Новички обнаруживают, что очень сложно рассуждать о большой процедурной базе кода и часто увязают в попытках создания стабильного и эффективного программного обеспечения большого масштаба. Главной инновацией в языках программирования стала попытка управлять сложностью, обычно через абстракцию, инкапсуляцию и уменьшение связности. Все системы типов и конструкции объектно-ориентированных и функциональных языков программирования на самом деле всего-лишь попытка взять под контроль сложность этих языков.
Большинство профессиональных программистов будут постоянно абстрагировать и декуплицировать код. По сути разница между хорошим и плохим кодом в основном и заключается в том, насколько программисту удалось это сделать. У инструментов визуального программирования очень редко есть эффективные механизмы для таких вещей, в результате «визуальный» разработчик оказывается в ловушке доступных возможностей, эквивалентной BASIC'у 1970-х годов.
Последнее заблуждение состоит в том, что визуальные программисты якобы могут обойтись без всех инструментов поддержки программирования, которые были разработаны на протяжении десятилетий. Взгляните на длительную эволюцию редакторов кода и сред IDE. Например, Visual Studio поддерживает эффективный инструмент intellisense, позволяющий подсматривать тысячи API-интерфейсов, доступных в одной только в библиотеке базового класса. Отсутствие хорошего контроля над версиями — еще один серьезный недостаток большинства инструментов визуального программирования.
Даже если они сохраняют свой макет в текстовом формате, «диффы» не имеют никакого или почти никакого смысла. Очень трудно сделать 'blame' (найти коммит и ответственного за изменения конкретной строки) в большой глыбе XML или JSON. Вещи, которые не имеют никакого значения для функционального исполнения программы, такие как положение и размер графических элементов, при этом постоянно приводят к изменениям в метаданных, что делает «дифф» еще более сложным для синтаксического анализа.
Языки текстового программирования научились разделять структурные блоки кода на отдельные исходные файлы, поэтому изменение одной части системы легко слить с изменением в другом. Визуальные инструменты обычно сохраняют результат по принципу «одна диаграмма на один файл», что означает, что слияния становятся проблематичными, и еще сложнее, если семантическое значение «диффа» трудно анализировать.
Вероятно, я ошибся, когда взял экранный снимок Scratch и использовал его в качестве основного примера в моем первом абзаце. Я не преподаватель, и у меня нет собственного мнения о эффективности Scratch как инструмента обучения. Многие люди говорят, что он чрезвычайно полезен в обучении программированию, особенно для детей. Все, что помогает попасть людям в чудесный и захватывающий мир программирования, следует только похвалить. Я действительно не намеревался сейчас критиковать конкретно Scratch, это просто пример системы визуального программирования, о которой, как мне казалось, большинство из моих читателей должно было хотя бы слышать.
Другим контр-примером, приведенным в Reddit, были инструменты статической структуры, такие как дизайнеры пользовательского интерфейса, дизайнеры схем баз данных или дизайнеры классов. Я согласен, что они могут быть очень полезными. Все, что помогает визуализировать структуру данных или масштабную структуру программы, является бонусом. Но их никогда не бывает достаточно. Об этом свидетельствует полный провал инструментов из 90-х, таких как Power Builder, которые базировались на графических визуализациях для создания среды разработки без необходимости работать с кодом.
Об авторе:
Заметки, мысли вслух, обучение у всех на виду, недоразумения, ошибки, неразбавленные мнения. Я Майк Хэдлоу, проповедующий разработчик. Я живу недалеко от Брайтона на южном побережье Англии.
Перевод выполнен при поддержке компании EDISON Software, которая профессионально занимается разработкой и тестированием софта.
Более 35 лет инженеры и ученые используют NI LabVIEW для разработки измерительных систем, испытательных стендов и систем управления. В основе LabVIEW лежит графический язык программирования G. Помимо самой возможности программирования среда LabVIEW предоставляет в распоряжение пользователя широкий спектр инструментов и библиотек: от интерактивных мастеров настройки и пользовательских интерфейсов до встроенных компилятора, компоновщика и средств отладки.
Краткая история развития высокоуровневого программирования
Чтобы лучше понять основные преимущества концепции графического программирования, стоит обратиться к истории появления первого высокоуровневого языка. В середине 50-х годов XX века, на заре развития компьютерной техники, небольшое подразделение в IBM разработало альтернативный способ программирования суперкомпьютеров IBM 704 – язык FORTRAN. В отличие от существовавшего в то время низкоуровневого языка, предложенный специалистами язык был ближе к прикладной области, проще воспринимался человеком и позволял ускорить процесс разработки.
Сперва инженерное сообщество скептически отнеслось к появлению нового языка. Способность программ, написанных на FORTRAN, работать столь же быстро, как и кропотливо созданные на низкоуровневых языках, вызывала большие сомнения. Однако довольно скоро стало ясно, что разница в производительности практически отсутствует. С другой стороны, FORTRAN позволял сократить размер исходного кода в десятки раз, поэтому не удивительно, что он быстро завоевал популярность.
Несмотря на то, что высокоуровневые языки все время совершенствуются, вопрос повышения удобства и скорости работы остается актуальным и на сегодняшний день. Это объясняет популярность и широкое распространение языка G, с тех пор как он появился в 1986 году. Этот язык предоставляет максимально возможный уровень абстракции, что позволяет пользователям работать более эффективно, практически не проигрывая в производительности кода таким языка как FORTRAN, C и C++.
LabVIEW: графическое потоковое программирование
Существует два основных отличия LabVIEW от других языков программирования. Во-первых, LabVIEW реализует концепцию графического программирования, поэтому исходный код представляет собой блок-диаграмму (соединенные друг с другом пиктограммы элементов языка), которая затем компилируется в машинный код. Несмотря на такой подход, в LabVIEW используются те же конструкции и методы программирования, что и в других языках: типы данных, циклы, переменные, рекурсия, обработка событий и объектно-ориентированное программирование.
Вторая отличительная особенность LabVIEW - это поддержка выполнения кода, написанного на языке G, в режиме потока данных (потоковое программирование), в то время как традиционные текстовые языки (например, C и C++) обеспечивают выполнение кода в виде последовательности команд. В основе языков потокового программирования (таких как G, Agilent VEE, Microsoft Visual Programming Language и Apple Quartz Composer) лежит концепция потока данных, который и определяет последовательность выполнения функциональных узлов программы.
Поначалу может показаться, что отличие подобного подхода от традиционного не существенно, однако на практике оказывается иначе. А именно, потоковое программирование в среде LabVIEW позволяет разработчику полностью сфокусироваться на данных и путях их обработки. Узлы программы - функции, циклы и прочие конструкции языка - получают данные через входы, производят их обработку и выводят данные с помощью выходов. Как только значения параметров поступают на каждый из входных терминалов узла, происходит выполнение кода узла (обработка поступивших данных), после чего значения выходных параметров оказываются доступными на выходных терминалах узла для дальнейшей их передачи на другие узлы согласно логике потока данных. Соответственно, из двух последовательно связанных узлов, второй сможет быть выполнен только после получения данных от предыдущего.
Интуитивное использование средств графического языка
Как и большинство людей, многие инженеры и ученые решают поставленные перед собой задачи, оперируя образами или символами. Подобный поход развивается в процессе обучения и применения соответствующих инструментов обработки информации – различных схем и диаграмм. Однако большинство языков программирования требуют изучения специфического синтаксиса и адаптации моделей прикладной области к возможностям языка. В тоже время, графический язык G позволяет работать с интуитивно понятными структурами.
Код языка LabVIEW удобнее для инженеров и ученых, потому что они привыкли к визуальной работе с данными, моделированию процессов с помощью блок-схем и диаграмм состояний, которые так же отражают потоки данных. Помимо этого, потоковое программирование обусловливает необходимость работать в терминологическом поле прикладной области задачи. Например, типичное приложение на LabVIEW сперва получает данные с нескольких каналов датчиков температуры, затем передает данные функции, выполняющей анализ, и, наконец, сохраняет данные на диск. Графическое представление программы наглядно демонстрирует порядок выполнение операций и потоки данных.
Интерактивные средства отладки
Поскольку концепция языка G проста для понимания, LabVIEW предоставляет в распоряжение пользователя столь же удобные и интуитивно понятные инструменты среды разработки. Например, уникальные средства отладки позволяют наглядно отобразить процесс распространения данных по проводникам, а также отобразить соответствующие значения на входах и выходах узлов кода (речь идет об анимации выполнения).
Кроме того, LabVIEW предоставляет разработчику набор инструментов отладки, аналогичных имеющимся в других средах разработки. С помощью пиктограмм на инструментальной панели блок-диаграммы вы можете запустить пошаговое выполнение кода, установить точки остановки и включить анимацию выполнения.
Отладочные средства позволяют установить пробники одновременно на многих участках программы, приостановить выполнение и выполнить вход в подпрограмму. Подобный функционал есть и в других средах разработки, однако LabVIEW, благодаря графической сути языка G, в более удобной форме отображает текущее состояние программы и взаимосвязи параллельных участков кода.
Одна из отличительных особенностей процесса отладки в LabVIEW – это скрытое компилирование кода. Пока вы работаете с кодом, компилятор постоянно проводит семантический и синтаксический анализ кода. В случае обнаружения ошибок, блокируется возможность выполнения программы, а на инструментальной панели отображается пиктограмма со сломанной стрелкой.
Автоматическое распараллеливание
Языки потокового программирования, такие как LabVIEW, позволяют автоматически распараллеливать выполнение кода. В отличие от языков с последовательным выполнением команд, таких как C и C++, графические языки изначально содержат в себе информацию о том, какие участи кода следует выполнять параллельно. Рассмотрим, к примеру, шаблон проектирования «Производитель/Потребитель», в котором два цикла While выполняются независимо: первый цикл генерирует или получает данные, а второй – обрабатывает их. Несмотря на то, что циклы выполняются параллельно, данные между ними успешно передаются с помощью механизма очередей, которые поддерживаются и в стандартных языках.
Параллелизм также позволяет увеличить производительность программ. В настоящее время становится все более популярной новая архитектура процессоров - многоядерные процессоры.
Чтобы до конца использовать все преимущества многоядерной архитектуры процессора, программы должны содержать участки кода, которые могут выполняться независимо (т.е. быть многопоточными). В обычных текстовых языках создание и управление потоками является сложной задачей для неопытного специалиста в программировании.
Явное преимущество языка LabVIEW по сравнению с обычными текстовыми языками программирования заключается в том, что реализация многопоточных приложений является весьма простой задачей. Встроенный компилятор самостоятельно определяет участки кода, имеющие параллельно расположенные узлы, и организует раздельные потоки для их параллельного исполнения. В компьютерной терминологии такой механизм называется «неявный параллелизм», т.е. реализация параллелизма осуществляется автоматически средствами разработки, а не специально написанным кодом.
Помимо поддержки многопоточности на многоядерных системах, LabVIEW позволяет создавать приложения для параллельных вычислений на ПЛИС – интегральных микросхемах с программируемой логикой, в которых выполнение независимых участков кода организуется абсолютно независимыми участками микросхемы, которые не влияют на производительность друг друга. LabVIEW очень хорошо подходит для программирования ПЛИС, потому что в его основе лежит работа с параллельными потоками данных. Именно поэтому он становится всё более популярным среди разработчиков, которым требуются параллельные детерминированные вычисления.
Уровень абстракции низкоуровневых операций
В примере с языком FORTRAN было показано, что уровни абстракции, обеспечиваемые языками высокого уровня – их главное преимущество, которое проявляется в более наглядном виде кода по сравнению с низкоуровневыми языками. LabVIEW автоматически обеспечивает выполнение ряда задач (например, управление памятью), которое в текстовых языках обычно ложится на плечи разработчика. В подобных случаях вы самостоятельно должны обеспечить выделение памяти перед ее использованием и освобождение – после, а также следить за тем, чтобы не выйти за границы выделенной области.
Автоматическое управление памятью – одно из главных преимуществ языка LabVIEW. Когда вы пишите программу на графическом языке программирования, вам не нужно ни выделять память для переменных, ни присваивать им значения. Вместо этого, вы создаете блок-диаграмму, отражающую движение данных. Узлы блок-диаграммы, которые генерируют данные, автоматически обеспечивают выделение памяти для данных. Высвобождение памяти происходит автоматически после того как данные оказываются не нужны. Как только вы добавляете дополнительные данные в массив или строку, вызываются процедуры выделение дополнительного объема памяти. Таким образом, вы можете сосредоточиться на решении поставленной задачи, а не разбираться в тонкостях языка и не допускать ошибок при программировании.
В то же время, если вам необходимо управление памятью на низком уровне, вы можете задействовать встроенные утилиты мониторинга использования памяти, чтобы оценить эффективность разных техник программирования.
Если программа на LabVIEW демонстрирует неожиданные результаты, вы можете воспользоваться как упомянутыми выше средствами отладки, так и инструментарием для продвинутых пользователей, а именно – тулкитом Desktop Execution Trace Toolkit, который позволяет провести динамический анализ кода на наличие:
• Утечек памяти и ошибки ссылок/указателей
• Участков кода, вызывающих не желаемое поведение программы
• Участков программы, на которых может быть увеличена производительность
• Определение вызова предшествующего ошибке
• Сравнение работы кода на разных платформах
Интеграция LabVIEW с другими языками
Несмотря на то, что LabVIEW идеально подходит для организации распараллеливания кода, а также скрывает тонкости управления памятью, он не является наиболее оптимальным выбором для решения некоторых задач. В частности, математические формулы и уравнения могут быть более наглядно представлены в текстовом виде, поэтому в LabVIEW реализованы механизмы добавления на блок-диаграмму текстового кода.
Например, в LabVIEW есть узел, называющийся Formula Node, который позволяет рассчитывать значения по текстовым формулам и выполнять текстовые программы с C-подобным синтаксисом.
Оптимальный способ решения ваших задач
Графический язык и концепция потокового программирования LabVIEW позволяет вам решать задачи более удобными и эффективными методами, чем традиционные текстовые языки. Ключевые особенности программирования на языке LabVIEW, а именно интуитивно понятный и наглядный графический код, а также управляемое потоком данных выполнение программы, позволяют сделать процесс программирования более близким к процессам мышления, чем другие языки. Несмотря на высокий уровень абстракции кода, производительность программ, написанных в среде LabVIEW, остается сопоставимой с языками типа C, благодаря встроенному компилятору кода.
Читайте также: