Published on

Я опубликовал приложение для iOS с ClojureScript и React Native

Outboard

Последние несколько лет я вел в приложении Notes.app список ресторанов, походов, баров и других мест, которые я собирался посетить. Он был беспорядочным, не имел географической привязки, и его трудно было быстро пополнять. Не найдя удовлетворительных решений в других местах, я решил почесать свой собственный зуд и создать приложение, достойное места на моем домашнем экране. Outboard - это результат последних пяти месяцев работы над сайд-проектом, созданным на ClojureScript на React Native.

До этого я создал пару приложений на Objective-C и мне нравится Swift как язык, так почему же именно этот стек? Познакомившись с функциональной реактивной моделью в интерпретации Re-frame, мне теперь сложно подходить к реализации пользовательского интерфейса как-то иначе. Добавьте сюда горячую перезагрузку и Clojure REPL, и ClojureScript на React Native стал очевидным выбором. Ниже перечислены плюсы и минусы, с которыми я столкнулся на этом пути.

Плюсы

Функциональное реактивное программирование

Рискуя преувеличить с самого начала, я просто больше не сталкиваюсь с ошибками на пересечении состояния и пользовательского интерфейса. Целый класс дефектов, с которыми я боролся на протяжении последних десяти с лишним лет профессиональной разработки программного обеспечения, практически исчез. Нет больше слегка не синхронизированных экранов, нет больше ссылок на мертвые данные; все исчезло. Вместо этого появился легкий, не требующий особых церемоний и шаблонов фреймворк Re-frame, который делает манипуляции с данными простыми и понятными, когда вы возвращаетесь к старому коду в будущем. На мой взгляд, Re-frame является убийственным применением философии Clojure на переднем крае.

Разработка на основе REPL

Возможность экспериментировать с изменениями макета приложения или его состояния в симуляторе iOS очень важна для скорости разработки. Если я хочу узнать, как определенный набор данных может выглядеть на устройстве, я могу оценить одну строку в REPL, и результаты мгновенно появятся на экране. Нет никакого сравнения с повторной компиляцией и ручным обновлением данных.

Синтаксис икоты

Возможно, это больше личное предпочтение, обусловленное опытом, но мне гораздо легче работать с версткой приложений с помощью Flexbox и Hiccup, чем с конструктором интерфейсов XCode. Я никогда не считал систему ограничений Apple для управления различными размерами и разрешениями устройств интуитивно понятной, но Flexbox позволяет мне использовать имеющийся у меня (скудный) опыт веб-дизайна для создания разумно отзывчивого дизайна приложений.

Доступность библиотеки

Сообщество React Native на данный момент охватывает широкий спектр компаний с большими инвестициями, что приводит к появлению хорошей стабильности хорошо поддерживаемых библиотек для дополнительной функциональности. Некоторые из них я использовал:

Все эти модули являются нативными для Javascript, но их легко интегрировать в ClojureScript.

Нативные модули

Для некоторых вещей, которые мне нужно было сделать, не было уже создано ни одной библиотеки React Native, но создание функциональности для таких вещей, как хранение данных в App Groups и геокодирование адресов с помощью MapKit на Swift и передача ее в слой ClojureScript было простым и станет темой следующего поста.

Согласие

Однако не все было так радужно и солнечно.

Несоответствие инструментов

Самой большой проблемой, с которой я столкнулся, была работа над глубоким стеком, где слои уходили друг у друга из-под ног, иногда без предупреждения. Мне нравится использовать ClojureScript, но он создает еще один слой абстракции поверх шаткого фундамента из NPM, Javascript и React Native, которые находятся в постоянном движении.

Острые углы React Native

React Native, в частности, подвержен частым изменениям. По большей части мне удавалось сидеть на заблокированной версии React Native, но иногда добавление библиотеки требовало обновления самой React Native. Процесс обновления исключительно хрупок и требует ручного git-слияния больших файлов Info.plist.

Проблемы с упаковщиком

Одна из острых проблем, возникающих из-за несоответствия инструментов, связана с упаковщиком React Native, Metro. ClojureScript использует совершенно другой компилятор и упаковщик в Google Closure, и их совместное использование неэффективно; смотрите, например, этот выпуск, где документируются проблемы нехватки памяти и времени, когда Metro медленно пытается упаковать уже упакованный файл ClojureScript. Даже без дополнительных сложностей, связанных с Closure, Metro может вывести из себя - однажды я "решил" проблему с его кэшем после часа следования десяткам предложенных решений из темы на Github, просто переименовав каталог, в котором жил проект.

Планы на будущее

Я доволен своим релизом 1.0 и использую его ежедневно, время от времени внося изменения в пользовательский интерфейс или исправляя ошибки. Тем не менее, у меня есть планы на большие будущие возможности.

Синхронизация

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

Альтернативные устройства

Я также хотел бы добавить клиентов для iPad и настольных компьютеров; опять же, возможность повторно использовать модель данных с соответствующим слоем пользовательского интерфейса поверх нее должна быть полезной.

Заключение

Есть компромиссы, но если все взвесить, я бы снова выбрал ClojureScript на React Native для приложений такого класса. Скорость и надежность основной части процесса разработки трудно превзойти, и они перевешивают несоответствие инструментов и иногда возникающие проблемы незрелости экосистемы.