Интервью с создателем Notebox, Бакутой Андреем

Мне посчастливилось взять интервью у Бакуты Андрея, создателя приложения для хранения заметок Notebox. Так сказать из первых рук! Он рассказывал больше о десктопном приложении, о технологиях, процессе создания, что впечатлило и проч. Так как это его первое приложение под десктоп, и совсем недавно был первый релиз. 

- Расскажи про десктопный Notebox. 

- В общем, стек. Это clojure, это cljfx (библиотека, которая является надстройкой над JavaFX); да в принципе и всё. Так что стек очень небольшой получается. Тот же luggage, который у нас повсеместно используется: и в мобильных приложениях, и веб-приложениях, вот его использовать не получилось, потому что в данном случае мы работаем не в браузерном окружении. Поэтому попутно было написано некое подобие этого luggage'а, пока что минимальное. Я даже не уверен, что я написал функции для записи файлов. Потому что из десктопного Notebox'а я ничего не пишу, только читаю, соответственно для десктопного приложения я реализовал ту часть лагеджа, которая занимается чтением. Реализовал на Java, используя JavaSDK для Dropbox; тогда как в лагедже используется JS SDK для Dropbox. Интересно было повторить функциональность лагеджа, но уже на другом языке.

Ещё из интересного то, что автор cljfx сделал не просто тонкую надстройку над JavaFX, которая бы просто чуть-чуть приукрашала JavaFX API... я бы сказал, что оно его не украшает, а полностью преображает. То есть если JavaFX API — это просто набор классов, с помощью которых ты строишь интерфейс, ну классы типа Scene... Потом, что у нас на Scene может быть? Какая-нибудь StackPanel, внутри него VBoxView (аналог div), внутри VBoxView у нас еще парочка VBoxView, внутри которых парочка HBoxView (также аналог div, но уже с display: flex) и в них там какие-нибудь Buttons, Labels и т. д. Представь себе дерево из классов классов классов. Т. е. чтобы создать сцену мы инстанцируем класс сцены, в нём как-то вызываем методы этого инстанса, чтобы туда пропихнуть какой-то контент, а этот контент из себя представляет тоже инстансы других классов, и контент туда мы запихнули тоже вызовами методов. То есть очень и очень императивное API у этого JavaFX, и оно прям вообще такое. Смотришь туториал по JavaFX, и у тебя один класс; внутри этого классы мы занимаемся тем, что инстанцируем другие классы. Что можно было бы сделать при написании своей clojure обертки? Во-первых, можно было ничего не делать. Из clojure джаву можно запросто вызывать, т. е. можно было бы заимпортировать эти самые JavaFX классы и начать фигачить как на джаве, только на clojure. Так как у clojure есть синтаксис создания инстанса, есть синтаксис вызова метода, есть синтаксис обращения к проперти. Он естественно отличается от того, что мы имеем в Java, потому что это все-таки лисп, но синтаксис есть и интероп (взаимодействие с джава кодом) там прям офигенный. То есть можно было бы вообще ничего не делать. Можно было бы взять голый JavaFX и начать строить на нём приложение. А можно было бы написать очень тонкую обёртку, которая вместо того, чтобы инстанцировать классы, позволяет дергать какие-то функции, которые под капотом инстанцируют классы. Но чувак (создатель cljfx — прим. редактора) пошёл дальше, он сделал полностью декларативное API, где ты интерфейс описываешь кложуровскими структурами данных. Т. е. похоже на то, как мы делаем в React'е, только в React'е мы описываем интерфейс с помощью JSX, здесь мы описываем интерфейс с помощью кложуровских структур данных, т. е. с помощью векторов и мапов. Т. е. очень круто! Чувак пошёл дальше, видно, что он проникся идеями re-frame, и он в свой фреймворк тоже попытался заложить эти идеи, т. о. у нас есть одна большая структура данных, в которой хранится всё состояние приложения как в re-frame'e, как в Redux'e, и наши вьюхи реагируют на изменения этой структуры данных. Т. е. мы как-то меняем эту структуру данных, и вьюхи тут же перерендериваются.

Естественно, есть способ доступа к этим данных, некий аналог реактовских селекторов, и есть способ записи этих данных, тут можно было бы сказать аналог реактовских экшенов, но там это не совсем так, так как нет редьюсеров, поэтому и нет экшенов. Данные пишутся скорее как в re-frame'e, через events и effects (ивенты и эффекты). На любое действие пользователя и на любое действие, порождаемое действиями пользователя, скорее всего есть событие, например, в моём случае fetch-book или search-in-book (событие, которое может породить пользователь тем, что он вобьёт что-то в строку поиска, и мы вызовем событие search-in-book). У нас есть описание этого события, оно в свою очередь может породить ещё два события: search-in-fetched-books (поиск в тех книжках, которые были скачаны) – это перове событие, а второе — fetch-more-books (скачай ещё больше книжек). И что из себя представляет событие? Это некий мультиметод, который диспатчится по имени события, и принимает некий payload, и в зависимости от того, что это за событие и что это за payload, это событие может вернуть 1 или несколько эффектов. Эффектом может быть новое событие, может быть запись в глобальное хранилище и может быть любой твой кастомный эффект. Например, ты можешь запросить аутентификацию: ты описываешь событие, и для того, чтобы оно корректно отработало, тебе нужен залогиненный пользователь. Ты в событии проверяешь, что пользователь не залогинен, например, смотришь куда-то в свою глобальную структуру данных по ключу :dropbox-token, не находишь его и соответственно возвращаешь некий эффект create-user, fetch-user или authenticate-user. Неважно как назовешь. И у тебя в другом месте, не там, где ты определяешь события, есть описание этих эффектов, реализация того, что конкретно должно происходить. Т. е. эффект в ивенте — это просто ключ в мапе, который возвращается ивентом. Значением по ключу уже будет пейлоад для эффекта. Например, тебя есть ключ authenticate-user; ты пишешь, что authenticate-user на самом деле – это вызов методов Dropbox SDK, которые уже полезую в сеть, полезут в файловую систему, ещё куда-то читать файлы с креденшелами и т. д. Вот, чувак такую систему привнёс в свой (уже наверное) фреймворк... Ну JavaFX — это уже фрэймворк для написания десктоп приложений, а тут он ещё его сделал более opinionated фреймворком. И теперь это фреймворк, в который он заложил систему управления состоянием. А идеи для этой системы он взял уже из рефрейма. Что очень круто!Это кстати позволило в какой-то момент буквально пятью строчками реализовать оффлайн режим. Так как всё состояние хранится в одной структуре, которое легко сериализуется, то собственно в этих 5 строчках я как раз и занимался тем, что при выходе из приложения сериализовывал состояние и сохранял его на диск. А при старте я это состояние извлекал из файловой системы, десериализовывал и использовал его как начальное состояние для всего приложения. Реально заняло 5 строчек.

Что ещё интересного можно рассказать про приложение? Получилось полностью автоматизировать билд, чего я не ожидал. Опять же, я подсмотрел как это делают другие умные ребята на гитхабе. Благо сейчас можно найти опенсорсные приложения, которые приложения от начала до конца: и сорцы есть, и билд-скрипты, и у тебя уже есть страничка, на которой ты можешь дать возможность скачать исполняемые файлы. Это всё было успешно украдено. И реализовано для конкретно моего приложения. Т. е. приложение собирается автоматически при каждом мерже нового тега, в моем случае это не просто мерж в main, а пуш какого-то тега. Так что, если я хочу обновить приложение, то я просто создаю тег с новой версией, делаю пуш, и у меня появляется новая версия приложения. Естественно, если проходит билд.

cljfx не совсем похож re-frame идейно, но реализация всё-таки отличается. В том же рефрэйме ивенты создаются с помощью, по-моему, специальных или макросов, или функций, а здесь ивенты создаются с помощью мультиметодов. Т. е. синтаксис отличается, реализация отличается, но идеи схожи. Это для тех, кто знает что такое re-frame.

Да, из интересного, я сейчас подумал, ммм... как-то по-другому начинаешь смотреть на веб-интерфейс. То, что ты считал прям таким вот стандартным, скучным, дефолтным, приобретает новую ценность и новые краски. Элементарно какой-нибудь position: sticky... или position: fixed, ещё проще чем sticky, когда ты как бы реализовываешь такой же эффект, но какими-то другими средствами, начинаешь по-другому всё это ценить.

Или та же возможность выделить всё на странице, выделить вообще любой текст. Когда ты пишешь десктопные приложения, ты понимаешь, что это на самом деле ФИЧА и нихрена себе фича! Т. е. выделять произвольный текст в приложении... это для тех, кто всё время писал десктоп, и потом они б такое увидели в вебе, для них это должен быть вообще взрыв мозга. Потому что выделять текст можно где? В input'ах, в textarea'ах, в тех местах, где ты редактируешь. Там можно выделять текст.

Вот. Ну и да, на позиционирование как-то смотришь уже по-другому, когда у тебя нет, например, margin'ов, если одни padding'и. Ты понимаешь, что в принципе этого достаточно.

- А тебе не кажется, что margin'ы лишние в вебе? Они создают какую-то мешанину? И путаницу когда что использовать.

- Ну да, создают. Потому что вроде бы у них есть своя семантика. Ты padding'ами отбиваешь место внутри контейнера. Т. е. у тебя есть контейнер, внутри него есть контент, и тебе нужно этот контент отдалить от границ контейнера, и ты делаешь это padding'ами. А margin'ами ты создаешь расстояние между контейнерами. Но это блин семантика, которая есть у меня в голове, а у другого программиста будет некая другая семантика, и вообще другой способ, и другие привычки использования этих margin'ов и padding'ов. Так что да, определённо вносит путаницу, и с этим не поспоришь. Сто процентов.

Ну и да, конечно раздражает, что тот же JavaFX реально уже устарел, хотя удивительно, что альтернатив не так много (не так много новых фреймворков для написания десктопа). Да, есть всякие React Native Desktop, Flutter for Desktop, ну всякие Electron'ы мы вообще в расчёт не берём, так как больше чего-то нативного хочется. На той же джаве, по-моему, ничего нового после JavaFX не появилось. Казалось бы, JavaFX это должен быть прям новьё-новьё, при этом если взять те же компоненты для отрисовки веб-контента, то они из себя представляют какие-то старые браузеры, встроенные в десктоп. Действительно старые, потому что я попытался сделать аутентификацию через Dropbox прям внутри десктопного приложения, то есть сделать некий WebView, которым бы мог управлять, в который я мог бы отправить юзера для того, чтобы он там получил свой токен, вернулся в моё десктопное приложение, не выходя из него, и тут же получил доступ к дропбоксу. Но не тут то было! Там Dropbox начал сразу ругаться на то, что у нас устаревшая версия браузера, которая то ли https не особо поддерживала, то ли какие-то проблемы с сертификатами были. Ну в общем, тот WebView, который позволяет рисовать JavaFX, представляет из себя устаревший браузер. Так что от идеи пришлось отказаться, и за токеном мы перенаправляем пользователя в системный браузер, в котором он логинится и оттуда забирает токен в виде строки, и уже сам возвращается в десктопное приложение. То есть к чему я? Фреймворки для разработки десктопных приложений потихоньку загибаются. Все смотрят в веб. Ну или да, на мобильные платформы.

- Угу, если можно разрабатывать сразу под несколько платформ (под мобилу, под десктоп, под веб), зачем париться и отдельно писать?

- Ну, с одной стороны да, с другой стороны user expirience точно будет страдать, если мы будем пытаться одно приложение разрабатывать под настолько разные платформы. Android и iOS — это уже платформы, которые достаточно отличаются, чтобы приложение, которое работает одновременно и там, и там, работало весьма посредственно и там, и там. Т. е. уже user experience бы пострадал, а если мы добавим к этому десктоп, то 100% где-то приложение будет работать хуже, чем ожидает юзер.

- А тебе не кажется, что вообще десктопные приложения уходят в Лету?

- Ну да, да, есть такое. Кажется. *смеется* Кажется.

- И тем ни менее ты написал приложение.

- Ну да, интересно же повторить опыт предков, тех самых доисторических людей, которые писали под десктоп.

- С которых собственно всё и началось.

- Угу. Ну и идея ещё была — проверить насколько опыт разработки веб-приложений можно перенести на десктоп. Вполне можно, когда идёшь по проторенной дорожке, когда до тебя некие люди постарались перенести свой опыт. Тот же опыт с рефреймом. Это очень круто!


Комментарии

Популярные сообщения из этого блога

Стайлгайд и компонентная разработка

Прогноз погоды в консоли

Погружение в React Native: навигация, работа оффлайн, пуш нотификации