TL;DR
Мы написали классный кодогенератор для iOS-разработки, обладающий следующими достоинствами:
- Поддержка Swift и Objective-C,
- Использование языка разметки liquid для создания шаблонов,
- Гибкая система управления шаблонами,
- Интеграция с менеджером зависимостей Cocoapods.
Больше подробностей — под катом.
Серьезные решения, касающиеся архитектуры проекта, несут за собой необходимость принятия определенного компромисса. Придерживаемся n-tier структуры — получаем некоторое количество пустых пробросов информации между слоями. Распараллеливаем задачи на несколько потоков — тратим огромное количество времени на решение неочевидных багов. В похожей ситуации, требующей принятия компромисса, столкнулись и мы в Rambler&Co, принимая решение использовать VIPER в качестве стандарта архитектуры всех наших мобильных приложений. Получив отличную модульность и четкое разделение ответственностей компонентов, мы приобрели головную боль в виде сложности и монотонности процесса создания новых модулей.
Среднестатистический iOS разработчик в начале работ над новым экраном просто создает один класс. Тот, кто принял волевое решение перейти на VIPER, в этот момент начинает страдать. В большинстве случаев ему требуется создать пять классов, шесть протоколов и написать пять тест-кейсов. Допустим, что для создания новых модулей наш бедолага наймет профессиональную секретаршу с огромной скоростью печати — но даже в таком случае он вряд ли сможет выйти за рамки 30 секунд на создание и заполнение одного файла. Применим те небольшие знания математики, которыми наделила природа мобильных разработчиков, перемножим эти числа и получим ответ в районе 10 минут. Тот самый среднестатистический разработчик за это же время успеет накидать пару сотен строк UITableViewDataSource, отправить несколько сетевых запросов и покрасить все view’шки в красивый лазурный цвет. Как-то несправедливо по отношению к труду нашего VIPER-гуру.
А ведь тяжелый и нудный ручной труд является не единственной проблемой. Не меньше головной боли приносят множащиеся с каждым модулем опечатки, которые с каждым днем все сильнее и сильнее утягивают проект на илистое дно сорванных сроков.
Одним из способов решения указанных проблем, которым долгое время пользовались и мы — это создание своих собственных шаблонов для Xcode. Не считая того, что такой подход просто не спортивен, для себя мы выделили еще ряд относительно серьезных недостатков.
- Xcode — не самая стабильная IDE, и периодически при его обновлениях шаблоны, плагины и прочий обвес могут успешно слетать.
- Нет удобного механизма добавления новых шаблонов, не говоря уже о получении обновлений.
- Принципиально отсутствует возможность добавления генерируемых файлов в разные таргеты проекта.
- Синтаксис бесконечно неудобный и сложный, особенно для того, кому нужно за десять минут просто накидать шаблон для проекта.
Но, конечно, все понимают, что больше всего расстраивал еще один, фатальный, недостаток — решение написано не нами. Контроля над ним слишком мало, а расширяемость для более специфичных задач стремится к нулю. Поэтому мы и решили написать свой кодогенератор — Генерамбу. Сразу же уточню очень важный тезис — хоть мы и приступили к проекту для того, чтобы упростить процесс создания VIPER модулей, но в результате получили куда более гибкую утилиту, которая может помочь в автоматизации широкого спектра задач по генерации и стандартизации кода.
С момента установки Генерамбы (gem install generamba) до создания своего первого модуля нужно пройти три шага:
- generamba setup запускает процесс настройки Генерамбы для работы с конкретным проектом. В этот момент задаются стандартные пути для файлов, настройки тестов, менеджеров зависимостей и прочей инфраструктуры. В результате выполнения команды мы получаем конфигурационный файл проекта — Rambafile.
- generamba template install запускает процесс установки указанных в Rambafile шаблонов.
- generamba gen HabrahabrModule rviper_controller уже непосредственно создает новый модуль HabrahabrModule, используя шаблон rviper_controller.
Для работы Генерамба использует несколько ресурсов:
- Rambafile — конфигурационный файл, содержащий все, что пользователь указал во время выполнения команды setup, а также ссылки на шаблоны и их каталоги,
- Один или больше шаблонов, которые могут быть указаны при создании нового модуля,
- Пользовательские настройки (к примеру, имя автора).
Первые два пункта смело попадают под Git, а настройки, привязанные к пользователю, лежат в проекто-независимой директории.
### Headers settings company: Rambler&Co ### Xcode project settings project_name: GenerambaSandbox prefix: RDS xcodeproj_path: GenerambaSandbox.xcodeproj ### Code generation settings section # The main project target name project_target: GenerambaSandbox # The file path for new modules project_file_path: GenerambaSandbox/Classes/Modules # The Xcode group path to new modules project_group_path: GenerambaSandbox/Classes/Modules ### Tests generation settings section # The tests target name test_target: GenerambaSandboxTests # The file path for new tests test_file_path: GenerambaSandboxTests/Classes/Modules # The Xcode group path to new tests test_group_path: GenerambaSandboxTests/Classes/Modules ### Dependencies settings section podfile_path: Podfile cartfile_path: Cartfile ### Templates catalogs: - 'https://github.com/rambler-ios/generamba-catalog' - 'https://github.com/igrekde/my-own-catalog' templates: - {name: rviper_controller} - {name: local_template_name, local: 'absolute/file/path'} - {name: remote_template_name, git: 'https://github.com/igrekde/remote_template'}
Отдельного упоминания достойна работа с шаблонами. В отличии от многих других генераторов, мы не зашиваем шаблоны в саму утилиту — взамен этого мы встроили более гибкую систему, подсмотренную у менеджеров зависимостей (читай, Cocoapods). Новые шаблоны могут быть установлены с использованием одного из следующих путей:
- Локальный шаблон (копируется из указанной папки)
- Удаленный шаблон (клонируется из указанного репозитория)
- Шаблон из каталога (в репозиториях с используемыми каталогами ищется подходящий шаблон по названию).
Спустя несколько месяцев использования Генерамбы на наших проектах, оформился самый часто используемый паттерн — для проекта создается свой каталог шаблонов, в рамках которого хранятся все, даже наименее часто используемые шаблоны. Со временем некоторые из таких решений, заточенных под конкретный проект, после определенных доработок попадают в нашу публичную спеку.
Как я уже упоминал, нас смущала сложность разметки стандартных шаблонов Xcode, и в качестве инструмента борьбы с этой проблемой был выбран шаблонный движок liquid — мало того, что с простым, удобным и понятным синтаксисом, так еще и с кучей дополнительных бонусов, которым можно найти применение не только во фронтенде, но и при кодогенерации.
Для сравнения, Xcode-шаблон:
// // ___VARIABLE_viperModuleName______FILENAME___ // ___PROJECTNAME___ // // Created by ___FULLUSERNAME___ on ___DATE___ // Copyright ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. // #import "___VARIABLE_viperModuleName:identifier___Interactor.h" #import "___VARIABLE_viperModuleName:identifier___InteractorOutput.h" @implementation ___VARIABLE_viperModuleName:identifier___Interactor #pragma mark - ___VARIABLE_viperModuleName:identifier___InteractorInput @end
Liquid шаблон для такого же файла:
// // {{ module_info.name }}{{ module_info.file_name }} // {{ module_info.project_name }} // // Created by {{ developer.name }} on {{ date }}. // Copyright {{ year }} {{ developer.company }}. All rights reserved. // #import "{{module_info.name}}Interactor.h" #import "{{module_info.name}}InteractorOutput.h" @implementation {{module_info.name}}Interactor #pragma mark - {{module_info.name}}InteractorInput @end
Мы продолжаем активно развивать Генерамбу. Помимо относительно бытовых задач мы присматриваемся и к другим направлениям:
- добавление GUI, в том числе в виде плагинов для IDE,
- поддержка Android-проектов,
- фантастика, требующая работы с AST-деревом — к примеру, автогенерация тест-кейсов по описанным протоколам или моков для swift-классов.
В качестве заключения хочется добавить, что Генерамба послужила отличным наглядным примером пользы автоматизации вполне тривиальных задач — полученный нами опыт мы перенесем и на другие области деятельности отдела, которым не помешало бы избавиться от ручного труда.
Решили начать использовать Генерамбу? Задавайте свои вопросы и пишите о найденных проблемах в issues — наше сообщество хоть и небольшое, но достаточно активное.
Полезные ссылки:
- liftoff, для генерации Xcode-проектов,
- Книга VIPER,
- Документация Генерамбы,
- Выступление на Rambler.iOS V про Генерамбу: слайды, видео
ссылка на оригинал статьи https://habrahabr.ru/post/276275/
Добавить комментарий