Не верю в no-code

Волны хайпа вокруг no-code выросли до невероятных масштабов, и недавняя отличная статья vas3k по этой теме заставила меня вновь направить туда вектор внимания. К тому же самые бросающиеся в глаза атрибуты no-code вроде визуального программирования и data-enhanced programming были где-то в зоне моих рабочих интересов последние пару лет.

Нагло укравВдохновившись идеей, я решил создать себе бота, который бы каждое утро нежно встречал меня приветствием, списком дел на сегодня и интересными метриками. Такой персональный ассистент, но для бедных. Создать бота в телеграме и начать отправлять себе сообщения через HTTP API заняло 2 минуты, и это была самая лёгкая часть пути.

Для MVF я поставил цель хотя бы присылать список событий из календаря на день. Потом добавить эмоджи — и можно жить. Попробую на примере этого конкретного сценария рассказать, почему я не очень верю в no-code в том виде, в котором нам его сегодня продают.

Сразу сделаю ремарку: дальше по тексту это всё не критика конкретных инструментов и и людей их создающих, а вопросы о подходах и концепциях.

Проблемки

Я уже был немного знаком с IFTTT и Zapier, так что решил начать эксперимент с них.

Здесь мы сразу натыкаемся на одну из главных проблем no-code продуктов: ты ограничен триггерами и действиями, добавленными разработчиками тулов. Ни Zapier ни IFTTT не дают тебе возможности взять все события из календаря за день. Тут работает классика нашей индустрии: продакт оунеры подумали за тебя и решили что тебе это не нужно, пользователям наверное надо в основном реагировать на добавление событий в календарь.

От упомянутого в статье integromat.io больше отдаёт духом "сделано программистами", и в данном контексте это хорошо. Тут уже есть нужный мне триггер "найди все события в календаре за период времени", отлично. К сожалению, дальше мы натыкаемся на вторую проблему no-code тулов: они пытаются всеми силами защитить пользователей от написания любого кода, даже там, где он уместен. А вместо этого предлагают накликивать недо-код мышкой.

У пользователей тысячи разных юзкейсов, невозможно вынести их все в чекбоксы, дроп-дауны и другие опции в настройках. Вот мне нужно найти все события календаря с 9 утра и до конца дня, а условному Пете надо найти события в ближайший час. Как предлагают удовлетворить все такие наши хотелки в no-code мире? Конечно через функции. Которые как бы код, но всё-таки no-code код, ведь мы тут решаем задачи автоматизации без написания кода 🤷‍♂️

В хорошем случае нам дадут обширную библиотеку готовых функций. В отличном случае нам дадут возможность писать свои функции на каком-нибудь JavaScript (исполняться они правда скорее всего будут на AWS Lambda с холодным стартом в секунду и жёсткими лимитами на ресурсы, но для домашних автоматизаторов сойдёт). В обычном случае нам дадут 10 функций, тщательно отобранных продакт оунерами, чтобы случаем не отпугнуть пользователей СЛОЖНОСТЬЮ.

К сожалению, в integromat на нашлось функции endOfDay, чтобы найти все события до конца дня, но я знаю что триггер срабатывает в 9 утра, так что подкостылим и выберем всё, что начинается в ближайшие 15 часов.

События получены, теперь бы отправить их текстом в телеграм. Тут мы проворачиваем тот же ментальный трюк: продукт у нас как бы no-code, но по workflow летают какие-то коллекции объектов, и надо их превратить в текст, но делать это без кода. Как разработчик, я знаю что мне нужно что-то вроде такой функции:

events.map(e => e.name).join(', ')

Опираясь на интуицию, я накликиваю что-то такое:

Да, тут действительно надо мышкой перетаскивать функции в редактор, просто так написать map не выйдет. Мой главный вопрос: чем такой no-code-код проще code-кода или какого-нибудь шаблонизатора или DSL? Если для решения задачи нужно техническое мышление и понимание базовых концепций обработки данных (условия, агрегации, трансформации), то зачем прятать от пользователя код за кодоподобными графическими элементами?

Справедливости ради, я могу придумать несколько причин.

Чем хорош no-code

Если ты дашь программисту задачу написать такую интеграцию календаря с телеграмом, то с большой вероятностью на выходе получишь одну из двух крайностей:

  • Полотно кода, выполняющее сценарий в одной огромной функции на 1000 строк
    • С hard-coded токенами
    • С кусками кода, скопированными из разных ответов StackOverflow, работающих вместе по чистой случайности в 2 случаях из 3
  • Over-engineered проект с кучей ненужных слоёв и абстракций
    • Генерализованный модуль работы с любыми календарями, ну чтобы потом чуть что можно было просто смигрировать с Google на Microsoft
    • Подсистема отправки любых нотификаций в любые системы, при этом для тела нотификаций будет использован не текст, а абстракция документа с вложенными блоками и узлами. Красиво, расширяемо.

Графический редактор workflow вынуждает тебя дробить работу на мелкие шаги, выполняющие ровно одно действие, и визуализирует data flow, позволяя быстро окинуть взглядом весь сценарий. Конечно всё это можно сделать и в коде, но в реальности программистам постоянно что-то мешает.

Инфраструктура

Ещё более крутая штука этих инструментов — это то, что мне не надо писать инфраструктурный код для интеграции с сервисами. Вот серьёзно, для меня это прямо основной ментальный блокер — каждый раз, когда я думаю над каким-то скриптом, в моей голове звучит пугающая мысль "ой сейчас же придётся тратить время чтобы разобраться как у них там устроены авторизации в API, как регистрировать клиента, как хранить токены".

Это не сложные, а просто крайне скучные и неинтересные задачи. Я хочу потратить время на бизнес-домен и решение моей проблемы, а не на разбор элегантных подходов и костылей, принятых разработчиками сторонних сервисов в их API.

Вторая инфраструктурная вещь это стандартизированное и униформное логирование событий и обработка ошибок. Нанятные бизнесом разработчики, как правило, не очень хороши в этом, чаще всего они останавливаются на бесполезных логах вроде

INFO: Operation started
ERROR: Error occurred

Попробованные мной no-code инструменты показывают на UI детальные логи исполнения workflow — какие данные были переданы, какое действие отработало, а где произошла ошибка, что очень упрощает процесс настройки и отладки.

Как сделать лучше

Сейчас no-code инструменты часто пытаются решить не совсем те проблемы, с которыми сталкиваются "not so technical users". На мой взгляд, написание доменного кода для преобразования данных не сильно сложнее, чем накликивание такого же data flow через UI.

Пользователям не нужен визуальный редактор для накликивания формул, им надо избавиться от скучной, рутинной и местами непонятной не-программистам работы по интеграции со сторонними сервисами. А упрощение написания этого кода для обработки данных достигается через хорошую систему подсказок в редакторе, которая показывает пользователю какие API есть у сервиса, какие данные есть в триггерах, какие функции можно вызывать на этих данных.

Например, редактор используемый в Visual Studio Code, доступен в виде библиотеки Monaco Editor, к нему можно прикрутить очень богатую систему подсказок, что мы и сделали в Targetprocess.

Помогаем с кодом

Одна из фич, над которой я работал, как раз позволяет настраивать внутренние автоматизации — вещи вроде "когда создан баг, автоматически назначь его на подходящего человека". Мы тоже начали с UI-элементов для бизнес-действий вроде "добавить комментарий", "перевести в такой-то стейт", "обновить сущность".

Однако мы быстро сообразили, что у пользователей гораздо больше сценариев, чем мы можем представить и реализовать за пару месяцев, поэтому мы сфокусировались на том, чтобы дать им возможность описывать эти сценарии кодом (мы выбрали JavaScript), и сделали для них sandbox и редактор, интегрированные с доменом и API.

Например, когда пользователь создаёт сценарий, реагирующий на изменение стейта юзер стори, мы в редакторе подсказываем какие поля есть у этой изменённой юзер стори.

Когда пользователю надо работать с Targetprocess API, мы пробрасываем в контекст исполнения скрипта специальный клиент, который уже прозрачно для пользователя авторизован, который умеет работать с HTTP-редиректами, делать retry, логировать все запросы и т.д. Кроме того, редактор тоже знает про возможности этого клиента, и подсказывает пользователю, какие действия он может совершить с API.

Кстати, здесь интересный side-note для любителей функционального программирования [1]

Мне кажется, здесь можно найти очень классный баланс между простотой графических редакторов и мощностью кода — давайте писать мелкие скрипты, преобразующие данные, заворачивать их в визуальные блоки и строить из них workflow. Блоки можно сделать параметризуемыми, и тогда даже дать возможность пользователям переиспользовать их.

Тогда моя изначальная задача решалась бы таким вот скриптом. Его output можно направить напрямую в блок "Send HTTP request".

import {getEvents} from 'google/calendar';
import {now, endOfDay} from 'dates';

const events = getEvents({
  from: now(),
  to: endOfDay(now())
});

if (events.length > 0) {
  return 'Events for today: ' + events.map('name').join(', ');
}

return 'No events for today';

Фильтры и DSL

Такой же редактор можно использовать и для фильтрации данных через DSL вместо гигантских визуальные фильтров (кстати, типичная их проблема — использование AND и OR, ещё не видел ни одного элегантного подхода).

Сравните следующий скрин с текстовым фильтром:

(Organizer.Email.Contains("John") AND DateStart > Now.AddDays(10))
OR Description.Contains("URGENT")

Тут можно возразить, что надо ещё догадаться как текстовый фильтр написать, и да, порог входа здесь немного выше, но опять же хороший редактор очень облегчает эту задачу. Немного синтетический пример:

Например, мы использовали такой подход для редактора формул, добавив в подсказки знание о домене.

Выводы

  • No-code инструменты классные тем, что прячут от пользователя логику интеграции с сервисами — авторизация, профили, поддержка нескольких аккаунтов, а не то, что теперь вместо написания функции map я кликаю по ней в UI.
  • Data samples и data suggestions это круто. No-code выглядят привлекательно потому что прямо "не отходя от кассы" пользователи видят shape данных, пришедших из интеграции. Я вижу здесь какие-то аналогии со статической типизацией — инструмент как компилятор не даёт мне совершить ошибку и подсказывает что я могу использовать.
    • Я бы очень хотел увидеть развитие data-enhanced программирования и его приход в мейнстрим индустрии
  • Пользователям не надо думать о хостинге и инфраструктуре. Это никак не заслуга no-code, но вполне себе selling point.
  • Визуальное программирование формул не нужно. Ты всё равно с ним мыслишь как при написании кода — так дайте возможность использовать полноценный язык программирования.
  • В простых сценариях лучше дать пользователю DSL с подсказками (в дополнение к ЯП, а не вместо него), чем средства визуального программирования.
  • Идея "теперь не надо писать код, так что творить смогут не только привилегированный 1% technical people" ложная и не приживётся, но пока на ней удаётся зарабатывать шарлатанамграмотным предпринимателям. Всё как обычно. Разработчики пока всё ещё нужны.

  1. Мы старались дизайнить окружение так, чтобы пользователи писали скрипты, похожие на чистые функции. На входе у них данные о триггерах, на выходе — описание сайд-эффектов, которые надо исполнить (обновить поле у сущности, добавить комментарий, сделать HTTP-запрос). Сами скрипты не должны совершать никаких мутаций. Такой подход даёт много клёвых фич — полученные сайд-эффекты можно анализировать, автоматически батчить, проверять на наличие циклов, логировать их детали в логах. Отчаянно рекомендую этот подход. ↩︎