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

Хватит делать фичи, делайте инструменты

Хватит делать фичи, делайте инструменты

Александр Свиридов, Ozon at #MOSDROID 17 Chlorine

Доклад о том как как мы в Ozon развиваем приложение через Backend Driven UI, запускаем фичи без релиза и отдыхаем в выходные.

Поговорим о наших гибких инструментах формирования страниц из блоков, которыми можно управлять из админки. Этот подход позволяет упростить жизнь разработчикам, стандартизировать создание новых фичей и дает возможность продукт оунерам не ждать релиза мобильного приложения.

MOSDROID

May 30, 2019
Tweet

More Decks by MOSDROID

Other Decks in Programming

Transcript

  1. План 1. Задачи 2. Backend реализация 3. Android реализация 4.

    Developer experience 5. Проблемы 6. К чему пришли %2
  2. Задачи • Быстро запускать акции, промоутить товары и продавцов
 eCommerce

    очень динамичный рынок • BE команда разделена на business units – Вертикали
 Microservices architecture • У каждого компонента должен быть свой владелец
 контроль от и до • Нет выделенной команды MobileAPI
 узкое место • AB тесты и аналитика
 быстрый фидбэк %3
  3. Что получилось? 1. Один запрос на страницу 2. Логика виджета

    полностью у вертикали 3. Контракт по UI 4. Можно управлять набором и порядком виджетовна странице %12
  4. Задачи перед мобильной командой 1. Поддерживать различные виджеты 2. Виджет

    не привязан к странице 3. Сделать инструмент удобный для использования 4. Общий подход к аналитике %14
  5. Реализация на Android 1. Composer framework 2. RecyclerView c GridLayoutManager

    3. Большие виджеты могут разбиваться на несколько ViewHolders 4. Общий контейнер виджетов (через DI) %20
  6. Процесс разработки 1. Создание Config 2. Регистрация виджета в DI

    3. Маппинг модели 4. Верстка и бизнес логика %22
  7. Создание Config %23 у нас есть Live Templates interface Config<StateDTO>

    { val parser: (params: String?, state: String?) -> StateDTO? } interface ViewMapper<StateDTO : Any?, VO : ViewObject> { val mapper: (StateDTO, WidgetInfo) -> List<VO> val layout: Int val holderProducer: (View, ComposerReferences) -> WidgetViewHolder<VO>? }
  8. Регистрируем виджет %24 @Module abstract class ComposerCommonWidgetsModule { @Module companion

    object { @ElementsIntoSet @JvmStatic @Reusable @Provides fun provideWidget( bannerConfig: BannerConfig, bannerViewMapper: BannerViewMapper ): Set<Widget> = hashSetOf( Widget( vertical = "cms", component = "banner", config = bannerConfig, viewMappers = arrayOf(bannerViewMapper) )) } }
  9. Маппинг модели %25 class BannerMapper @Inject constructor() : WidgetMapper<BannerDTO, BannerVO>

    { override fun invoke(dto: BannerDTO, widgetInfo: WidgetInfo) = BannerVO( id = "${dto.item.image}.${dto.width}.${dto.height}".hashCode().toLong(), image = ImageHelper.getResizedImagePath(dto.item.image), ratio = dto.height.toFloat() / dto.width.toFloat(), url = dto.item.deeplink ) }
  10. Верстка и бизнес логика %26 class BannerViewHolder( private val router:

    ScreenRouter, private val analytics: WidgetAnalytics ) : WidgetViewHolder<BannerVO>(), LayoutContainer { override fun bind(item: BannerVO, info: WidgetInfo) { (itemView as AspectRatioImageView).apply { ratio = item.ratio this.loadAsBitmap(item.image) } itemView.setOnClickListener { _ -> analytics.bannerClick(info.component, item.url.orEmpty()) router.openDeeplink(deeplink = item.url!!, context = itemView.context) } } }
  11. Советы по созданию фреймворков 1. Ограничьте область применения фреймворка 2.

    Схожая реализация с iOS/mobile Web 3. Удобство пользования фреймворком крайне важно 4. Выберите красивое название ☺ %37