64
Создание модульных приложений на примере Рамблер.Кассы

Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Embed Size (px)

Citation preview

Page 1: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Создание модульных приложений на примере

“Рамблер.Кассы”

Page 2: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

О чем?

• Введение в историю “Рамблер.Касса”

• Что используем

• Пример

Page 3: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

О чем?

• Введение в историю “Рамблер.Касса”

• Что используем

• Пример

Page 4: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

О чем?

• Введение в историю “Рамблер.Касса”

• Что используем

• Пример

Page 5: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Модуль — функционально законченный фрагмент программы, оформленный в виде отдельного файла с исходным кодом.

Глоссарий

Page 6: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Модульность — это свойство системы, связанное с возможностью ее декомпозиции на ряд внутренне связанных между собой модулей

Глоссарий

Page 7: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

• Приложение, отображающее информацию по событию: - кино - спектакли - спорт

• Возможность купить билеты на эти события без наценки

• iPhone и iPad версии

Что же такое “Рамблер.Касса”?

Page 8: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

• Приложение, отображающее информацию по событию: - кино - спектакли - спорт

• Возможность купить билеты на эти события без наценки

• iPhone и iPad версии

Что же такое “Рамблер.Касса”?

Page 9: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

• Приложение, отображающее информацию по событию: - кино - спектакли - спорт

• Возможность купить билеты на эти события без наценки

• iPhone и iPad версии

Что же такое “Рамблер.Касса”?

Page 10: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

• Приложение, отображающее информацию по событию: - кино - спектакли - спорт

• Возможность купить билеты на эти события без наценки

• iPhone и iPad версии

Что же такое “Рамблер.Касса”?

Page 11: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

Что же такое “Рамблер.Касса”?

Page 12: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

Что же такое “Рамблер.Касса”?

Page 13: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

• Проект развивается

• Появляется первая “брендированная версия”

Page 14: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

Что же такое “брендированная” версия?

• Отдельное приложение, существующее обособленно от основной версии

• Имеет свои особенности: - своя цветовая схема, логотипы и т.д. - отличный от основной кассы функционал

Page 15: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

Что же такое “брендированная” версия?

Page 16: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

Что же такое “брендированная” версия?

Page 17: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Немного истории

Page 18: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

• Общий функционал

• Отличный функционал

• Количество версий только растет

Проблема

Page 19: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Проблема

Page 20: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Проблема

Page 21: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Расписание

Поддержка Билеты

Карта

Спорт

Кино Кино

Кино

Проблема

Расписание

Билеты

Карта

Расписание

Поддержка

Билеты

Page 22: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Как это было?

• Один проект для всех версий

• Множество таргетов

• Ветвления через “if” по define макросам

Page 23: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #ifdef BOLSHOI switch (section) { case 2: return 2; case 3: return 2; default: return 0; } #else switch (section) { case 0: return 2; case 1: return 1;

default: return 0; } #endif }

Как это было?

Page 24: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

- (instancetype)init { self = [super init]; NSString *bundleIdentifier = [[NSBundle mainBundle] infoDictionary][@"CFBundleIdentifier"]; if ([bundleIdentifier rangeOfString:@"cinemapark"].location != NSNotFound) { // CINEMA PARK _tintColor = [UIColor colorWithRed:31.f / 255.f green:110.f / 255.f blue:180.f / 255.f alpha:1.f]; _navigationBarTintColor = [UIColor colorWithRed:4.f/255.f green:110.f/255.f blue:180.f/255.f alpha:1.f]; _navigationBarTitleColor = [UIColor whiteColor]; _shouldShowTheaters = NO; _onlyOneCinema = NO; #if !defined(AF_APP_EXTENSIONS) [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; #endif if ([bundleIdentifier hasSuffix:@".dev"]) { _widgetKey = @"foo"; } else { _widgetKey = @"foo"; } } else if ([bundleIdentifier rangeOfString:@"Bolshoi"].location != NSNotFound) { // Bolshoi Rostov _tintColor = [UIColor kassaBolshoiMainColor]; _navigationBarTintColor = [UIColor kassaBolshoiMainColor]; _navigationBarTitleColor = [UIColor kassaBolshoiActiveTabsColor]; _selectedBarItemColor = [UIColor kassaBolshoiActiveTabsColor]; _unselectedBarItemColor = [UIColor kassaBolshoiSecondaryColor]; _barTextColor = [UIColor kassaBolshoiActiveTabsColor]; _shouldShowTheaters = NO; _onlyOneCinema = YES; if ([bundleIdentifier hasSuffix:@".dev"]) { _widgetKey = @"foo"; } else { _widgetKey = @"foo"; } }else { // KASSA APP _tintColor = [UIColor colorWithRed:255.f / 255.f green:133.f / 255.f blue:47.f / 255.f alpha:1.f]; _navigationBarTintColor = nil; _navigationBarTitleColor = nil; _selectedBarItemColor = _tintColor; _unselectedBarItemColor = nil; _barTextColor = nil; _shouldShowTheaters = YES; _onlyOneCinema = NO; if ([bundleIdentifier hasSuffix:@".dev"]) { _widgetKey = @"foo"; } else { _widgetKey = @"foo"; } } return self; }

if ([bundleIdentifier rangeOfString:@"cinemapark"].location != NSNotFound) { // CINEMA PARK _tintColor = [UIColor colorWithRed:31.f / 255.f green:110.f / 255.f blue:180.f / 255.f alpha:1.f];

Как это было?

Page 25: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Как это было?

Page 26: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

• Модуль - экран приложения, выполняющий свою функцию

• Саб-модуль - отдельная функциональность конкретного модуля, отвечающая за единственную обязанность

Page 27: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Page 28: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

• Разбить приложение на модули

• Разбить каждые модули на саб-модули

• Подключать нужные модули, а с ними и нужные саб-модули для конкретных таргетов

Решение

Page 29: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Модуль “кинотеатры”

• Получает через API список кинотеатров

• Отображает этот список

• Осуществляет навигацию на другие модули

Page 30: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Модуль “кинотеатры”

view presenter

router

interactor

entity

entity

entity

Page 31: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Модуль “кинотеатры”

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Page 32: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 33: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 34: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 35: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 36: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 37: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 38: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Nimbus

Решение

Page 39: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Nimbus

Cell Object

Решение

Page 40: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Nimbus

Cell ObjectСконфигурированная

ячейка

Решение

Page 41: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 42: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 43: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

TYPHOON

Решение

Page 44: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение@interface RKCinemasDefaultConfiguratorAssembly : TyphoonAssembly

@property (nonatomic, strong) RKSharedAssembly *sharedAssembly;

- (id<RKCinemasViewProtocol, RKBaseListViewOutConfiguratorProtocol, RKCinemasDataProviderDelegate>)cinemasViewController; - (id<RKCinemasPresenterViewOutputProtocol, RKCinemasPresenterInteractorOutputProtocol>)cinemaPresenter; - (id<RKCinemasInteractorProtocol>)cinemasInteractor; - (id<RKCinemasRouterProtocol>)cinemasRouter; - (id<RKCinemasServiceProtocol>)cinemasService; - (id<RKBaseListViewConfiguratorProtocol>)cinemaConfigurator; - (id<RKCinemasDataSourceProviderProtocol>)cinemasDataSourceProvider; - (id<RKCinemasDataSourceConverterProtocol>)cinemasDataConverter;

@end

Page 45: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Активация фабрики

Page 46: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Page 47: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Page 48: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Модуль “кинотеатры”

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Page 49: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

Решение

Модуль “кинотеатры”

Page 50: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

RKCinemasDataConverter

Решение

Модуль “кинотеатры”

Page 51: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

view presenter

router

interactor entityservice

data source provider

data source converter

ui configurator

RKCinemasDataConverterRKCinemasGiantDataConverter

Решение

Модуль “кинотеатры”

Page 52: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение@implementation RKCinemasDataConverter

- (NSArray *)convertArrayOfListCinemasToPlaceCellObjects:(NSArray *)list { NSMutableArray *array = [[NSMutableArray alloc] init]; for (RKList *listObject in list) { [array addObject:listObject.title]; NSArray *objects = [self convertListOfCinemasToCellObjects:listObject.objects]; [array addObjectsFromArray:objects]; } return [array copy]; }

- (NSArray *)convertListOfCinemasToCellObjects:(NSArray *)list { NSMutableArray *array = [[NSMutableArray alloc] init]; for (RKPlace *place in list) { [array addObject:[RKListPlaceCellObject objectWithPlace:place]]; } return [array copy]; }

@end

Page 53: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение@implementation RKCinemasGiantDataConverter

- (NSArray *)convertListOfCinemasToCellObjects:(NSArray *)list { NSMutableArray *array = [[NSMutableArray alloc] init]; for (RKPlace *place in list) { id<RKCinemaDataProtocol>cinemaInfo = [self.dataProvider cinemaInfoById:place.identifier]; NSString *backgroundImageName = [cinemaInfo backgroundImageName]; NSString *logoImageName = [cinemaInfo logoImageName]; [array addObject:[RKPhotoCinemaCellObject objectWithPlace:place backgroundImageName:backgroundImageName logoImageName:logoImageName]]; } return [array copy]; }

- (NSArray *)convertArrayOfListCinemasToPlaceCellObjects:(NSArray *)list { NSMutableArray *array = [[NSMutableArray alloc] init];

for (RKList *listObject in list) { [array addObject:listObject.title]; NSArray *objects = [self convertListOfCinemasToCellObjects:listObject.objects]; [array addObjectsFromArray:objects]; } return [array copy]; }

@end

Page 54: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

#import "RKCinemasDefaultConfiguratorAssembly.h"

@protocol RKCinemasDataProviderProtocol;

@interface RKCinemasGiantConfiguratorAssembly : RKCinemasDefaultConfiguratorAssembly

- (id<RKCinemasDataSourceConverterProtocol>)cinemasDataConverter; - (id<RKCinemasDataProviderProtocol>)giantCinemasDataProvider;

@end

Page 55: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

- (id<RKCinemasDataSourceConverterProtocol>)cinemasDataConverter { return [TyphoonDefinition withClass:[RKCinemasGiantDataConverter class] configuration:^(TyphoonDefinition *definition) { [definition injectProperty:@selector(dataProvider) with:[self giantCinemasDataProvider]]; }]; }

- (id<RKCinemasDataSourceConverterProtocol>)cinemasDataConverter { return [TyphoonDefinition withClass:[RKCinemasDataConverter class]]; }

Definition для основной версии

Definition для “брединрованной” версии

Page 56: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решениеrambler-kassa.plist

giant.plist

Page 57: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Решение

Page 58: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Заключение

• Код чище

• Уникальный функционал затрагивает только нужные таргеты

• Общий код для всех таргетов

• Тестирование саб-модулей

Page 59: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Заключение

• Код чище

• Уникальный функционал затрагивает только нужные таргеты

• Общий код для всех таргетов

• Тестирование саб-модулей

Page 60: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Заключение

• Код чище

• Уникальный функционал затрагивает только нужные таргеты

• Общий код для всех таргетов

• Тестирование саб-модулей

Page 61: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Заключение

• Код чище

• Уникальный функционал затрагивает только нужные таргеты

• Общий код для всех таргетов

• Тестирование саб-модулей

Page 62: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Заключение

• VIPER

• NIMBUS

• TYPHOON

Page 63: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Заключение• COCOAPOD (?)

Page 64: Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы

Ссылки

http://typhoonframework.org/

Статья с общими принципами

https://www.objc.io/issues/13-architecture/viper/

Официальный сайт проекта “Тyphoon”

http://habrahabr.ru/company/rambler-co/blog/264683/

https://www.youtube.com/watch?v=LO59z3fjc9k

TYPHOON

Цикл статей от Егора Толстова

Выступление на rambler.ios #3

VIPER

https://medium.com/brigade-engineering/brigades-experience-using-an-mvc-alternative-36ef1601a41f

Вводная статья

NIMBUShttps://github.com/jverkoey/nimbus Исходники и ссылка на wiki проекта

http://www.slideshare.net/Rambler-iOS/nimbus-models Презентация с rambler.ios #1 от Стаса Цыганова