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. Хватит делать фичи,
    делайте инструменты
    Александр Свиридов

    View Slide

  2. План
    1. Задачи
    2. Backend реализация
    3. Android реализация
    4. Developer experience
    5. Проблемы
    6. К чему пришли
    %2

    View Slide

  3. Задачи
    • Быстро запускать акции, промоутить товары и продавцов

    eCommerce очень динамичный рынок
    • BE команда разделена на business units – Вертикали

    Microservices architecture
    • У каждого компонента должен быть свой владелец

    контроль от и до
    • Нет выделенной команды MobileAPI

    узкое место
    • AB тесты и аналитика

    быстрый фидбэк
    %3

    View Slide

  4. Composer

    View Slide

  5. %5
    Это Гребенка

    View Slide

  6. %6
    StoreFront
    Marketing
    StoreFront
    Marketing shelf
    cms
    marketing
    cms
    Widget Vertical Service

    View Slide

  7. Apps
    Desktop
    ComposerAPI
    URL
    BE

    View Slide

  8. Apps
    Desktop
    Layout API
    ComposerAPI
    URL
    layout
    BE

    View Slide

  9. Apps
    Desktop
    Layout API
    ComposerAPI
    cms
    shelf
    marketing
    BE

    View Slide

  10. Apps
    Desktop
    Layout API
    ComposerAPI
    BE
    cms
    shelf
    marketing

    View Slide

  11. Apps
    Desktop
    Layout API
    Composer
    response
    BE
    ComposerAPI
    cms
    shelf
    marketing

    View Slide

  12. Что получилось?
    1. Один запрос на страницу
    2. Логика виджета полностью у вертикали
    3. Контракт по UI
    4. Можно управлять набором и порядком виджетовна странице
    %12

    View Slide

  13. Android реализация

    View Slide

  14. Задачи перед мобильной командой
    1. Поддерживать различные виджеты
    2. Виджет не привязан к странице
    3. Сделать инструмент удобный для использования
    4. Общий подход к аналитике
    %14

    View Slide

  15. Реализация на Android
    %15
    Home PDP Catalog

    View Slide

  16. Разбиение на ViewHolders
    %16
    Home PDP Catalog

    View Slide

  17. Общий контейнер
    %17
    PDP Home

    View Slide

  18. Аналитика
    %18

    View Slide

  19. Composer framework
    67
    виджетов
    %19

    View Slide

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

    View Slide

  21. Development experience

    View Slide

  22. Процесс разработки
    1. Создание Config
    2. Регистрация виджета в DI
    3. Маппинг модели
    4. Верстка и бизнес логика
    %22

    View Slide

  23. Создание Config
    %23
    у нас есть Live Templates
    interface Config {
    val parser: (params: String?, state: String?) -> StateDTO?
    }
    interface ViewMapper {
    val mapper: (StateDTO, WidgetInfo) -> List
    val layout: Int
    val holderProducer: (View, ComposerReferences) -> WidgetViewHolder?
    }

    View Slide

  24. Регистрируем виджет
    %24
    @Module
    abstract class ComposerCommonWidgetsModule {
    @Module
    companion object {
    @ElementsIntoSet
    @JvmStatic
    @Reusable
    @Provides
    fun provideWidget(
    bannerConfig: BannerConfig,
    bannerViewMapper: BannerViewMapper
    ): Set =
    hashSetOf(
    Widget(
    vertical = "cms",
    component = "banner",
    config = bannerConfig,
    viewMappers = arrayOf(bannerViewMapper)
    ))
    }
    }

    View Slide

  25. Маппинг модели
    %25
    class BannerMapper @Inject constructor() : WidgetMapper {
    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
    )
    }

    View Slide

  26. Верстка и бизнес логика
    %26
    class BannerViewHolder(
    private val router: ScreenRouter,
    private val analytics: WidgetAnalytics
    ) : WidgetViewHolder(), 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)
    }
    }
    }

    View Slide

  27. Итог
    1. Верхнеуровневый фреймворк
    2. Простой контракт
    3. Разработка до BE (Charles / Ghost Widget)
    4. Onboarding
    %27

    View Slide

  28. Проблемы

    View Slide

  29. Связанные виджеты
    %29

    View Slide

  30. Дублирование данных
    %30

    View Slide

  31. Большой респонс
    %31

    View Slide

  32. Кастомные виджеты
    %32

    View Slide

  33. К чему пришли

    View Slide

  34. Страницы управляются с BE
    %34

    View Slide

  35. Переиспользование элементов
    %35

    View Slide

  36. Фичи без релиза
    %36

    View Slide

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

    View Slide

  38. Спасибо за внимание!
    [email protected]
    Александ Свиридов

    View Slide