- PVSM.RU - https://www.pvsm.ru -

TL;DR
Мы написали классный кодогенератор [1] для iOS-разработки, обладающий следующими достоинствами:
Больше подробностей — под катом.
Серьезные решения, касающиеся архитектуры проекта, несут за собой необходимость принятия определенного компромисса. Придерживаемся n-tier структуры [2] — получаем некоторое количество пустых пробросов информации между слоями. Распараллеливаем задачи на несколько потоков — тратим огромное количество времени на решение неочевидных багов. В похожей ситуации, требующей принятия компромисса, столкнулись и мы в Rambler&Co, принимая решение использовать VIPER в качестве стандарта архитектуры всех наших мобильных приложений. Получив отличную модульность и четкое разделение ответственностей компонентов, мы приобрели головную боль в виде сложности и монотонности процесса создания новых модулей.
Среднестатистический iOS разработчик в начале работ над новым экраном просто создает один класс. Тот, кто принял волевое решение перейти на VIPER, в этот момент начинает страдать. В большинстве случаев ему требуется создать пять классов, шесть протоколов и написать пять тест-кейсов. Допустим, что для создания новых модулей наш бедолага наймет профессиональную секретаршу с огромной скоростью печати — но даже в таком случае он вряд ли сможет выйти за рамки 30 секунд на создание и заполнение одного файла. Применим те небольшие знания математики, которыми наделила природа мобильных разработчиков, перемножим эти числа и получим ответ в районе 10 минут. Тот самый среднестатистический разработчик за это же время успеет накидать пару сотен строк UITableViewDataSource, отправить несколько сетевых запросов и покрасить все view’шки в красивый лазурный цвет. Как-то несправедливо по отношению к труду нашего VIPER-гуру.

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

Одним из способов решения указанных проблем, которым долгое время пользовались и мы — это создание своих собственных шаблонов для Xcode. Не считая того, что такой подход просто не спортивен, для себя мы выделили еще ряд относительно серьезных недостатков.
Но, конечно, все понимают, что больше всего расстраивал еще один, фатальный, недостаток — решение написано не нами. Контроля над ним слишком мало, а расширяемость для более специфичных задач стремится к нулю. Поэтому мы и решили написать свой кодогенератор — Генерамбу. Сразу же уточню очень важный тезис — хоть мы и приступили к проекту для того, чтобы упростить процесс создания VIPER модулей, но в результате получили куда более гибкую утилиту, которая может помочь в автоматизации широкого спектра задач по генерации и стандартизации кода.
С момента установки Генерамбы (gem install generamba) до создания своего первого модуля нужно пройти три шага:
Для работы Генерамба использует несколько ресурсов:
Первые два пункта смело попадают под 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). Новые шаблоны могут быть установлены с использованием одного из следующих путей:
Спустя несколько месяцев использования Генерамбы на наших проектах, оформился самый часто используемый паттерн — для проекта создается свой каталог шаблонов, в рамках которого хранятся все, даже наименее часто используемые шаблоны. Со временем некоторые из таких решений, заточенных под конкретный проект, после определенных доработок попадают в нашу публичную спеку [3].
Как я уже упоминал, нас смущала сложность разметки стандартных шаблонов Xcode, и в качестве инструмента борьбы с этой проблемой был выбран шаблонный движок liquid [4] — мало того, что с простым, удобным и понятным синтаксисом, так еще и с кучей дополнительных бонусов, которым можно найти применение не только во фронтенде, но и при кодогенерации.
Для сравнения, 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
Мы продолжаем активно развивать Генерамбу. Помимо относительно бытовых задач мы присматриваемся и к другим направлениям:
В качестве заключения хочется добавить, что Генерамба послужила отличным наглядным примером пользы автоматизации вполне тривиальных задач — полученный нами опыт мы перенесем и на другие области деятельности отдела, которым не помешало бы избавиться от ручного труда.
Решили начать использовать Генерамбу? Задавайте свои вопросы и пишите о найденных проблемах в issues [5] — наше сообщество хоть и небольшое, но достаточно активное.
Полезные ссылки:
Автор: Rambler&Co
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ruby/112007
Ссылки в тексте:
[1] классный кодогенератор: https://github.com/rambler-ios/Generamba
[2] n-tier структуры: https://en.wikipedia.org/wiki/Multitier_architecture
[3] в нашу публичную спеку: https://github.com/rambler-ios/generamba-catalog
[4] шаблонный движок liquid: https://github.com/Shopify/liquid
[5] issues: https://github.com/rambler-ios/Generamba/issues
[6] liftoff, для генерации Xcode-проектов: https://github.com/thoughtbot/liftoff
[7] Книга VIPER: https://github.com/rambler-ios/The-Book-of-VIPER
[8] Документация Генерамбы: https://github.com/rambler-ios/Generamba/wiki
[9] слайды: http://www.slideshare.net/Rambler-iOS/viper-56423582
[10] видео: http://www.youtube.com/watch?v=NXNiN9FaUnY
[11] Источник: https://habrahabr.ru/post/276275/
Нажмите здесь для печати.