Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Архитектурные излишества в iOS приложениях Superjob

Архитектурные излишества в iOS приложениях Superjob

Vladimir Burdukov

July 13, 2015
Tweet

More Decks by Vladimir Burdukov

Other Decks in Programming

Transcript

  1. О Superjob.ru • ~ 15 000 000 резюме • ~

    1 000 000 работодателей • ~ 700 000 посетителей сайта ежедневно • ~ 50 000 пользователей приложения Поиск работы ежедневно 2
  2. Мобильная команда • 3 iOS разработчика • 2 Android разработчика

    • 1 Windows Phone разработчик • 1 дизайнер • 1 API-писатель • 0 менеджеров 7
  3. Об инструментах Sketch. Почему не Photoshop или Illustrator? • дизайн

    интерфейсов в векторном формате • текстовые и CSS стили • экспорт элементов в @1x,@2x,@3x PNG или PDF • это модно 9
  4. Об инструментах Paw • тестирование запросов API • хранение наборов

    констант, быстрое переключение между ними • например, URL API, token приложения. • динамические переменные между разными запросами • например, в запросе авторизации возвращается токен, который нужно передавать в каждый последующий запрос к API. 10
  5. Об инструментах Fastlane • автоматизация всех этапов бета-релиза приложения: •

    выставить номер сборки, например 2015.07.13.15.45 • pod install • запустить unit-тесты • собрать xcarchive 11
  6. Об инструментах Fastlane • автоматизация всех этапов бета-релиза приложения: •

    собрать ipa для TestFlight • загрузить в TestFlight • собрать ipa для установки на тестовые устройства (например, для iOS 7) • загрузить в Slack 12
  7. Об архитектуре Многослойность • за основу взяты идеи Clean Architecture

    • каждый слой знает про следующий снизу слой • компоненты приложения делятся на 5 слоев: • View • View Model • Facade • Adapter • Data Source 14
  8. Об архитектуре Data Source • все классы, которые занимаются загрузкой

    данных из внешних источников – API, PlistUtility, JSONUtility • обрабатывают запросы вида "дай мне содержимое этого файла" или "отправь GET запрос по этому URL с такими параметрами" • пока не покрыты тестами ! 16
  9. Об архитектуре Data Source • возвращают данные так, как получили

    из источника • например класс API возвращает NSHTTPURLResponse и разобранный JSON объект 17
  10. Об архитектуре Адаптеры • сейчас это классы APIAdapter и FileAdapter

    • предоставляют интерфейсы для доступа к Data Source, например "Получи список избранных вакансий" • единый формат возвращаемых данных для списков, отдельных элементов и запросов с логическим результатом (успешно или нет) 18
  11. Об архитектуре Адаптеры • например, для запроса какого-нибудь списка возвращается

    NSArray, состоящий из NSDictionary, количество всех элементов списка и флаг, определяющий существует ли следующая страница 19
  12. Об архитектуре Фасады • входная точка получения данных внутри приложения

    • фасады преобразуют NSDictionary, полученные из адаптеров, в модели с помощью Mantle • фасады сами разруливают из какого адаптера брать данные 20
  13. Об архитектуре Фасады • например, если пользователь авторизован, то избранные

    вакансии надо получать из API (APIAdapter), если не авторизован – то из файла на диске (FileAdapter) 21
  14. Об архитектуре View Model • view model преобразует данные из

    моделей в данные для отображения • например, форматирует дату в строку, число 120000 в строку 120 000 ₽ 22
  15. Об архитектуре View Model • знает все о данных, которые

    должны отобразиться в UI • например, количество секций в таблице, количество элементов в секции, сами эти элементы • получает данные из разных фасадов и компонует их так, как нужно для отображения в UI 23
  16. Об архитектуре View • пользовательский интерфейс (чаще всего UITableViewController) •

    по мотивам шаблона MVVM View Controller занимается только представлением данных из View Model на экран устройства и обработкой действий пользователя 24
  17. Об архитектуре Связи • view model – это свойство объекта

    View Controller • обновление view model происходит по вызову метода из View • view – это делегат View Model • обновление UI происходит по вызову методов делегата View Model 25
  18. Об архитектуре Связи • между этими уровнями также устанавливаются отношения

    с помощью свойств • например, у SearchResultsViewModel есть свойство vacancyFacade 26
  19. Об архитектуре Связи • в публичных интерфейсах фасадов, адаптеров и

    Data Source объявлены instance методы, которые возвращают RACSignal (ReactiveCocoa) 27
  20. Тесты • тестируются объекты отдельных слоев • на данный момент

    мы тестируем view model, фасады и адаптеры • data source реализованы предельно просто, тесты к ним будут написаны позже 28
  21. Тесты • тесты view тоже будут писаться позже, есть две

    идеи как и что можно в этом слое тестировать: • тестировать их внешний вид с помощью facebook/ios-snapshot-test-case • с помощью новых UI тестов в Xcode 7 и мока View Model тестировать что и как отображается в контроллере 29
  22. Тесты Что и как тестировать? • тестируется отдельный объект как

    черный ящик: • создаются моки всех его зависимостей • вызываются его методы • проверяется к каким мокам он обратился и какой выдал результат 32
  23. Тесты Что и как тестировать • изначально общение между view

    model, фасадами, адаптерами и data source происходило с помощью completion блоков • но для эмуляции приходилось писать в 4 раза больше тестового кода • поэтому блоки были заменены на RACSignal 33
  24. [viewModel loadData]; MKTArgumentCaptor *argument = [MKTArgumentCaptor new]; [verify(facade) favoriteVacanciesWithCompletion: [argument

    capture]]; SJVacancyFacadeListCompletionBlock completion = [argument value]; SJFacadeListResponse *response = [SJFacadeListResponse listResponseWithObjects:models totalCount:models.count hasMoreItems:NO]; completion(response); 35
  25. - (void)loadData { [[self.facade favoriteVacancies] subscribeNext: ^(RACTuple *response) { ///

    process models } error:^(NSError *error) { /// process error }]; } 36
  26. Dependency Injection • каждая связь между верхним слоем и нижним

    – это отдельное свойство • например, у VacancyFacade есть свойства apiAdapter и fileAdapter • в публичных интерфейсах объектов объявлены только instance методы • никаких синглтонов (на самом деле это не так) 38
  27. Dependency Injection Объявление зависимостей @interface SJVacancyFacade () @property (nonatomic, strong)

    SJAPIAdapter *apiAdapter; @property (nonatomic, strong) SJFileAdapter *fileAdapter; @end @implementation SJVacancyFacade objection_requires(@"apiAdapter", @"fileAdapter") @end 40
  28. Dependency Injection Singleton • т.к. один фасад может использоваться в

    разных View Model, то нет необходимости создавать много объектов этого фасада • однако для того, чтобы тестировать каждый объект в отдельности, нужно иметь возможность подменять его зависимости на моки, поэтому традиционные реализации Singleton нам не подошли 41