Большинство сред визуального программирования не находят достойного применения. Как вы думаете, почему? Они нацелены на замену синтаксиса кода и бизнес-логики, но разработчики никогда эти аспекты не визуализируют. Напротив, они визуализируют переходы состояний, схемы распределения памяти или сетевые запросы.
На мой взгляд, те, кто работает с визуальным программированием, гораздо больше преуспеют, если начнут с аспектов программного обеспечения, которые разработчики уже визуализируют.
▍ Контекст
Каждые несколько месяцев кто-нибудь да выпускает очередной красивый язык визуального программирования, который выглядит, например, так:
Конкретно этот смотрится очень лаконично, притом что большинство куда менее привлекательны.
Показанный алгоритм заменяет следующий псевдокод1:
def merge_sort(a):
if (length(a) == 2):
if (a[0] < a[1])
return a
else
return [a[1], a[0]]
else:
[x1, x2] = split_in_half(a)
sorted_x1 = merge_sort(x1)
sorted_x2 = merge_sort(x2)
return priority_merge(sorted_x1, sorted_x2)
Как и в примере выше, системы, о которых я говорю, пытаются заменить сам синтаксис кода.
Но всякий раз, когда эти визуальные системы появляются, мы думаем «как прикольно!», так их и не используя. Я ещё не видел, чтобы какая-нибудь из них хоть раз упоминалась при попытке решить какую-либо задачу. Почему? Почему мы продолжаем возвращаться к визуальному программированию, если его никто не использует?
Одна из причин в том, что, по нашему мнению, оно поможет менее опытным программистам. Если бы только его код не был столь пугающим. Если бы он был визуальным. Самым популярным языком программирования является Excel Formula, который выглядит так:
=INDEX(A1:A4,SMALL(IF(Active[A1:A4]=E$1,ROW(A1:A4)-1),ROW(1:1)),2)
Я проигнорирую эту причину, потому что многие аналогичные инструменты явно предназначены для опытных разработчиков. Они предполагают, что вы будете устанавливать их через
npm install
или развернёте в AWS Lambda.Почему визуальное программирование не заходит разработчикам?
Разработчики говорят, что хотят «визуальное программирование», и ты начинаешь думать «ага, давайте заменим
if
и for
». Но никто никогда не создавал схему программы для чтения for (i in 0..10) if even?(i) print(i)
. Знакомые с кодом разработчики уже ценят и понимают текстовые представления для чтения и записи бизнес-логики2.Давайте лучше посмотрим, что разработчики именно делают, а не говорят.
Разработчики уделяют время визуализации различных аспектов кода, но редко самой его логике. Они визуализируют другие стороны ПО, которые являются важными, неявными и трудными для понимания.
Вот некоторые примеры визуализации, которые я часто встречаю в серьёзных контекстах:
- Различные способы визуализации базы кода в целом.
- Схемы подключений компьютеров в сети.
- Схемы размещения данных в памяти.
- Схемы переходов конечных автоматов.
- Swimlane-диаграммы для протоколов, работающих по принципу запрос/ответ.
Вот такое визуальное программирование интересует разработчиков. Специалистам нужна помощь именно с этими задачами, для решения которых они прибегают к визуальным представлениям.
Если вы скептично настроены в отношении подобных решений, позвольте спросить: «Вам известно, как в точности размещены данные в памяти вашей системы?» А ведь неудачное размещение данных в памяти является одной из основных проблем падения производительности. При этом очень трудно «увидеть», как именно конкретный элемент данных размещён, и сопоставить это с паттернами доступа в базе кода.
Или ещё вопрос: «Известны ли вам все внешние зависимости, которые задействует ваш код, отвечая на HTTP-запрос? Вы уверены? А вы не заметили, что Боб недавно добавил вызов в сервис ограничения скорости передачи в промежуточном ПО?» Не беспокойтесь, вы узнаете об этом при следующем сбое.
Для обоих вопросов ответом обычно будет: «Я думаю, что знаю» с затаившимся страхом, что, возможно, вы всё-таки упустили нечто, что не смогли увидеть.
К сожалению, большинство визуализаций:
- Делаются наспех.
- Составляются вручную на салфетке или с помощью Whimsical.
- Редко интегрируются в стандартный рабочий поток.
Это не говорит о том, что в индустрии нет достойных решений. Некоторые техники визуализации интегрируются в среды разработки и используются очень активно:
- Инспектор просмотра элементов DOM.
- Flame-графики в профилировщиках.
- Диаграммы SQL-таблиц.
Но всё это исключения, а не что-то распространённое. Разве не круто, когда вы можете выявить проблему производительности по flame-графику? И нам нужна эта возможность для всего.
Далее я расскажу о некоторых из этих визуализаций, чтобы вы могли рассмотреть их использование в своей текущей работе или даже интеграцию в существующие среды разработки.
▍ Визуализация базы кода
В этом прекрасном выступлении показано множество способов визуализации различных аспектов базы кода. Множество! Вот несколько интересных конкретно для меня:
- Sourcetrail: иерархия классов и браузер зависимостей.
- Treemap: статистический обзор файлов в базе кода.
- Периодическое сохранение кода.
▍ Sourcetrail
Sourcetrail – это опенсорсный инструмент для визуализации баз кода (закрыт), написанный спикером из выступления выше. Вот прекрасный обзор того, как этот инструмент помогает перемещаться по базе кода. Выглядит он так:
Sourcetrail решает множество типичных проблем дизайна при визуализации кода:
- Он показывает визуализацию рядом с кодом, при наведении на который подсвечивается соответствующая визуальная часть. И наоборот, при наведении на диаграмму, подсвечивается код. Клик по зависимости переводит вас к отвечающему за неё коду (например, когда одна функция вызывает другую, или один модуль требует другой).
- Причём этот инструмент продуманным образом скрывает информацию. В базах кода зачастую присутствует слишком много связей для одновременной визуализации. Sourcetrail же изначально показывает только то, что вы, по его мнению, ищите, и для вывода дополнительной информации просит либо кликнуть, либо навести куда-либо. Его интерфейс построен так, чтобы подтягивать потоки, которые кажутся интересными, а не получать общий обзор всей базы кода. Этим он отличается от описанного далее Treemap, который сделан как раз для получения общего представления.
Однако, как показывает демо, Sourcetrail присущ ряд типичных проблем, связанных с подобным способом визуализации:
- Нет очевидных указаний на то «когда этот инструмент может понадобиться». Выполняя профилирование, вы думаете: «Мне нужен flame-граф». А когда вам нужна эта визуализация?
- Он не присутствует в тех инструментах, которые я хочу использовать. В демо показано, как пользователь переключается между Sourcetrail и Sublime. Этот тип визуализации кода и навигации по нему должен находиться внутри редактора.
▍ Treemap
В этих видео Джонатан Блоу реализует «карту дерева» для инспектирования различных аспектов кодовой базы. Исходя из видео (я его вьюер не использовал), последняя версия выглядит так:
- Каждый квадрат здесь представляет файл кода.
- Размер квадрата отражает размер файла.
- Цвет квадрата представляет смесь метрик в каждом файле вроде глубины вложенных
if
, глубины вложенных циклов, количества глобальных считываний и так далее.
С помощью подобной визуализации можно отражать и прочие метрики
(size, color)
в отношении базы кода, например, (code_size, code_quality)
, (code_size, heap_access / code_size)
и тому подобное.Даже если вы визуализируете нечто совсем простое вроде
code_size
без цвета, это может оказаться очень полезным при онбординге сотрудников для работы над массивной базой кода. Типичный монолит в крупных технологических корпорациях может выглядеть так:packages/
first_dependency/
first_transitive_dep/
second_dependency/
second_transitive_dep/
...
src/
bingo/
papaya/
lmnop/
racoon/
wingman/
galactus/
...
Вы наверняка бегло просматривали такие. Я тоже так делал, когда устраивался в крупную компанию. Когда вы клонируете такой репозиторий и просто по нему пробегаетесь, то по факту не понимаете, что конкретно в нём находится, даже в общих чертах. В примере выше оказывается, что бо́льшая часть кода находится в сервисе
racoon/
(3M строк кода) и second_transitive_dep/
(1M строк кода). Всё остальное занимает менее 300К строк и сопоставимо с ошибкой округления. Вы можете работать с такой базой кода годами, не понимая этих базовых фактов.▍ Диаграмма сохранения кода
Работа Рича Хики «History of Closure» содержит несколько интересных визуализаций, которые помогают понять, как базы кода Clojure развивались со временем. Вот диаграмма сгорания задач, сгенерированная Hercules CLI:
- Код, написанный в течение каждого конкретного года, представлен здесь своим цветом (например, для 2006 это красный).
- Если какой-то код удаляется или заменяется на код следующего года, его участок удаляется.
- Отслеживая цвета, можно видеть остаточный объём кода по годам. Например, код 2006 года (красный) был преимущественно удалён или заменён. А вот код 2011 года (зелёный) с момента своего написания остался практически нетронутым. То же касается почти всех лет3.
▍ Компьютерные сети и топологии сервисов
Если вы когда-нибудь начнёте использовать AWS, то заметите, что документация этой платформы полна диаграмм вроде следующей:
Думаю, эта диаграмма весьма наглядна. Она показывает все задействованные «сервисы» и их связи. В этом случае, если вы знаете, что каждый из них делает, то их взаимосвязанность будет очевидной. (Если же не знаете, придётся читать о каждой).
За время своей карьеры я составлял подобную топологическую схему для каждой команды, в которой работал, и усвоил несколько уроков:
- По мере присоединения новых людей я начинал с последней созданной схемы (в среднем за шесть месяцев), что упрощало задачу. С последнего раза также происходили кое-какие изменения.
- Каждый раз при составлении диаграммы я упускал что-нибудь важное.
- Насколько понимаю, это был самый важный технический артефакт, который я когда-либо передавал новым участникам команды.
Вопрос: «Если вы используете определения сервисов gRPC, то можете ли генерировать на их основе диаграммы?»
▍ Схемы памяти
В этой теме Reddit участник задал вопрос, пытаясь понять схему распределения памяти указателей Rc<T>:
Привет! Хочу понять схему памяти при выполнении следующего фрагмента кода из стандартной библиотеки:
use std::rc::Rc; let vec_var = vec![1.0, 2.0, 3.0]; let foo = Rc::new(vec_var); let a = Rc::clone(&foo); let b = Rc::clone(&foo);
Я представил себе примерно следующую картину её распределения. Верна ли она? Спасибо!
На это один из пользователей ответил такой схемой:
Заметьте, что изначальный код не изменился. Единственное, что указано в ответе – это скорректированная диаграмма. Дело в том, что для задавшего вопрос схема является более эффективной формой представления его мысленной модели, поэтому её корректировка влияет именно на эту модель, но не на сам код.
Завершается обсуждение так (выделение моё):
Здравствуйте! Благодарю за то, что пролили свет на мой вопрос.
Вот почему важно визуальное программирование: оно зачастую отражает то, что люди представляют у себя в голове (или пытаются представить). Генерация хорошей схемы позволяет прояснить картинку в уме.
В книге «Programming Rust» очень активно используются схемы распределения памяти:
Вопрос: «Можете ли вы сгенерировать эти диаграммы прямо из аннотаций типа struct
?»
В этом языке есть ещё один способ «распределения памяти»: его модель владения. Независимо от формы и размера данных в памяти, различные ссылки «владеют» другими ссылками, формируя таким образом дерево. Принцип владения лучше всего описывается этой схемой из «Programming Rust»:
Вопрос: «Можете ли вы генерировать деревья владения на основе исходного кода Rust?»
▍ Конечные автоматы
Эти штуки довольно стандартны. В документации Idris с их помощью демонстрируют, о чём пойдёт речь, когда предстоит раскрыть тему новых принципов моделирования конечных автоматов в системе типов. Я считаю, что этот пример полезен на двух уровнях:
- Если вы знакомы с диаграммами переходов состояний, то сможете с ходу понять происходящее.
- Вы, скорее всего, не знакомы с нотацией кода конечного автомата, поэтому будет очень кстати иметь для него альтернативный вариант представления.
Вопрос: «Можете ли вы генерировать эти диаграммы напрямую из аннотаций типов Idris?»
Но вам не нужно придерживаться строгих диаграмм конечных автоматов из универсального языка моделирования. Для чего используются эти состояния?
PaymentIntent является основным объектом, который Stripe использует для представления выполняющегося платежа. С платежом может произойти очень многое, в связи с чем в этом инструменте реализован довольно сложный конечный автомат. Мы с Мишель Бу и Изабель Бенсусан в 2019 году составили для этого механизма вот такую диаграмму конечного автомата, которая показана ниже. Тогда это была одна из первых «диаграмм» в его документации.
Она отражает различные состояния, в которых может находиться
PaymentIntent
, сопровождая каждый своим UI:Занятный пример конечных автоматов и их формализации показан в лекции Лесли Лампорта на тему коммита транзакций в TLA+.
▍ Swimlane-диаграммы для визуализации обмена запросами/ответами
Клиент-серверная архитектура на основе запросов/ответов может становиться очень сложной, и я нередко видел, как люди создают для их отслеживания swimlane-диаграммы.
Вот хороший пример из документации Stripe. В нём показаны все запросы/ответы, происходящие, когда клиент оформляет заказ, сохраняет выбранный способ оплаты и, собственно, платит:
Если вы такой ещё не видели:
- В столбцах указан тот, кто выполняет запрос (компьютер или человек).
- Каждая рамка – это действие, которое они могут выполнить.
- Каждая стрелка – это запрос/ответ между ними.
- Время, проходящее по мере выполнения запросов.
Такие схемы прекрасны. Здесь виден порядок запросов, зависимости между ними, кто и что делает и так далее. Важно то, что когда при написании кода вы видите подобный фрагмент:
const r = await stripe.confirmPayment();
то можете найти соответствующий ему запрос и просмотреть контекст, в котором он происходит, даже если в окружающем коде этого контекста нет.
Адриенна Дрейфус усердно потрудилась, чтобы создать и стандартизировать эти диаграммы в документации Stripe.
Вопрос: «Можете ли вы генерировать эти диаграммы непосредственно из комплексных тестов, которые написали для своего сервиса?»
Этот пример не отражает временну́ю составляющую при передаче сообщений. Обратите внимание, что стрелки направлены горизонтально. Но эту же диаграмму можно использовать для диагностирования состояний гонки и прочих багов, связанных с выходом из строя или проблемами тайминга.
В Aphyr зачастую используют собственную версию swimlane-диаграмм, чтобы показать, как различные процессы рассматривают состояние в распределённой системе. Например, в анализе Jepsen VoltDB 6.3 они показывают, как различные узлы базы данных могут обмениваться сообщениями:
В этой версии диаграммы для понимания проблем системы очень важно понимать продолжительность времени между запросами.
В той же статье показана интерактивная диаграмма по типу swimlane, визуализирующая результаты, полученные от инструмента Jepsen:
- Теперь каждая «дорожка» является горизонтальным, пронумерованным рядом (10, 11, 18), представляющим процесс, который считывает или записывает данные.
- В рамках отражены операции процессов, требующие время для своего завершения. Линии представляют логические связи между данными, которые процессы видят. Линии, которые нарушают линейность, отмечены недопустимыми и окрашены красным.
Ещё один крутой пример есть в документации алгоритма Double Rachet мессенджера Signal. Эти диаграммы отслеживают, что конкретно Элис и Бобу необходимо на каждом шаге работы протокола для шифрования и дешифровки очередного сообщения:
Этот протокол достаточно сложен, чтобы я мог воспринять его диаграммы как источник истины. Иными словами, если реализация алгоритма Double Rachet вдруг сделает что-либо, противоречащее диаграммам, то ошибка, скорее, окажется в коде, а не в них. Именно в перечисленных областях, на мой взгляд, визуальное программирование должно являться актуальным средством, но эта тема уже для другой статьи.
▍ Сноски
1. Я не знаю, верен ли код выше – таким я его вывел на основе диаграммы. ↩
2. Это стандартная критика систем визуального программирования, и, на мой взгляд, в этом случае толпа права. Но почему люди продолжают возвращаться к этой технологии? Что им следует делать вместо этого? ↩
3. У Рича также есть отличная презентация истории Clojure, где он рассказывает, почему эти диаграммы сгорания задач выглядят именно так: Clojure с целью сохранения стабильности кода старается избегать его переписывания, за исключением случаев исправления багов.↩
Telegram-канал со скидками, розыгрышами призов и новостями IT ?
Комментарии (91)
LordDarklight
17.07.2024 14:09+12Визуальное программирование как полностью самостоятельное направление вряд ли когда-нибудь взлетит. На то есть несколько причин:
Так уже исторически сложилось, что людям проще работать с текстами и под это активно затачивались все текстовые процессоры и IDE - читать и вводить буквы просто проще, как и выполнять разные операции над текстами. Да - визуализация как бы считается более лёгкой для восприятии - но об этом ниже. Да - можно попробовать создать удобную и очень продвинутую IDE и натаскать на неё человека - но уверен сложность такой среды будет куда выше чем у текстового процессора! Хотя, может и удастся с ней работать хорошо натасканному специалисту достаточно просто!
Компьютерным алгоритмам так же куда проще работать именно с текстовым преставлением - и тут вообще ничего не изменится. Кроме того - роль автоматизированной обработки текстов с каждым десятилетием будет расти и расти!
С текущими средствами ввода и манипулирования данными - человеку куда проще вводить данные (алгоритмы) с клавиатуры, чем, скажем, мышью. Вот когда разработают что-то более продвинутое для ввода - может что-то и изменится. Но даже силой мысли или в VR оперировать текстами, мне кажется, по-прежнему будет проще...
Действительно, визуализация очень хорошо может восприниматься человеком... но.... только до определённого уровня сложности - затем происходит перелом и обратный процесс - восприятие резко падает. И все попытки разбивать визуализацию на кластеры детализации только усложняют детальный анализ. Да - сложные тексты тоже бывает очень непросто анализировать и воспринимать. Но тут есть методики по их написанию и средства упрощения их преставления и анализа, и ориентирования по таким текстам - и они хорошо работают!
Визуализация алгоритмов только может стать хорошим подспорьем в стандартных текстовых IDE как отдельный инструмент - либо для простых алгоритмов и новичков, либо как дополнительное средство анализа кода - например при поиске ошибок - т.к. позволяет эффективно визуализировать движение по коду в динамике, в т.ч. в виде активной схемы в реальном времени выполнения!
-
Так же визуализация может быть удобна для ряд узких задач программирования или для представления данных: это нейросети и какой-либо кластерный анализ
LordDarklight
17.07.2024 14:09+2Забыл добавить ещё три очень важных пункта:
Этот пункт - дополнение к 1. Более менее простую визуальную схему нарисовать достаточно легко. Но - как только начнёт расти количество элементов - первое с чем все сталкиваются - это как размещать это всё на плоскости и как размещать связи между бллками. Это реально очень большая проблема - когда рисуются комплексные схемы - банально - как это всё структурировать на 2D, квази 3D, настоящем 3D. Спросите любого схемотехника - для него это головная боль. Да, для рисования, условно, электрических схем есть продвинутые IDE - помогающие с эффективным расположением элементов - но не решающие эту проблему. А схемы чертят уже очень давно...
Но даже если Вы всё эффективно разместите - и тут нате... нужен рефакторинг, ну или просто изменения в логике алгоритма - и даже пусть продвинутая IDE вам позволит технически (это уже другая проблема - см. п.1) быстро изменить логику - но свою красивую визуализацию Вы тут же поломаете - и всё придётся ровнять заново!
С текстами всё проще - есть несколько прямых рекомендаций и правил а-ля "чистый код" - но даже если их соблюдать - условно тексты просто структурируются сверху вниз - иногда немного вправо - и всё. Да тут тоже есть свои нюансы и недостатки восприятия 0 но современные IDE активно пытаются их решать! И здесь есть ещё что совершенствовать и куда развиваться!Повторное использование кода, сборка комплексных элементов из отдельных модулей, файлов, да и просто разных частей - расположенных в разных местах - это всё реалии современности - код перестал быть строго линейным - он может быть разбросан по проекту, по библиотекам проекта - и собираться по кусакам (пример - да хоть частичные классы, или методы, вынесенные за пределы определения структуры класса), а изначальна описываться очень абстрактно. Текстовое представление отлично к этому приспособлено. А вот у графического тут явно будут большие проблемы именно на стадии исходника - конечно представить уже собранное решение графически будет уж "не так сложно" (но см. пункт 8.),
Так же и обратное - декомпозировать сложный текст - не так уж сложно - декомпозировать сложное визуальное представление - это кошмар...Сейчас разработкой рулит Git ну или в общем случае - версионирование кода - со всеми инструментами сравнения, объединения, пул-реквестов и веток. И для текстового представления всё это подходит отлично! А вот с графическим представлением будет большая жоп.... Особенно кода решение в итоге собирается из нескольких источников и так же из нескольких источников обновляется... Я не говорю о том, что для графической визуализации проводить сравнение и мердж невозможно - тут могут быть и свою интересные фишки - но проблем, всё-равно, будет куда больше, чем с текстами...
Поэтому сейчас наоборот - в разработке есть обратная тенденция - там где раньше рисовали схемы визуальными средствами - сейчас переходят на текстовый кодинг. Начиная от UML XML и до DocHub. Да хоть посмотрите и формат векторных изображений SCV.
И я сейчас, порисовав некоторое время кучу схем визуальными средствами - уже видеть все этм редакторы не могу - это просто убожество - и хочу далее рисовать схемы только текстом! То же и про векторную графику - дайте мне лучше редактор с командами для рисования графических элементов!
То же и про UI формы: XAML, Jet compose, Swift UI, Flatter - Это всё прекрасно (хотя синтаксис я бы ещё существенно доработал бы - и с текстами провести такие доработки, в т.ч. переписав компиляторы, будет провернуть куда проще, чем с графическими системами)!
Отдельно замечу про... устный ввод! Вроде бы есть тенденция к возможности реализации ввода программного устным набором - начитка! Лично я не сторонник такого подхода (хотя устный ввод может быть хорошим подспорьем для рефакторинга и управления прочим инструментарием IDE). Но я считаю так - что при устном вводе (и тем более при вводе силой мысли) грань между способом текстового кодирования и визуального рисования уже сильно стирается (с учётом конечно несколько разных техник команд общения и очень продвинутой IDE, которая эффективно будет решать проблемы восприятия и авто визуализации). При этом со стороны наблюдать за графическим представление отчасти может быть даже удобнее чем за текстовым! Но... до этого ещё очень далеко - и, лично мой мнение, что бы так не вводилось - текст или визуальные схемы - это всё-равно будет менее эффективно - чем прямою ввод руками с клавиатуры (или как-то ещё иначе - но с точным преобразование механики нервных импульсов к текстовый поток); и тем более - если такой символьный поток ещё и параллельно дополнить вербальными командами лица, для управление IDE и интеллектуальным помощником ввода!
ef_end_y
17.07.2024 14:09Это все так, но есть вариант транслировать прямо в мозг
LordDarklight
17.07.2024 14:09В каком виде?
Это только на словах звучит эпично
ef_end_y
17.07.2024 14:09Если б я знал будущее... Во-первых разработки взаимодействия напрямую с мозгом уже ведутся, а во-вторых прогнозировать как оно в будущем - такое себе занятие, обычно мало у кого получается зайти дальше "ну, эта штука будет в Х раз быстрее, и У раз меньше"
LordDarklight
17.07.2024 14:09Вопрос то был не про техническую часть - а как раз пофантазировать о том, как это визуально т.е. с практической стороны восприятия могло бы быть - ну и сделать оценки эффективности такого решения!
А насчёт технической части - да в мозг лезу уже сейчас - и, возможно, когда-то научатся очень умело им манипулировать (так что будущее "Матрица" покажется Вам раем, а вот будущее "Континуум", или" 2035: Город-призрак" - очень пугает, так что может не надо?) - но, думаю, это ещё очень и очень не скоро... ту скорее программы сами себя быстрее начнут писать - и человек тогда вообще не понадобится!
Groramar
17.07.2024 14:09+2Основная проблема - сложность. С проектом в миллион строк кода я обращаюсь достаточно легко, но проектом даже в тысячи визуальных инстансов мне кажется будет не подъемным для понимания
SadOcean
17.07.2024 14:09+4Согласен в целом со статьей.
В моей области (геймдев) есть много попыток использовать визуальное программирование, самое известное наверное Unreal Blueprints - визуальный язык для Unreal engine.
Но все это считается несерьезным по целому ряду причин.
Я думаю самая важная - быстро растущая комплексность делает эти диаграммы совершенно нечитаемыми паутинами, а средств организации кода, подобных модулям не придумали. Точнее что-то придумали, но использовать сложно, что противоречит идее "легкого входа". В итоге классический код становится хорошим компромиссным решением между сложностью написания, чтения и распознавания взаимосвязей.
Но есть много специализированных областей, в которых это может быть оправданно:
- Редакторы шейдеров. Их можно писать кодом, но в визуальном программировании можно получить визуализацию промежуточных результатов, что обеспечивает глубокое понимание и легкую отладку того, что ты делаешь
- Редакторы анимаций (по сути машины состояний) - аналогично, даже большие деревья все еще доступны для понимания, все узлы более менее однообразны.
- Часто делают редакторы квестов/диалогов в виде деревьев. Тут нужно упомянуть, что хотя это и распространенное решение, так же часто используются и DSL, где это описывается обычным текстом. Например многие чатботы содержат деревья с визуальным программированием для начинающих, но более продвинутые версии все равно описываются через DSL
- Я делал даже небольшой ЯП для геймдизайнеров на объектах, хотя по структуре он был ближе к scratch - скорее там были последовательности команд списками, нежели деревья или визуальное программирование. На самом деле основной плюс такого языка был в том, что не нужно было знать синтаксис, только основные принципы. Команды и переменные выбирались из списка.
В общем потенциал велик, но на пути использования визуального программирования есть серьезные проблемы, которое даже классическое программирование не научилось решать.
И рано или поздно это упирается в самую главную проблему обычного программирования - войну со сложностью.
И если для больших систем это научились худо-бедно решать, то с визуальным программированием беда.aldekotan
17.07.2024 14:09Я надеюсь, что визуальное программирование останется как явление и будет развиваться, так как на личном опыте использования тех же Блупринтов и FlowGraph из CryEngine (даже не знаю, остались ли они там, давно не пользовался) заметил, как подобные инструменты упрощают работу не специалистам, вроде меня. Т.е. на лицо большая специализация/упрощение, ценой сокращения возможностей.
Классическое же программирование, на мой взгляд, требует более основательного подхода, хотя и даёт больше возможностей. Нельзя просто вытянуть ноду PrintString и вписать туда нужный текст, для начала нужно решить, через что этот текст будет выводиться и есть ли у программы вообще окно вывода.
Sadler
17.07.2024 14:09+1В моей области (геймдев) есть много попыток использовать визуальное программирование, самое известное наверное Unreal Blueprints - визуальный язык для Unreal engine.Но все это считается несерьезным по целому ряду причин.
Лучше бы Epic-и дали нормальный скриптовый язык со знакомым синтаксисом, не требующий перекомпиляции после каждого изменения. А то либо Blueprints, которые сложно использовать с git, которые ломаются в неожиданных местах при рефакторинге и легко превращаются в спагетти, либо C++, который иногда(!) умудряется собраться через live coding (иногда при этом ломая связанные blueprints), но чаще требует закрывать unreal и перекомпилить (генерируя pch и прочих Intermediate на десятки GB и тормозя рандомное время, от 3 сек до получаса), не отлаживается в окне unreal, крашит редактор в случае банальной ошибки в коде.
inkelyad
17.07.2024 14:09+6Программирование не в одиночку - это VC, сравнение и слияние изменений от разных людей, разрешение конфликтов, ревью кода. И если формат текстовый - то есть мешок инструментов, что все это умеют делать. А вот для визуального отображения придется все это писать практически заново. Желающих мало.
Fushigi
17.07.2024 14:09+3В статье всё намешано. Заголовок про визуальное программирование, но говорим о визуализации кода и данных. Это так то разные вещи.
Мне кажется визуальное программирование потихоньку взлетает - то тут, то там графовые редакторы вполне неплохо справляются. Главная проблема, имхо, что часто в таких графах пытаются решить низкоуровневые задачи. Отсюда макароны и малая скорость.
Визуальное программирование должно быть только для высокоуровневых задач. Подкреплено снизу хорошей кодовой базой. И тогда это будет такой же шаг в разработке, как когда-то был от ассемблера к С
NickDoom
17.07.2024 14:09+3«Балет на льду и хоккей на траве» ®©™.
С маниакальным упорством люди пытаются описать логические элементы текстом (VHDL), а алгоритм — диаграммами.
Начните с визуального «программирования» ПЛИС, может, дальше-то и идти не придётся?
user87644
17.07.2024 14:09Написание кода уже "визуальное", просто образы в голове, а не на бумаге. Что-то трудно представимое, обычно, дополняется комментарием, названием алгоритма, ссылкой и т.п., где картина достраивается. А тут, получается и то, что обычно напечатано, и то, что обычно в голове, переносится на лист, отчего общая картина очень быстро вырастает в размерах. Для какой-то простой кастомизации поведения сойдет.
qbertych
17.07.2024 14:09+5Рассуждения про бесполезное визуальное программирование без единого слова о Labview, у которого нехилая такая доля рынка промышленной автоматизации - ну такое.
engin
17.07.2024 14:09+2Сегодня LabVIEW стал де-факто стандартом разработки инженерных систем и прочно занял свою нишу. С развитием робототехники, скоро LabVIEW он выйдет за рамки простой среды для инженеров и станет доступной всем желающим сделать свою систему. Чем собственно и занимаюсь.
aldekotan
17.07.2024 14:09Читаю про Labview и понимаю, что мечтал о таком инструменте всё это время. Спасибо, что упомянули!
Хоть я и сижу в геймдеве, всегда тянулся к визуальным языкам (FlowGraph в CryEngine, BluePrint в UnrealEngine), а здесь вижу, что всё организовано значительно серьёзнее. Может, смогу применить и в своей работе)
vk6677
17.07.2024 14:09В ПЛК популярны диаграммы и функциональные блоки. Но сложные проекты лучше "текстом" писать.
Format-X22
17.07.2024 14:09+3Обратите внимание - этот комментарий, другие комментарии, эта статья, эта страница хабра… оно всё из текста. Да, в случае страницы есть интерфейс, а в статье даже есть картинки. Но всё же задумайтесь - сейчас вы читаете этот комментарий текстом. Почему же никто не пишет комментарии картинками? Вот то то и оно.
Дело в том что мы все имеем опыт в тексте частенько лишь на лет 5 меньше нашего возраста. А самый удобный инструмент тот с которым ты уже давно успешно работаешь, а ещё с ним работают миллионы людей в рамках языка и миллиарды в рамках текста вообще. Если бы мы рисовали картинками слова… то получились бы иероглифы, которые используются также парой миллиардов людей. При этом они также упрощены до штрихов и простых символов. Даже в виде картинок это текст.
Визуальное программирование не эргономично также как написание этого комментария визуальными объектами с линиями - это возможно, но категорически не практично. Не говоря уже о том что на клавиатуре есть куча символов и ввод линеен, как и чтение. А вот с картинкой он многонаправлен, многомерен. Человеческое восприятие конечно может так, но это сложнее.
Картинки конечно нужны. Но они как пояснение. Действительно - некоторые вещи лучше зарисовать. Не хватает языкам программирования дополнений в виде зарисовок либо крупно-архитектурных моментов, либо наоборот микро… с другой стороны рефакторить и усложнять такое по мере развития проекта - это боль. Потому зарисовать в документации это ок, а вот тащить в код - сомнительно. В конце концов сколько существует книг, поставляемых в формате текста без всего, и всё там прекрасно. Лишь некоторые вставляемые иллюстрации, например фотографии. Или опять же те же общие абстрактные схемы.
Текст идеально подходит для описания и понимания. Невозможно создать полноценный язык программирования в визуальном виде по фундаментальным неразрешимым причинам.
zergon321
17.07.2024 14:09Визуальное программирование существует уже давно и активно применяется. Посмотрите на Houdini, на shading, compositing и geometry nodes в Blender'e, на blueprints в Unreal Engine. Естественно, никто с помощью него не пишет огромные системы. Только небольшие скрипты для симуляций, покраски модели, игрового события и т.д.
Refridgerator
17.07.2024 14:09+10У меня тоже есть свой собственный визуальный язык программирования, вот так выглядит:
Описанная в статье проблема в том, что визуальное программирование идеально подходит для data-flow, а его пытаются пихать в control-flow. Равно как и наоборот, программирование сложной DSP-логики чисто текстом это боль и страдания. Нужно просто правильно декомпозировать задачу и выбирать подходящие инструменты, только и всего.
igorts
17.07.2024 14:09Смутило, что используется термин визуальное программирование, но по сути речь идет о визуальном моделировании.
Из моего опыта, наиболее близко и эффективно применение визуального подхода для получения кода - это ER модели, и Oracle Designer был великолепен в свое время.
error911
17.07.2024 14:09Возможно, в будущем визуальное программирование будет как основа, а под капотом будут трудиться нейросети.
Snacker
17.07.2024 14:09Около 20 лет назад я столкнулся с VisSim. Мне показалось это довольно интересным решением. Самое главное, что его отличает от, например, Scratch, это отсутствие привычных конструкций из языков программирования, таких как циклы и переменные. Он состоит из логических элементов, сигналов и ввода-вывода. И в таком, вроде бы урезанном, виде можно реализовать практически любую программную конструкцию. И выносит вполне себе наглядно при этом. Проблема там была с поддержкой железа (только пара вариантов от TI) и очень плохая генерация кода на Си. Можно было обойтись и без генерации, но, опять таки нужны были платы от тексаса.
mayorovp
17.07.2024 14:09Вы серьёзно сравниваете симулятор схем с языком программирования?
Snacker
17.07.2024 14:09+1Это не симулятор схем. И для эмбеддед задач вполне подходит пусть и с некоторыми ограничениями. Я же говорил, что с ее помощью делал прошивку для отладочной платы от тексаса. Вполне себе работало, ввод с кнопок, по ком порту, вывод на компорт и светодиоды. Проблем не было. Почему это нельзя сравнить с языком программирования?
koreychenko
17.07.2024 14:09+1Проблема многих языков визуального программирования в том, что они пытаются заменить собой вообще все операции обычных текстовых языков. В результате это превращается в адский ад.
Как в визуальном программировании будут выглядеть такие штуки:$a = $b ?? $c + 1;
Или, например, элементарный array_map или array_filter:
$filteredValues = array_filter($array, fn(Item $item) => $item->getValue() > $threshold);
И вся вот это создает такое количество визуального шума, что за ним теряется процесс как таковой.
У меня просто тоже был подход к снаряду. Я делал конструктор чат-ботов для Telegram. Тоже визуальный, разумеется. Потом мне захотелось интерактивности и гибкости и я туда притащил все фишки визуального программирования, вроде циклов, ветвления, переменных..... А потом я решил сделать текстовую игру.... на 700 сообщений.... с проверками, ветвлениями и т.п. Как это выглядело видно под спойлером.
Визуальное программирование - это просто!
LordDarklight
17.07.2024 14:09+1Не адепт визуального программирования. Но из чистого любопытства
$a = $b ?? $c + 1;
Хотя подвариантов представления операций тут много разных может быть (например +1 может быть операцией на стрелке)
Зелёная стрелка - передача значения (операция более приоритетна чем чем просто переход)
Фиолетовая - переход к другому блоку без передачи значения
Синий идентификатор с - случайно - должен быть как b - красный - как просто источник данных
Надписи на строках- условия (! - отрицание, ? - базовое сравнение)
Позже и про маппинг придумаю
koreychenko
17.07.2024 14:09+1Очень много условностей, ИМХО. Вы добавили еще одно измерение - цвет. И это тоже надо будет запоминать программисту.
К тому же представленный пример висит в воздухе. Если его встраивать в большую программу, то куда, будет идти стрелка из предыдущего блока? Кроме того, примеры с $b и $c+1 это были просто примеры выражения. В реальном мире там может быть, например, результат выполнения какой-нить функции. Например:$a = functionA($param1) ?? functionB($param2);
Понятно, что в "нормальных" языках визуального программирования можно реализовывать кастомные именованные блоки (и даже с параметрами). По сути это подпрограммы. Но при этом, ИМХО, теряется вся фишка визуализации.
LordDarklight
17.07.2024 14:09Очень много условностей, ИМХО. Вы добавили ещё одно измерение - цвет. И это тоже надо будет запоминать программисту
Во-первых, я не добавлял измерение цвет - он здесь, скорее, как подспорье - ведь и в современных IDE текст тоже же не чёрно-белые!
Во-вторых - мы же переходим от текста к графике - а тут уже активно в ход идут разные средства визуализации - иначе - зачем нам графика?
Но при этом, ИМХО, теряется вся фишка визуализации.
Наверное Вы слишком зашорены в понимании что есть визуализация при программировании - а я выше сразу дал замечание - что представлений может быть много. И много представлений могут быть реализованы в одном решении.
В тех же текстах ведь тоже, скажем, есть группировки - сворачивания блоков - и ничего - не шибко люди возмущаются "что теряется всё преимущество текстов" - да и настраивается это гибко...
то куда, будет идти стрелка из предыдущего блока?
В примере выше входящая стрелочка должна указывать на левый блок "b" - это же очевидно!
Кроме того, примеры с $b и $c+1 это были просто примеры выражения. В реальном мире там может быть, например, результат выполнения какой-нить функции
Как я считаю - всё-таки писать выражения при визуализации можно несколькими путями - для удобства:
Как в примере выше - прямо внутри блока - удобно для простых выражений, например математических вычислений
Писать через соединения блоков стрелочками-операциями (показано в примере ниже для "+")
Писать через блоки-операции (показано в примере ниже как вызов функции или приведение типа)
Может ещё какие варианты могут быт...
При этом - все варианты должны быть взаимозаменяемы автоматическим рефакторингом- по необходимости. А сложные вычисления ещё должны быть и реализуемыми в виде подблока (подпрограммы) - по умолчанию свёрнутой, открываемой отдельно как функция (ниже в примере это может быть внутри нижнего блока справа - свёрнутого второго вызова функции "functionA").
Ваш же пример ниже:
$a = functionA($param1) ?? functionB($param2);
Опять же - это проcто один из вариантов. И я не претендую на эффективность и красоту - я не адепт визуального программирования
Примечание:
+/- сворачиваемый блок
Лупа - открывает детали реализации (вообще-то - предполагается открытие в отельном попап (или, скорее, плавающем) блоке, или даже окне - но тут, для наглядности (и упрощения моего рисования), рисую сбоку) - точечная линия от лупы - появляется только при раскрытии - или ещё может не быть вовсе
В этом примере некоторые операции представлены внутри блоков (например приведение типов), некоторые на стрелочках перехода
Пунктирная стрелочка справа - автоматическая - визуализация возврата значения функции
Возможно, в блоках вызова функций тоже стоит показывать фактические типы (но это всё может быть настраиваемым) - раз это типизированный ЯП
По-хорошему, в реализации функции "functionB" на стрелочке передачи результата сложения Arg2 нужно отобразить в какой параметр передаётся это значение, хотя бы автоматически - если у функции только один обязательный параметр (однозначное соответствие) - для наглядности визуализации
Аналогично могут передаваться какие-то аргументы и в исходные вызовы функций "functionA", "functionB" - но это необязательно - т.к. логика переходов может быть совсем от других источников (как переход от функции "functionA" к функции "functionB)" - но всё-равно можно был бы сделать вторичные, "висящие" блоки передачи аргументов. Но, данный синтаксис визуализации этого не требует - хотя это можно создать автоматически рефакторингом для наглядности
Ошибся в обязательных параметров функции "functinonB" - пусть Arg2 тоже имеет какое-то значение по умолчанию - лень перерисовывать! Прошу прощение - это не существенный огрех
Кстати, очень интересной фишкой может стать раскрытие реализации вфункции "functinonB" сразу в переданных аргументах а не в параметрах
Так в чём сложность создания или восприятия?
Тут только некоторые трудности у платформы по эффективной визуализации будут!
inkelyad
17.07.2024 14:09+1Так в чём сложность создания или восприятия?
Вот даже в примере визуализация занимает в разы большую площадь, если сравнивать со строкой. Соответственно, вообще на экране меньше логики помещаться будет, которую можно окинуть взглядом и помедитировать, не трогая управление отображением.
LordDarklight
17.07.2024 14:09Вот даже в примере визуализация занимает в разы большую площадь, если сравнивать со строкой.
Конечно - поэтому я и не адепт визуализации - изложил свои аргументы выше в комментариях - но это не значит что, относительно эффективно, визуализировать вообще нельзя - Вы спросили как будет выглядеть - я показал один из вариантов. Остальное дело привычки и дело вкуса
aldekotan
17.07.2024 14:09Касаемо красоты под спойлером, это всё - функции? Или структура диалогов? Почему не поделить на отдельные секции? Спрятать под капот, использовать функции и макросы, вызовы событий... решения есть. И чем больше я изучаю визуальное программирование, тем меньше становятся подобные схемы. Так сказать, перехожу на уровень выше.
koreychenko
17.07.2024 14:09Это отдельные сообщения. И тут еще управляющих конструкций особо нет, просто сами сообщения и кнопки под ними. Понятно, что надо группировать сообщения в линейные сценарии и запускать сразу сценарий, вместо длинной портянки сообщений, но не потеряется ли тогда "визуальность".
А если делать не визуально, то я бы это всё запихнул в JSON или в YAML, добавил каких-нибудь управляющих инструкций, написал простенький парсер этого конфига и оно бы прекрасно работало. И править было бы намного удобнее, честно говоря.
aldekotan
17.07.2024 14:09Возможно, визуальность и правда потеряется. Но, на мой взгляд, что в обычном коде, что в визуальном, читабельность и понятность одинаково важны и достигаются схожими методами)
То есть, для меня, скажем, будет одинаково трудно понять, что делает код, если он состоит из 1000 строк или если тот же самый код показан через визуальные ноды и этих нод 1000.
А вот если код разбит на функции и каждая такая функция помещается на экране - разобраться в ней будет проще, как в визуальных нодах, так и в текстовом виде.
Что забавно, и в обычном коде и в нодах мне очень помогает разделение по цвету и по блокам (через комментарии).
LordDarklight
17.07.2024 14:09$filteredValues = array_filter($array, fn(Item $item) => $item->getValue() > $threshold);
Чисто такой пример мог бы выглядеть так
Грифельного цвета блок - это анонимная лямбда с одним аргументов (автоопределяемый по контексту тела), и одной переменной в "замыкании"
Но выглядит то всё не очень красиво - поэтому ниже картинка с 4-мя вариантами более эффективного визуального представления данной операции:
Слева направо:
Значение переменно "array" передаётся в переменную с условием, наложенным через зарезервированное слово "item" - что говорит, что его надо наложить на элементы внутри потока "array", вторым аргументом сравнения идёт другая переменная - т.к. условие написано на стрелочек, здесь нет стрелочки передачи сюда этой переменной из блока
Зато в этом примере передаются обе переменные - здесь применятся отдельная операция сравнения в блоке условия, так же через обращение к элементам массива "array" через зарезервированное слово "item" (в принципе, наверное можно сделать и отдельный блок сравнения - который всегда оперирует только внутренними элементами передаваемого в него потока, тогда применять "item" будет не нужно)
Вот, примерно как тут, только тут мы сразу определяем обращение к переменной "array" как блоку развёртывания потока - на выходе уже будет идти только поток элементов "array" (т.е. сами "item"), поэтому тут на стрелочке условие уже упрощено - только оператор сравнения и второй аргумент сравнения
Здесь аналогичный подход - только применён блок преобразования (в данном случае фильтрации), с условием прям в самом блоке, поэтому на выходе уже будет отфильтрованный массив, который и передаётся далее в переменную-приёмник
Лично мне нравится 4-ый (правый) вариант - но в нём нужно определять блок источника; а если нужно переходить из другого, уже имеющегося, блока (без определения нового - хотя это тоже возможно) - то нравится первый (левый) вариант (здесь источник, в лице блока "array" может быть определён как угодно - это не влияет на решение, главное - его тип данных должен быть перечислимым).
Безусловно, это далеко не все возможные эффективные визуализации фильтрации одной переменной по условию для помещения результата в другую переменную.Применение ссылок на источники (переменные) внутри выражений блоков или стрелок достаточно компактно и легко читается, но тут есть недостаток, в отличии от ссылки с другого блока - ссылка более гибкий механизм, т.к. в этом случае зависимый блок не зависит напрямую от выражения исходного блока - и его можно легко менять, не трогая зависимые блоки! Но насколько это принципиальное преимуществ - я не знаю! Но - все варианты записи должны быть иметь возможность лёгкого применения авторе факторинга друг в друга - так что это вообще не проблема - а ли8ь разные представления одного и того же!
А теперь посмотрите у кого представление получилось более красивым, понятным, компактным и эффективно воспринимаемым и видоизменяемым?
Впрочем... я и текстом могу написать такие варианты тоже весьма эффективно и компактно:
filtredValues <- From array Filter (item>threshold)
array -> Filter (it>threshold) -> filtredValues
(array) -> if(item>threshold) -> filtredValues
array:(item>threshold) -> filtredValues
LordDarklight
17.07.2024 14:09Все 4-ре примера выше приведены в синтаксисе разрабатываемого мною ЯП 5-го поколения под рабочим названием "ODIN") - надеюсь разберётесь - всё же просто:
-> и <- это операторы направления потока данных
(источник) это операция начала извлечения (перечисления) элементов источника (может быть ещё так: (elm<-array) если нужен свой идентификатор для элементов источника - но это нужно при вложенных перечислениях
Filter это команда - принимает на вход источник и возвращает обработанный источник (it - зарезервированное идентификатор - ссылающийся на внутреннюю реализацию команды - по сути там лямбда)
Двоеточие - это операция преобразования - в данном случае с вложенным в скобки выражением фильтрации с обращением череp item - к содержимому источника)
-
array:(item>threshold) -> filtredValues
можно написать и так короче (но, на мой взгляд, менее наглядно):
filtredValues <- array:>threshold
или так (как аналог и для (array) -> if(item>threshold) -> filtredValues):filtredValues <- (e<-array, e>threshold)
или (тут цепочка преобразований может быть ещё продолен с доп ":" справа, и можно обращаться к "e" - исходное значение; просто сами выражения перечислений могут быть куда более сложными):
filtredValues <- (e<-array):(e>threshold)
Я это всё как раз к тому - что я сильно настаиваю, что текстом писать можно и компактнее эффективнее - и именно этот подход и надо развивать в будущих ЯП
IGR2014
17.07.2024 14:09+1Вот диаграмма сгорания задач, сгенерированная Hercules CLI:
Количество строк кода и годы вижу, а понять смысл не могу. Это визуализация того сколько кода с каких времён в проекте осталось? Или что?
markshevchenko
Смотрел лекцию Владимира Пирожкова — это дизайнер (конструктор?) автомобилей, долгое время проработавший за рубежом. Он говорил, что надо обращать внимание на тенденции, чтобы понять, каким будет будущее. Тенденции с компьютерами заключатся в том, что системные блоки стремительно сжимаются, в то время, как мониторы не менее стремительно растут в ширину и высоту, становясь при этом всё тоньше.
В недалёком будущем, скажем, через 10-15-20 лет легко представить, что компьютер будет похож ни лист ватмана формата А4 или А3. Мы будем его сворачивать, носить с собой, раскладывать на столе, работать.
Понятно, что в таком виде мышь клавиатура будут не очень адекватными средствами ввода. Скорее всего, у нас будут жесты и голос.
Я могу представить, как на таком компьютере смогут работать дизайнеры или музыканты. Даже, возможно, авторы текстов. Но программисты?
Не знаю, какими будут языки программирования будущего, но, кажется, что они будут именно визуальными. Я пытался подобрать удачные примеры визуальных языков и у меня получился список, похожий на тот, что в статье. Мой список был поменьше, потому что я не настолько в теме. Тем не менее, конечные автоматы, разнообразные деревья и ER-диаграммы у меня были.
Блок-схемы в этот список не попали: я никогда не считал их удобными или удачными.
Я заметил, что удачные языки по своей природе декларативны, и это довольно предсказуемо. Думаю, что новая форма компьютеров вынудит нас переходить на визуальные языки и программировать жестами и голосом. Скорее всего, визуальные языки будут именно декларативными. Но пока конкретных вариантов я не видел.
vtal007
Простите, куда системные блоки сжимаются (причем аж даже стремительно)? они как были коробкой на литров 30-40-50. так и остались со времен IBM-PC (или даже раньше), ток раньше клали горизонтально, а теперь чаще вертикально (на столе, под столом)
Да есть поделия китайцев и тайваньяцев довольно компактные и на ноутбучном железо. Но это вот именно что по сути ноутбук, только урезанный по функционалу
Как ни старайся, а 4090 (да хоть 4060) не особо сожмешь
markshevchenko
Почему тайваньцев и китайцев? Маломерные форм-факторы — это международные стандарты. Я видел мини-системники производства HP и Dell, не говоря уже об эппловских Mac mini.
Мне кажется, вы хватаетесь за отдельные исключения, совершенно игнорируя то, что я написал — тенденцию. Не надо вам в футурологи.
vtal007
у одних есть платформа декс-мини, у других компы, которые помещаются на ладоне
а что такое "маломерные форм-факторы" ?
мини-системники с задушенным i3 - ну да, они продаются (в период пандемии на авито их продавали дешево, потому что компании их покупали, но люди не пользовались в силу возможно убогости и низкой производительности, буквально за 16к можно было купить какой-то "мин-системник" с i3 9-го поколения, но с индексом t, у которого все достаточно грустно по производительности), но это ж не значит, что их вообще покупают за пределами офисов. Вы бы себе купили бы сознательно десктоп, где производительность зарезана, при наличии альтернативы? если да. то зачем?
да я как-то не стремился
Если Вы считаете, что есть какой-то тренд, то его надо цифрами потверждать, а то у меня значит "единичные случаи" (ага, игровые видюхи то миллионами продают, ну очень исключительные случаи), а у Вас - тренды
markshevchenko
Ну вот я написал про Mac Mini, вы успешно мой пример проигнорировали. Кажется, просто не влезает в ваше представление о мире.
Я довольно давно отказался от тауэров, лет десять назад. Собирал себе и системники небольшие, сейчас вот на ноутах сижу. Работаю, пишу программы, всё ок.
Тренды не надо подтверждать цифрами. Я тут никому ничего не доказываю, я просто размышляю. Кажется, этот навык уже утрачивает свою актуальность.
vtal007
ни маки, ни какая-то отдельная модель (мак-мини) не занимает какого-то доминирующего положения на рынке PC. Поэтому я проигнорировал
какие-то странные попытки задеть
ну и я собирал и и ноут у меня тоже есть и что? единичный опыт это вообще ни разу не репрезентативно. А ноуты это вообще не "системные блоки"
Правда что ли? то есть вот это
это просто "Миш, мне пофиг, я так чувствую"
markshevchenko
Да, правда. Потому что, я напишу ещё раз — мне интересна тема визуальных языков программирования, мне интересно, как это могло бы выглядеть. И да, идея о том, что такая проблематика перед нами встанет, появилась у меня, когда я увидел, как звукорежиссёр одной группы, на концерте которой я был, ходил по залу с планшетом и настраивал звук.
Я подумал: а кто ещё может работать на планшете? А мы, программисты, сможем ли?
Мой комментарий для тех, кому интересно подумать в эту сторону. Вам не интересно. Хорошо. Давайте больше не отнимать друг у друга время.
LordDarklight
Отвечу Вам так - все смотрят на свои (редко - чужие) проблемы со "своей колокольни"! И, когда Вы увидели как звукорежиссёр управлять звуком с планшета - так - лет так 30-35 назад (ещё со школьной скамьи), увлекаясь и программированием и сочинение музыки, чертыхался от музыкальных редакторов от Cakewalk, Cubase, Sound forge до только набирающих тогда популярность мультидорожечников, от Sony Acid (который нынче Vega) до... (уже не помню какие тогда уже были, вроде тоже Sound Forge и Audition - но он он тогда по-другому назывался). Нет - в те времена я тащился от Cakewalk и Acid, а затем и от Fruty Loops - но считал это всё слишком неудобным и примитивным! И именно тогда мне пришла в голову мысль - что писать музыку куда удобнее было бы текстом (а тогда среди программирования также были крайне популярны визуальные среды разработки как Delphi, Vusual C, Borland C++ builder, или, скажем, Dream viewer; даже азы данных в СУБД стремились рисовать в визуальных конструкторах)!
И я стал думать - как это всё лучше организовать - перебрав несколько отличных концепций! Считая себя 100; оригинальным новатором этой темы! Особенно на фоне того - как в XXI веке музыка стали сочинять генеративные AI сети - генерировать музыку текстом для них самое то!
И только спустя 30 лет - я узнал о том, что программирование музыки придумали на заре самого программирования 3-го поколения - т.к. в 70-х когда прошлого века! Кстати, там начинали, кажется, именно с графического программирования (сейчас не помню, на вскидку какой это был ЯП - поищу)! Но... ознакомившись с ними всеми... в т.ч. с недавнопояшившишься новым ЯП для создания музыки, базирующемся на JavaScript - счёл это всё примитивным и не удобным!
И сейчас проектирую свой собственный ЯП для создания музыки под рабочим названием "Orange". Это будет весь продвинутый ЯП - не только для композирования и аранжировки - но и для сложной звукорежиссуры и звуковой обработки, и даже аконкурирования с системами библиотек цифровых музыкальных инструментов - а-ка Kontakt (который я тоже счёл крайне примитивным) и реализации гипер-мультисемплирования! Но всё делает текстом (само собой работа с привычными для музыкантов и звукорежиссёров средствами ввода тоже подразумевается - даже с, условно с электрогитарами и аналоговыми источниками звука") - и всё через кодогенерацию (само собой информации - это цифровые RAW данные).
И не только статичное программирование - но и динамичное - когда музыка меняется прям в реальном времени!
И управление этим всем подразумевается не только специфической адаптированной структурой текстовых скриптов! Но и реализацией адаптированной студии IDE (для повышения удобства) - с продвинутой частью визуализации! И конечно же поддержкой плагинов и библиотек! И... само собой версионирование а-ля Git, и продвинутого текстового поиска (в т.ч. по регулярным выражениям), анализа, маккро/мето-программирования, кодогенерации и рефакторинга!
И да.... моя идея не в том, чтобы управлять этим с планшета - это достаточно сложная система (особенно при управлении в реальном времени) - для работы с которой могут потребоваться несколько мониторов и лаже клавиатур... не считая специфичного музыкального оборудования! Но... в относительно простых статичных случаях можно обойтись и, условно, рядовыми текстовыми процессорами с несколькими специальными плагинами для комфорта! Да и при желании - частично можно было бы и с планшета управлять!
Так что вот даже так - музыка - это тоже код - и его вполне себе можно писать программой! Как и всё в нашем мире - есть программный кол! Таков мой девиз!
А системы искусственного интеллекта тут станут отличными помощниками с их гибким восприятием и оперированием текстовыми данными!
markshevchenko
Это вот прямо интересно. Никогда не думал про кодирование музыки. Мне казалось, что формат MIDI закрыл эту проблематику, но я никогда не погружался глубоко.
Сам формат бинарный, но, если мне не изменяет память, есть текстовое представление?
И, да, есть классическое графическое представление — ноты.
А есть какие-то статьи или видео про ваши наработки?
LordDarklight
MIDI (Musical Instrument Digital Interface) как формат данных - это бинарное представление просто последовательности инструкций (команд). Дефакто стандарт цифрового сопряжения любого музыкального оборудования или программных плагинов (кроме прямой обработки звука в виде потока декретированной волны, хотя и WAVE тоже через MIDI обрабатывать можно). В каком-то смысле - можно считать это аналогом IR в контексте управляемых ЯП. Только туго с управляемыми ЯП для MIDI. Про текстовую нотацию для MIDI не слышал - но можно глянуть LilyPond
Про различные музыкальные нотации вот тут wiki (английская версия полнее). Но распространены сейчас табулатуры и ABC-разметка - текстовый программный подход к музыки позволяет применять разные нотации - как будет удобно! У меня есть о свой расширение для табулатур!
А любителям графической визуализации предлагаю заглянуть сюда
А адептам моделирования разметкой - сюда
Статья, как и сам ЯП пока в разработке ;-)
Но для удовлетворения любопытства - вот несколько отрывков из зеро-драфт:
Пролог ORANGE Music creator studio
OMC Language - это спецификация скриптовой языка программирования, разработанного для написания музыкальных (или иных других) звуковых композиций, да и вообще для звукоизвлечения и обработке звука. Это специфический ЯП для эффективной работы со звуком, в первую очередь с его молодикой – т.е. главная поставленная задача – лёгкость аранжировки (от того и название orange – arrange) музыкального полотна плюс наложение эффектов и мультидорожечный (мультиканальный) мастеринг, с глубокой автоматизацией всех процессов. С поддержкой применения сторонних плагинов (в т.ч. VST) и внешнего звукового процессинга. С полным описанием всего проекта в удобочитаемом и набираемом текстовом виде. Впрочем, обработка звука тут не 100% обязательна, и на данном ЯП вполне себе можно писать практически любые программы (подключив необходимые библиотеки).
Данный ЯП является высокоуровневым, практически строго императивным, языком с элементами функционального программирования, и в своей базе является интерпретируемым.
Спецификация прицельно разработана для удобного программирования многопоточного потока команд исполнения (каждый трек – это отдельный параллельный поток) и их синхронизации друг с другом; причём во многих случаях операторы неявно (или явно) порождают отдельный поток (трэк) исполнения (но этим можно управлять по контексту использования). Так же ЯП является контекстно-зависимым - в каждый момент есть некое состояние текущего контекста исполнения, им можно гибко управлять, настраивая общие контекстные параметры, на которые могут опираться исполняемые в нём команды, контекст можно клонировать и дробить (в подблоках и подпрограммах), делать частично наследуемым, сохранять, создавать новый и восстанавливать для текущего потока, и передавать в другие потоки и подпрограммы.
ЯП может эффективно применяться как для статического написания музыки (или иного процесса, но деле всё-таки будет идти речь о музыке), так и для динамического создания (или сведения) музыки в реальном времени, в т.ч. через внешнюю генерацию другими алгоритмами и управления воспроизведением, например, для программ-автогенератором музыки, как полностью автономных (нейросети, самостоятельно сочиняющие музыку), так и более простые алгоритмы – которые просто генерируют динамически меняющийся звуковой поток по заданным правилам реакции на какие-либо состояния их собственных процессов (или отслеживаемых ими внешних процессов). В принципе, на OMC тоже можно было бы реализовать в будущем полностью автономную генерацию музыки – у ЯП нет каких-либо ограничений для этого.
Введение в команду sample
Для помещения в текущий трек содержимого нужно просто выполнять разные встроенные, библиотечные, кастомные команды и паттерны. С точки зрения программирования всё это будет очень похоже просто на императивный (с элементами функционального стиля) код, где каждый трек – это просто параллельный поток исполнения программы, но с некоторыми специфическими нюансами.
Например, чтобы воспроизвести какой-то семпл (считаем, что он заранее уже был загружен программно, или входит в часть ресурсов проекта) нужно выполнить команду
sample(“путь\имя семпла”)
Можно создать переменную-псевдоним для этой команды, чтобы получить более короткое имя
val a = @sample(“путь\имя семпла”)
И далее просто обращаться к ней
a a a a //Семпла прозвучит подряд 4 раза друг за другом
Такие алиасы можно создавать для любых выражений Языка (в т.ч. параметрических и с открытым концом – об этом всё будет подробнее позже рассказано), но выражение должно иметь полностью закрытые скобки, которые были открыты в нём.
Существует много путей управления воспроизведением семплов и их последовательности, например, если надо вставить задержку между ними – то есть команда delay
a delay(100ms) a delay(100ms) a delay(100ms) a delay(100ms)
команда sample имеет параметр для установки начальной и конечной задержки
var a = @sample(“путь\имя семпла”, BeginDelay=40ms, EndDelay=60ms)
a a a a
или так
var a = @{ delay(40) sample(“путь\имя семпла”) delay(60) }
a a a a
Команда sample имеет очень много параметров, и вообще – для воспроизведения сложных семплов могут быть определены отдельные специальные функции. Сейчас я не буду это всё рассматривать. Но несколько важных рассмотрю
Одним из главных параметров является тон
sample(“путь\имя семпла”, .D) //Формально тон «Ре» - если семпл откалиброван по тону «До»=C); в действительности – это изменение тона семпла от базового на 3 ноты вверх; формально – понятие ноты тут тоже условно (семпл может быть сконфигурирован произвольным образом) – и это просто изменение на 3 тона вверх
sample(“путь\имя семпла”, .+D) //Но 3 тона и октаву вверх (октавы формально тоже условны)
sample(“путь\имя семпла”, .--D) //Опустить тон на 2 октавы и увеличить на 2 тона
sample(“путь\имя семпла”, .-<D) //Опустить тон на одну октаву и 3 тона
sample(“путь\имя семпла”, 800) //Числами тоже можно задавать: положительные – увеличение тона, отрицательные – уменьшения относительно базы
sample(“путь\имя семпла”, .D, BaseToneOffset=800) //Можно так же дополнительно смещать базовый тон, относительно которого будет воспроизводиться заданный основной тон
sample[“путь\имя семпла”].BaseToneOffset=800 //А вот так можно изменить значение по умолчанию для семпла (только в рамках текущего трека); замечу, что имя ресурса задано в квадратных скобках
Помимо тона важным параметром является длительность звучания:
sample(“путь\имя семпла”, .A, 500ms) //Базовый тон, звучит полсекунды (важно, чтобы он сэмпл не был короче 500 мс или был зациклен)
Тут для разных форматов семплов очень много нюансов определения длительности их звучания – и у команды sample есть много параметров для корректного использования длительности. Например, у семпла может быть часть затухания (после основного звучания) и в примере выше длительность будет общая т.е. вместе с затуханием. Если же нужно не учитывать длительность затухания то можно написать так:
sample(“путь\имя семпла”, .A, 500ms, FadePlay=.Always) //Если звучание не уложится в 500 мс, то затухание всё-равно будет проиграно
или так
sample(“путь\имя семпла”, .A, MainLen=500ms) //аналогично – лимитируется только длина основной части семпла
sample(“путь\имя семпла”, .A, 750ms MainLen=500ms) //Основная часть семпла лимитируется 500 мс, а весь семпл (с затуханием) лимитируется 750 мс
sample(“путь\имя семпла”, .A, 500ms, FadePlay=.Continue) //Затухание будет полностью звучать, если успеет начаться за 500 мс проигрывания всего семпла
И так далее – тут возможностей очень много. Особенно для циклических семплов. Для удобства проигрывания сложных семплов луче пользоваться специальными библиотечными командами, более узко специализированными для воспроизведения семпла в том или ином режиме. Плюс применять псевдонимы для перенастроенных вызовов команд.
Но ещё одним важным параметром длины семпла является DelayLen – это длина задержки семпла
sample(“путь\имя семпла”, .A, 750ms DelayLen=500ms) //Формально семпл будет звучать 750 мс, но выполнение sample завершится уже через 500 мс и начнётся выполнение следующей команды, до завершения звучания семпла. Важно – если будет задан параметр EndDelay – всё-равно сделает задержку после прошествии времени длины семпла
Очень важным компаньоном команды sample является команда specimen – она запускает семпл и не делает задержку для следующих команд, которые параллельно проигрываемому семплу могут выполнять ещё какие-то действия – например спецэффекты для семпла, или даже запускать другие семплы, которые начнут прерываться параллельно с текущим в рамках единого трека.
Введение в клавишную нотацию
Помимо прямой вставки семпла в партитуру трека, есть возможность зафиксировать его за всем треком
use instrument sample(“путь\имя семпла”) //Тут можно зафиксировать все необходимые параметры по умолчанию
Передача нот удобнее всего через паттерн клавиш
{keys: -A500+(D#200 E200 D#200 E200 D#200 E200) } //Нота «Ля», октавой ниже, звучит 500 мс, поэтому в начале получается аккорд (-А+D) нота Ре звучит 200 мс, после чего сменяется на «Ми», которая чередуется несколько раз с «До#» каждые 200 мс (но первые «До#», «Ми» и вторя «До#» буду сыграны вместе с «Ля», но за 100 мс, до конца звучания второй «До#», нота «Ля» перестанет звучать (истекут 500 мс)
Если не задать у ноты «Ля» время звучания, оно автоматически будет как у всего аккорда; при этом можно задать время в сего аккорда (даже такого сложного, с чередованием нот)
{keys: -A+(D# E D# E D# E):MainLen(1000) } //Тут вся последовательность звучит 1000 мс –время звучания каждой ноты будет одинаковым и вычислено из общего времени звучания (отдельным нотам можно задать их персональное время звучания – тогда оно будет вычтено из общего при расчёте звучания остальных нот)
Все ноты буду воспроизводиться текущим инструментом, заданным как семпл.
Число справа от ноты – это длительность звучания (без учета затухания). Символ «#» это диез (смещение на полтона вверх); есть и бимоль «&» - пример “D&200” – но применяется редко.
Если при воспроизведении ноты нужно указать какие-то особые параметры семпла – их можно указать в скобках вызова ноты
{keys: D#200(EndDelay=100) G(FullLen=200) D#200(EndDelay=100) G(FullLen=200)} //Число справа от имени ноты длительность звучания (без учета затухания) на это время будет пауза перед запуском следующей ноты; G(FullLen=200) задаёт длительность с учётом затухания; EndDelay=100 задаёт дополнительную паузу конце звучания ноты (от конца основного звучания) прежде чем управление перейдёт дальше
Можно и так записать
{keys: D#200:EndDelay:100 G:FullLen:200 D#200:EndDelay:100 G:FullLen:200}
Всё это в базовой октаве семпла. Октаву можно понижать и повышать – символы «-» и «+» строго перед именем ноты (ну или передать в ноту аргумент Octave=номер октавы – 0-я субконтр-октава –, 1-я контр-октава и т.д.) – сколько будет символов на столько октава будет сдвинута (а в примере выше -A25 – это «Ля» на одну октаву ниже базовой – т.е. «Ля» в малой октаве).
{keys: ---D200 --D200 -D200 D200 +D200 ++D200 +++D200} //Игра ноты «До» во всех основных октавах
Кстати, октаву можно зафиксировать для текущего контекста, например, для нотного паттерна – тогда относительные изменения октавы будут уже от неё, а «абсолютные» (числовые) останутся от базовой
{octave:3 keys: D200 +D200 ++D200 +++D200 ++++D200 +++++D200 +++++++D200}
Ещё одним способом явно указать октаву – её номер перед нотой
{keys: 3D200 2D200 1D200 0D200 1D200 2D200 3D200}
Замечу, что такой способ отличается от общепринятого, где октава пишется справа от ноты (так как, в данном случае, там располагается длительность), но такой вариант формата тоже возможен:
{classic: D1-200 D2-200 D3-200 D4-200 D5-200 D6-200 D7-200} //октава всегда должна быть указана
По умолчанию за нулевую берётся смещение на 4 октавы вниз до субконтр-октавы (но в настройках или в параметрах текущего контекста это можно изменить – но цифрами справа можно будет только прибавить октаву, но не убавить)
{octave:1 classic: D1-200 D2-200 D3-200 D4-200 D5-200 D6-200 D7-200} //задали нулевое смещение октавы
Замечу, что есть ещё один вариант записи нот (вообще их может быть много – если установить дополнительные интерпретаторы формата), из мира трекерной музыки – важное отличие: тут не задаётся напрямую длительность ноты – она звучит, пока явно не будет сброшена или не начнётся другая (ну если, нота зациклена – иначе звучит до своего конца и всё) – и тут каждая позиция имеет фиксированную длину тактов звучания (это всё настраивается), пропуск тактов «--» (обязательно отделено от нот) или «NP», заглушить ноту «00»
{ticklen:200ms tracker: D1 -- D2 -- -- D3 D4 D5 -- D6 00 NP NP D7}
Этот формат ещё много поддерживает фишек трекерной записи, но о них сейчас говорить не буду.
Нотные паттерны скрывают ещё много нюансов (например, можно задавать эффекты, силу/скорость нажатия и отпускания (или какие-то ещё техники, если речь не идёт про клавишный инструмент – это уже нюансы текущего инструмента), управлять громкостью и пространственным позиционированием и т.п.), но пока я вновь вернусь к описанию команд трека. Последнее, что добавлю – нотный паттерн так же поддерживает переменные (обычно речь о внешних, хотя внутри можно тоже объявить) и функции (в т.ч. генераторы) – ссылаться на них внутри паттерна можно обычным способом (по имени), но внутри паттерна есть свои ключевые слова – они переопределяют пользовательские идентификаторы (кстати, внутри паттерна можно переопределять существующие и вводить свои ключевые идентификаторы и переменные (в т.ч. внешние) через создание псевдонимов, сослаться на внешнюю переменную или функцию так же можно через префикс $ - за ним всегда подразумеваете внешний идентификатор (при необходимости получить адрес – последовательность спецсимволов такая «@$» далее идентификатор).
var len=800 {keys: D#(len+10) E(len+20) D#(len+40) E(len+80) D#(len+100) E(len+random(100)) }
аналогично (но переменная len существует только внутри паттерна; и фунукция даёт случайное число от 1, а не от 0)
def rnd() = random(1...100)
{ var len=800 keys: D#(len+10) E(len+20) D#(len+40) E(len+80) D#(len+100) E(len+rnd()) }
Введение в лупы
И так. Если нам нужно несколько раз подряд воспроизвести один и тот же семпл мы можем его написать несколько раз
sample(“путь\имя”) sample(“путь\имя”) sample(“путь\имя”)
А можно просто запустить цикл
repeat(3) sample(“путь\имя”) //можно ещё так sample(“путь\имя”):repeat(3)
Такими же способами можно зациклить и блок кода
repeat(3) { sample(“путь\имя1”) delay (200) sample(“путь\имя2”) Delay(200) }
или
{ sample(“путь\имя1”) delay (200) sample(“путь\имя2”) delay (200) }:repeat(3) //кстати repeat(0) не выполнит ни разу
Код, следующий за блоком цикла будет ждать пока не выполнится цикл, но если написать так
loop(3) sample(“путь\имя1”) sample(“путь\имя2”)
Выполнение семплов 1 и 2 начнётся одновременно, но на втором цикле будет запущен 1-ый семпл, независимо от звучания 2-го или какие команды там будут ещё вне цикла. То есть, loop цикл запускается параллельно текущему треку (можно считать, и по факту так оно и есть, что цикл запускается в отдельном субтреке, но с копией текущего контекста, и связанный с ним, и с его каналом; это похоже на оператор by, который тоже порождал параллельное выполнение – и внутри цикла он тоже может быть – и это будет ещё один поток параллельного выполнения).
Можно запустить и бесконечный цикл (если с repeat это не очень полезно, хотя – это как посмотреть), то с loop – будет куда полезнее (тем более что есть команда break – для прерывания цикла, а её параметр – это сколько вложенных циклов надо прервать (или можно указать конкретный цикл – об этом ниже)
loop { sample(“путь\имя1”) delay(300) sample(“путь\имя2”) } //Бесконечный цикл, пока существует трек, в котором он запущен
По сути loop – это отдельный поток исполнения (отдельный трек) и ему присуще всё, что касается управления параллельными потоками. Например, их можно прерывать извне
loop { sample(“путь\имя1”, FullLen=300) delay(300) sample(“путь\имя2», FullLen=300) ? checksignal(1) break }
repeat { delay(300) ? (random(4) == 0) -> signal(1); sample(“путь\имя3”, FullLen=300) }
//Здесь семрплы 1 и 2 могут звучать одновременно с семплом 3, или он звучит между ними, но случайным образом внешний код подаёт сигнал и цикл завершается (сигнал – не звуковой, а логический)
Но каждый цикл – это объект – поэтому можно и так
var myLoop = loop { sample(“путь\имя1”, FullLen=300) delay(300) sample(“путь\имя2”, FullLen=300) }
repeat { delay(300) ? (random(4) == 0) ->myLoop.Break(.End); sample(“путь\имя3», FullLen=300) }
Вместо Break можно вызывать Abort() – тогда цикл прервётся в любой момент времени (даже не доиграв семпл) или Stop() – тогда цикл остановится перед началом очередной итерации
Ещё вариант
var myLoop = loop { sample(“путь\имя1”, FullLen=300) delay(300) sample(“путь\имя2”, FullLen=300) break(.Check) }
repeat { delay(300) ? (random(4) == 0) ->myLoop.Break(.Manual); sample(“путь\имя3”, FullLen=300) }
Здесь «break(.Check)» сработает только если будет вызван «Break(.Manual)»
Наряду с break есть и команда continue – перезапускающая итерацию цикла (continue(.Restart) – перезапустит цикл полностью (если у него был лимит на число итераций или какая-то позиция), как будто цикл запустили снова.
Сигналы, удобны не столько для прерывания потоков (как выше можно заметить – они лишь маркер), но больше для синхронизации потоков
var myLoop1 = loop { sample(“путь\имя1”, FullLen=300) waitsignal(1) sample(“путь\имя2”, FullLen=300) waitsignal(2)}
var myLoop2 = loop { sample(“путь\имя3”, FullLen=300) waitsignal(1) sample(“путь\имя4”, FullLen=300) waitsignal(2)}
repeat(4) { delay(300) signal(1,10ms) sample(“путь\имя5”, FullLen=300) signal(2,10ms)} //10ms – вторым аргументом указывает длительность сигнала (после чего он автоматически сбросится, либо надо сбрасывать самостоятельно (signaloff(…)), либо сигнал без длительности автоматически сбрасывается при выходе исполнения из блока (блок в цикле считается всем циклом)
Есть схожая альтернатива сигналам – mark
loop { sample(“путь\имя1”, FullLen=300) mark(1,3) sample(“путь\имя2”, FullLen=300) mark(2,3)}
loop { sample(“путь\имя3”, FullLen=300) mark(1,3) sample(“путь\имя4”, FullLen=300) mark(2,3)}
sample(“путь\имя5”, FullLen=300) mark(1,3) sample(“путь\имя6”, FullLen=300) mark(2,3)
mark – это «сигнал» (не пересекается с обычным сигналом – это именно марк-сигнал) и ожидание в одном флаконе – тут два аргумента – первый идентификатор сигнала, второй счетчик – как только зарегистрируются все 3 марк-сигнала произойдёт продолжение выполнения и сигнал будет сброшен.
Но можно вызывать и так (причём тут опущен и идентификатор сигнала (будет общий) и счетчик (ведётся автоматически):
loop { mark(.Context) sample(“путь\имя1”, FullLen=300) mark sample(“путь\имя2”, FullLen=300) mark}
loop { mark(.Context) sample(“путь\имя3”, FullLen=300) mark sample(“путь\имя4”, FullLen=300) mark}
mark(.Context) sample(“путь\имя5”, FullLen=300) mark sample(“путь\имя6”, FullLen=300) mark
здесь mark(.Context) – автоматически определяет количество различных независимых контекстов, нуждающихся в синхронизации и настраивает макс значения текущего счётчика единым образом
Альтернативная запись через блок mark { }
loop { mark { sample(“путь\имя1”, FullLen=300) } mark { sample(“путь\имя2”, FullLen=300) }}
loop { mark { sample(“путь\имя3”, FullLen=300) } mark { sample(“путь\имя4”, FullLen=300) }}
mark { sample(“путь\имя5”, FullLen=300) } mark { sample(“путь\имя6”, FullLen=300) }
здесь будет синхронизация в конце блока всех начатых блоков (идентификатор блока задавайте по необходимости), после чего блоки можно заново начинать для другой синхронизации
Каждый цикл имеет возвращаемое значение и его можно присвоить переменной
var a = loop(3) { sample(“путь\имя1”) sample(“путь\имя2”) } //или var a = { sample(“путь\имя1”) sample(“путь\имя2”) }:loop(3)
В этой переменной содержится объект управления циклом. В примере выше применён цикл loop – по умолчанию он стартует сразу же в параллельном потоке, а код в текущем продолжает выполняться сразу за ним. Соответственно, через переменную цикла можно управлять этим циклом – в основном это команды потока: Pause, Resume, Break и т.п., но есть и более специфичные команды именно для цикла: Start, Restart, Continue. И некоторые команды управления контекстом выполнения.
Можно и такой цикл присвоить переменной
var a = repeat { sample(“путь\имя1”) sample(“путь\имя2”) }
Цикл repeat не выполняется параллельно, но в выражении присвоения он не стартует сразу (иначе бы присвоение не произошло, пока цикл не завершится и в таком присвоении не было бы смысла). Поэтому, чтобы цикл стартовать нужно написать так: a.Start(3) но можно и просто обратиться к переменной, как к функции a(3) – при этом цикл вполне можно вызвать несколько раз (в любом месте, где доступна переменная цикла):
a(3) a(4) a(3) //в аргументах вызова задаются значения выполнения цикла – в данном случае число повторов и это всё равносильно repeat(10) { sample(“путь\имя1”) sample(“путь\имя2”) }
Но это всё просто синтаксический сахар внутри переменной находится объект, описывающий цикл. И этот значение можно даже передавать в другие функции как аргумент.
Все циклы являются подпрограммами и автоматически захватывают переменные контекста (где цикл был определён). Но есть важное замечание – параллельный цикл loop обычные переменные захватывает по значению – в его потоке исполнения это будут копии переменных, хотя ссылки на объекты будут одинаковые) – изменение копии переменной не будет менять другую её копию (но изменения внутри объекта значения переменной будет единым). Такое поведение не является единственно возможным, тут много нюансов по синхронизации значений – про это будет отдельно в части параллельного программирования.
Moog_Prodigy
Честно говоря, как-то сильно заморочено. Напоминает другой проект, правда не про музыку а про трехмерное моделирование - OpenScad. Там тоже все операции делаются исключительно кодом. Но это же жутко неудобно, имхо.
А когда придумали Piano Roll представление нот, да хоть в том же Cakewalk - это сильно, прям в разы упростило написание музыки. У вас усложнение вижу я.
LordDarklight
Как написал Выше - у меня идея достаточно комплексная и многофункциональная! Но тут только практика может показать - удачная она или нет - лично я вижу за этим будущее - а пока я представил лишь отрывки из очень раннего черновика! и даже если мне не удастся придумать удобное решение, которое могло бы стать популярным хотя бы в кругах с определённым мышлением, то это не значит, что это невозможно в принципе!
А всё остальное - это просто ломка восприятия - сейчас музыканты привыкли к другому. А насчёт Piano Roll - знаете - есть серьёзные композиторы, которые до сих пор его не признают такой подход - просо их академически учили обратному!
У меня те же аргументы как и при противостоянии визуального программирования и текстового (см выше) - разве что визуальны партитуры музыки вряд ли когда-то будут иметь очень высокую визуальную сложность (хотя это Вы её Black midi не видели (с одноимённой группой не путайте - хотя их музыка и вышла из данного стиля) - вот микро кавер на известный мотив 26 сек и 230k нот, подлиннее и пожёстче - не для всех ушей 5.5 мин и 5М нот; ну или попроще, а это вообще шедевр или вот известная мелодия с постепенной раскруткой - такое только программировать... God mode reblacked
The Convergence - шикарно).
Создавать сложные мелодии, с кучей инструментов, с разнесением в 3D пространстве - это Вам не партитуру в несколько сот тысяч знаков накалякать - тут число генерируемых команд будет исчисляться ярдами на минуту контента! Да - это уже очень далёкая от классики музыка (но классику тоже можно - осовременить) - это музыка будущего (я не про Black midi если что) - сложная, объёмная, непостоянная (ведь тут ещё и случайные числа можно применять - так чтобы, условно, каждый семпл звучал несколько иначе - а не просто дублировался - что добавляет натуральности); Не говоря уже о том, что музыка может просто генерироваться на лету (причём вполне нормальная музыка - но тут, конечно надо глубоко настраивать, готовые части партитуры с вариациями исполнения и совмещения; эх... вспомнил как генерировала музыка в древней, не сыскавшей популярность, игре 7th legion - если начало шокирует - промотайте вперёд или смените трек)... А уж какие огромные возможности по программированию эффектов обработки звука...
Так же программирование музыки - это отличное подспорье для математических направлений в музыки - например для Math Rock, и везде, где нужна высокая точность гармонии
LordDarklight
Безусловный ОФФтопик (хоть и контекстный) - но наглядный пример Black midi
Moog_Prodigy
Знаете, я когда-то экспериментировал с именно программированием музыки. Выглядело это так - два компьютера, на одном запущен Reason, и комп этот слушает midi порт. А что это такое? Да тот же уарт по сути. Поканально разведены ударные, бас, синтезаторы. А на другом компьютере программа на visual basic пихает байтики в выход миди своей звуковухи. Для начала я выводил из Cubase именно в миди порт, далее на втором компе звучали синтезаторы и все что надо. Затем я начал делать скрипты, меня интересовал DnB, PsyTrance, вот и я наделал шаблонов под ударные (они там не то чтобы сильно замороченные), переходы, мелодические и басовые линии отправлялись в порт (точнее процедуру, которая паковала их в ноты), сверху этого всего простейший табличный гармонизатор, и вот получилось просто охрененно. Совершенно убойный драмчик круглосуточно. Без нейросеток. Тупо по шаблонам, шаблоны это еще верх надстройки типа квадрат, переход, генерировать новую мелодию, от нее взять четыре ноты в бас, там транспонировать, повторять до начала нового квадрата или конца 4.
Шаблоны прямо в коде задавал, в тупом формате midi а именно ноту от 0 до 127, можно было написать нечто типа G7 но не заморочился. Накидал десять шаблонов и потом ходил кайфовал, музыка от компа, и драйвовая (очень зависит от шаблонов, те же ударные).
Где то валяется этот проект, но его придется переписывать с нуля. Слишком костыльно. А почему два компа? Ну потому что настроить Reason и чисто программный комп в 2010 было попроще, хотя и тогда был виртуал миди.
markshevchenko
Очень здорово. Даже не ожидал узнать что-нибудь настолько интересное, когда писал свой комментарий. Спасибо, погружусь в изучение.
Табулатуры вижу регулярно в интернете, но их довольно трудно парсить, именно, с программистской точки зрения.
Сам в своё время освоил всё-таки ноты и успел купить Guitar Pro, чтобы их там вводить. Но я не настоящий музыкант, любитель, так что воспринимаю всё это как некую данность. Что-то придумывать в этой области не могу, не хватает знаний.
Refridgerator
На самом деле в этой области ещё непаханное поле. Я тоже недавно накидал черновик спецификации для аналогичной задачи, тоже потому, что ни одно из существующих решений не зашло. Как минимум, чтобы иметь возможность русскими буквами писать "ля ля ля фа" в перемешку с гитарными и ударными табулатурами.
LordDarklight
Очень любопытно! Я выше поделился отрывками из своих черновиков. Поделитесь тоже?
Refridgerator
Не вопрос, но чуть попозже. Может вообще стоит в виде отдельной статьи оформить, раз нашёлся хотя бы один человек, которому это тоже интересно)
Refridgerator
Вкратце: партитура разбивается на отдельные музыкальные фразы, оформленных в виде текстовых блоков с заголовком, например:
[гамма1]
до ре ми фа соль ля си +до
[гамма2]
до -си ля соль фа ми ре до
Я отказался от явного задания октавы в пользу контекста и служебных операторов. В данном примере "+" значит перескок на следующую октаву, а "-" соответственно вниз. Ноты октавы разбиваются в зависимости от тональности, до-мажор по умолчанию, другие задаются служебным оператором
@key:Am
Длительность задаётся справа от ноты в виде модификатора с умножением и/или делением:
до/4 ре/4 ми*3/2
Ноты можно объединять в группы, чтобы задать модификатор один на всех:
(до ре ми)*2/3 // триолька
Также для группы можно задать количество повторений:
(до ре ми)x3 // то же, что и до ре ми до ре ми до ре ми
Можно задать громкость для каждой ноты:
до'100 ре'50 ми'10
Также к ноте можно привязять произвольное количество атрибутов, которые секвенсор или синтезатор при желании сможет обработать:
до<vibrato:3,detune:30,pan:-1>
Диезы, бемоли - по классике:
до# до&
Но можно их ставить перед нотой, а тогда его действие продлится до следующего такта (по стандарту нотной записи). В качестве конца такта выступает символ "
|
" (ну а какой же ещё). В этом случае потребуется бекар, для него я выбрал символ "%
".Помимо символьного обозначения нот можно использовать числа для хроматических отклонений от последней известной:
до 2 4 // то же, что и до ре ми
Ноты можно объединять в аккорды фигурными скобками:
{до ми соль +до} // прозвучат одновременно
По умолчанию, когда начинается следующая нота, предыдущая завершается. С помощью префикса "
~
" её можно оставить звучать до явного завершения префиксом "!
". А "!!
" завершает все звучащие ноты сразу:~до ~ми !до ~соль !!
Вместо этого можно использовать несколько голосов, располагая их друг над другом:
:[1] . . си ~
:[2] . съ ~ ~
:[3] ми ~ ~ ~
Точка это пауза, одиночная тильда - продолжение звучания предыдущей ноты. Для ноты соль здесь использовано двух-буквенное сокращение, для всех нот также можно использовать стандартные латинские обозначения c d e f g а h.
Ну и таким образом можно нативно гитарные табы прописывать:
[:1 @root:64] 0 ~ ~ ~|5 ~ 7 ~ |
[:2 @root:59] 1 ~ ~ ~|5 ~ 6 ~ |
[:3 @root:55] 2 ~ ~ ~|5 ~ . . |
[:4 @root:40] . . . .|. . . . |
[:5 @root:35] 0 ~ ~ ~|0 ~ ~ ~ |
[:6 @root:30] . . . .|. . . . |
Как-то так.
Moog_Prodigy
Да, но вы знаете про трекерную музыку? Это совсем не MIDI, и хоть это не ЯП, но нечто похожее в самой идее.
LordDarklight
Конечно. Да - это отдельное направление - и да такие партитуры я тоже хочу поддерживать в виде текста - честно ни в одном трекерном редакторе я не нашёл комфорта в написании трекерной музыки ;-)
vtal007
Да, я понял. Вы увидели, как звукореж юзает планшет и поэтому
markshevchenko
Нет. Очевидно, вы не поняли. То, что тенденция есть, это уже из лекции Пирожкова я осознал. Но, видимо, такие темы не для вас. Можете не тратить ваше время.
inkelyad
Зря, кстати. Как раз те, что на авито (они и сейчас продаются) - и имеет смысл брать. В качестве второго компьютера-'пишущей машинки' и хождения по интернету совершенно замечательно подходит.
DarthVictor
Было бы желание. Вот например 4090FE в корпусе 5л.
Но это, конечно, для гиков. Обыватель наоборот будет использовать калорифер литров на сорок.
vtal007
ну это ж для фана. в массе своей в офисы и людям продают унылые черные коробки (кто-то домой покупает аквариумы. Во-первых это
красиво светится)у меня самого было nr200, но это совсем не типовая история
даже больше скажу, "сбор своего компа" это отдельное хобби (которое на пост-СССР живет из-за малых доходов + инженерная культура), для тех же американцев, можно просто купить готовый комп и не заморачиваться
собственно и у нас можно, но считается "фу, как ты мог" :)
мы то про тренды тут спорим, а то, что есть энтузиасты, так конечно есть, но они на масс-маркет не так чтобы влияют
вот кмк, начало популяризироваться SFF, китайцы наплодили неплохих корпусов. Но! внезапно, ITX материнки не дешевые (ну по крайне мере от а-брендов) и самое популярный формат mATX
Но повторю, сам формат ITX существует довольно давно (ну наверно как сам стандарт АТХ). и скорее можно сказать, что е-атх по сути мертво, а вот и корпуса и материнки АТХ вполне себе существуют. И пока этот формат есть, говорить о трендах по стремительному уменьшению корпусов мягко скажем опрометчиво
А те, маленькие коробки, с задушенными i3, конечно продаются, но что они реально меняют в плане трендов
VADemon
Нет, вопрос на 95% к позиции и мышлению (хобби). "Не заморачиваться" -- это для этих людей означает купить приставку (консоль).
А коим образом ПК сфера начала переживать ренессанс у западной публики (здесь, именно что, американской) - я так и не понял, но факт налицо. Опирающиеся на щедрые маркетинговые бюджеты (от билетов на перелеты до просто кучи (временно)бесплатных железок под тесты) и платеже- и донатоспособную публику, каналы типа LinusTechTips, GamersNexus, Hardware Unboxed ушатали вообще всех. Выросли настолько, что не боятся идти против маркетинговых команд, за что получали "баны" на железки для обзора.
vtal007
каналы типа LinusTechTips, GamersNexus, Hardware Unboxed
И примкнувшие к ним.. (и там же есть Дмитрий)
Кстати, может мне показалось, но они в большинстве канадцы
VADemon
LTT и Hardware Canucks - Канада; далее США и Австралия. Кроме Jayz 2 cents (побольше команда) остальные одиночки из США. Какого-то вменяемого присутствия остальных стран в этой тусовке я не вижу, кроме der8auer, который полноценно на обоих языках ведет канал(ы). Дальше идут текстовые публикации и при них каналы поменьше.
askharitonov
Они всё-таки становятся меньше, причём может даже несколько в ущерб функциональности (видел корпуса, где крепление под жёсткий диск просто не предусмотрено, предполагается, что будет SSD 2.5"). Ну и в целом современные системные блоки легче, разница хорошо заметна, если есть склад, на котором лежат старые системники, которые надо бы списать.
vtal007
какой ссд, все уже на m2 переходят. Но жесткие диски да, в бытовом смысле не нужны
но за счет того, что спереди не надо делать полку под ХДД, впереди ставят вентиляторы (то на то и выходит в классическом корпусе. Экономия по литражу есть у спец-корпусов - однообъемников, у меня есть от джонсбо d40 (или 41, не помню уже)
легче они потому что железо экономят. а не потому что "системные блоки сжимаются" :)
в общем и в целом, пока жив стандарт АТХ, никаких кардинальных изменений не будет. Потому что все делают под этот стандарт, все учитывают возможности систем охлаждения.
например, товарищ Хуанг с племяшкой наверняка могли бы выпустить более мощную видеокарту с ТДП ват этак в 1000. Но не выпускают, потому что ее будет сложно как разместить в корпусе, так и запитать и охладить (хотя инженерно задачча решаемая)
а те спец-версии процессоров с индексом t, ну не сказать чтобы какой-то тренд. и кажется и 10 лет назад выпускали. Ну или просто продавали целероны-атомы
arman_ka
сжимаются и с 4090 очень хорошо, но для программиста (не игр и не ии) видяха в целом мощная и не нужна, достаточно встройки
а про ноуты - стандарт индустрии это макбуки, вот и здрасте "обрезано"
сейчас эппл вот iPad выпустила на самом мощном их чипе
а вы продолжате мыслить как "ноут это не системник" - это такой же пк, просто удобнее.
понятно что если мыслить как вы, то и суперкомпьютеры до сих пор занимают целые здания, ну да, только в ту же площадь умещается большая производительность, но такая огромная производительность не всем нужна. Точнее большинству не нужна.
vtal007
Ну что значит "очень хорошо", когда Вы показываете крайне атипичный корпус? Поделитесь плиз сетапом, Вы ж наверняка знаете, а не просто дернули картинку с интернета
А причем тут программисты, когда обсуждали тренды на рынке десктопов
какой индустрии?
> "ноут это не системник" - это такой же пк, просто удобнее
Ноут и правда не системный блок. Да и удобство это относительное. Ноут - это набор компромиссов
ну да, производительность и правда растет, но тезис, с которым я спорил звучит так
Не "производительность растет на один кубический сантиметр", а именно объем системных блоков сжимается
novoselov
Ни жестами, ни голосам программировать не будут. IBM проводили исследования, за день человек тупо устает разговаривать. А еще поищите скорость передачи и восприятия информации через разные каналы, текст это самый быстрый способ на данный момент. Дальше только чипы в мозг.
markshevchenko
Ну, нет, так нет. Будут люди носить с собой лист ватмана, а также мышь и клавиатуру. Или возможны варианты. Я вот не думаю, что там надо будет прямо "разговаривать", скорее, время от времени произносить названия.
slonopotamus
Зачем что-то куда-то носить? =/
markshevchenko
Ну, я не знаю. Уже лет двадцать, как ноуты повсеместно используются. Не слышали?
slonopotamus
Ну вы нам про чудесное будущее рассказать пытаетесь. А там всё так же как и 20 лет назад.
markshevchenko
Нет, я просто размышляю. Для программиста это нормально — разминать мозги и думать на всякие интересные темы. Но, видимо, не для всякого программиста.
Похоже, есть и те, кому думать и фантазию включать неинтересно. Или нечем.
xSVPx
Эээ нет, не слышал.
Зачем разработчику ноутбук ? В офисе и дома у меня нормальные компьютеры. К слову сказать сосед проапгрейдился и его башня шире стандартной процентов на 30. Иначе не влезает водяное охлаждение ;(. Гроб громадный.
В командировке ? Все последние разы мне выдавали тачку на месте сразу же, и я мог запускать на ней свои контейнеры привезенные на флешке.
В метро я не программирую. Зачем ноутбук непонятно.
Кстати еще лет 10-15 назад ноутбук в командировки приходилось возить. Чтобы не копаться с настроенным окружением итп. Сейчас работая в виртуалках это слава богу не нужно.
markshevchenko
Вы очень странные вещи пишите, серьёзно. Мне выдают ноут на работе последние лет десять, наверное. Но дело даже не в этом.
Вы тратите свои аргументы впустую. Цель моего комментария была — пофантазировать на тему, затронутую в статье, потому что она мне близка, возможно, вызвать кого-то на обсуждение и моделирование, какими могли бы быть удачные визуальные языки программирования.
Вы докопались к отдельной детали, и мы просто зря тратим время на её обсуждение. Ну, живёте вы в вашем мире с тауэрами, и живите. Это просто значит, что обсуждение перспективных идей не для вас.
slonopotamus
Ну выдали ноутбук, допустим. Мне вон тоже выдали. Таскать-то его зачем и куда?)
markshevchenko
Я ещё раз повторю: вы докопались до детали, совершенно упустив основной посыл. Вам заняться нечем?
Groramar
В метро я не программирую. Зачем ноутбук непонятно.
Удобно на пузе держать, вот сейчас так пишу )))
У меня уже 7-й нотбук за 20+ лет программирования. Стационарных вообще не покупал для работы. Удобно во всех смыслах и за это время стало только еще лучше.
xSVPx
Вы лежа работаете что-ли? Я сидя, у меня какой-то монитор размером с современный телевизор, удобная клавиатура и мышь. Мой системник имеет детали купить которые я могу в течении пары часов, и вообще он неплохо охлаждается кучей вентиляторов, стоит в отдельном помещении и я его не выключаю неделями.
Зачем мне ноутбук? Чем он лучше то ? Он менее надёжен, медленнее (особенно за те же деньги), у него неудобная клавиатура, мышь, маленький экран. Чего себя мучать-то ?
Я понимаю, когда зачем-то нужна мобильность. Там да, приходится терпеть. Но разработчику то зачем ?
LordDarklight
С Вами соглашусь в том, что будущее за декларативными языками программирования! Но... вот визуализациям им, средство ввода исходника, нафиг не нужна будет - хотя... как некоторое подспорье в ряде случаев - будет полезно - но только как вспомогательный инструмент - условно когда надо глянуть на итоговую схему, прогнать тесты и отладку, быстро переключить какие-то оптации!
Но, всё же - основной код буду набирать и редактировать в текстовом представлении! Причём декларативность тут позволяет писать его очень абстрактно, разбрасывать по куче мест - и потом всё это будет собираться вместе - а итоговый код строиться на основе статической интерпретации всего этого декларативного и макро описания!
markshevchenko
Возможно, от клавиатуры и мыши никуда не деться. Но вообще интересно пофантазировать, если языки будут визуальными, то какими?
LordDarklight
Какие варианты?
Лично я считаю что тут не может быть какого-то приоритетного визуального представления - всё это очень специфично и индивидуально - то есть визуальный ЯП просто должен иметь несколько визуальных представлений (выбор между которыми будет зависеть от самого кода/задачи, от предпочтений разработчика, инструментальной базы IDE). И само собой, обязательно, должен иметь и текстовое представление! И да - так же будет прямая зависимость и от текстового синтаксиса и общей семантики такого ЯП. Здесь нет какого-то одного верного решения!
Но подчеркну - вряд такая визуализация как средство ввода алгоритма станет маломальский популярна - от того и развиваться она будет очень медленно!
markshevchenko
Мне тоже кажется, что не будет одного варианта, а будет несколько.
Есть, правда, идея, что все программы могут быть представлены, как в LISP. Каждое S-выражение из LISP можно нарисовать в виде дерева. Наверное, эти рисунки будут визуально громоздки, так как сложные математические формулы будут представлены как большие куски деревьев, похожих на абстрактные синтаксические деревья.
Но, возможно, это будет только начало.
Mishootk
Компьютер превращается в инструмент решения задач. Иметь компьютер ради компьютера - вариант все менее и менее популярный. В основном в учебных целях. Раньше для прослушивания музыки и просмотра фильмов был период, когда компьютер очень сильно выручал. Сейчас муззыку слушаем без экрана (умные колонки), видеоконтентом пользуемся довольствуясь классическим набором телеэкран+пульт.
К чему я? Для решения задач интерфейсы взаимодействия уйдут в узкую специализацию. Возможно и программирование ждет то же самое.
Murtagy
Интересное наблюдение. Звучит логично