В данной статье я хочу поделиться своим опытом разработки интерфейсов с уровнем кастомизации вплоть до 100% (реальные 100%). При этом сохраняется обратная совместимость и возможность апдейтов. Магия? - Нет, это CDD!

Все началось еще в 2018 году в одной крупной международной компании. Меня пригласили в главный офис для объяснения топ руководству как мы будем решать проблему кастомизации нашего продукта, а конкретно UI части. Клиентам необходимо было немного изменить его под себя и кое-что добавить. Нужно было сохранить обратную совместимость, чтобы клиенты могли получать обновления продукта. Тогда я знал только про возможности добавления “дыр” в коде (slots), в которые можно добавить любой функционал. Ну еще и про API, уже для изменения функциональности. Понятно что ни о какой возможности кастомизации на все 100% речи не шло, ведь тогда нужно изменять исходный код, а это само собой потеря обратной совместимости.

Конечно CDD нужен далеко не всем. Эта техника будет крайне полезна при разработке продукта, клиентам которого необходима глубокая кастомизация. Я имею ввиду, не просто поменять логотип и название, а поменять абсолютно все что душе угодно. И при этом не потерять возможность будущих апдейтов продукта.

Как же добиться практически 100%-й кастомизации и без единого разрыва без потери обратной совместимости?

В CDD используется "декларативная кастомизация", т.е. все представление с логикой  должны быть вывернуты наружу для возможности полной кастомизации. Если необходимо кастомизировать определенные части довольно сложной компоненты, тогда мы просто отображаем ее более простые внутренние компоненты. Эти компоненты могут быть упакованы в так называемый “черный ящик” с богатым API и “дырами” (slots), либо также отображены еще более простыми компонентами. Представление с логикой любых компонент (кроме примитивных) всегда можно вывернуть наружу, для получения 100% доступа.

И здесь вы можете возразить: “Но как же, ведь когда мы используем внутреннее содержимое, тогда мы теряем возможность апдейтов!”. Нет, это не совсем так, и вот почему:

  1. Компонента любой сложности (кроме примитивной) - это всего лишь набор более простых компонент, который всегда есть в свободном доступе и при ее апдейте, мы наглядно видим что и где в этом наборе изменилось и можем очень просто и быстро проапдейтить ее вручную (если это нужно);

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

Хорошо. А как же этого добиться? Какие шаги?

Сначала нужно разработать самые примитивные компоненты. Они могут, а некоторые из них даже должны иметь по 2 варианта:

  1. Стандартный компонент, “черный ящик” с богатым API и “дырами” (slots), удобен в использовании, но имеет ограниченные возможности кастомизации ;

  2. Компонент-обертка, расширяет возможности контента, который вы сами помещаете внутрь. Менее удобен в использовании, но имеет гораздо большие возможности кастомизации, вплоть до 100%. Обязательно для стандартных HTML элементов: <button>, <a>, <form>, <input>, <textarea>, <select>, …

Затем, при разработке более сложных компонент, нужно использовать набор из более простых. Как и примитивные компоненты, более сложные компоненты могут иметь 2 версии. Но компонент-обертку можно не создавать, если получится упаковать в стандартный компонент только декларативный шаблон из более простых компонент, без кода для управления им. И затем можно просто использовать внутреннее содержимое, когда нужна кастомизация.

В теории все хорошо. А как дела обстоят на практике?

Я создал технологию https://uiwebkit.com, которая уже делает это на практике. Еще, я сейчас готовлю к публикации проект поменьше и он уже полностью Open Source. Вот там уже наглядно видны все плюсы CDD. Проект будет крайне полезен тем, кто часто работает со сложными, кастомными HTML формами с динамическими полями и валидациями. Хотелось бы рассказать о нем подробнее, но это тема уже другой статьи.

Хотелось бы еще вспомнить нашумевший проект кастомизируемых мобильных телефонов Project Ara. На его примере можно увидеть что в принципе кастомизация нужна не всем и не всегда. Да и переплачивать за возможность кастомизации мало кто хочет. Но те немногие, кому действительно нужна кастомизация, готовы экспериментировать и пробовать разные подходы, чтобы получить именно тот результат, который соответствует именно их ожиданиям.

Буду рад вашим комментариям и мнению на этот счет, либо можете смело писать в личку. Спасибо!

Комментарии (11)


  1. nin-jin
    07.10.2022 23:08
    -5

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

    Что ж вы $mol-то не попробовали, где любой компонент (и даже целые приложения) кастомизируем без разделения на "стандартный" и "обёртку"?


    1. via-site Автор
      08.10.2022 09:51
      +1

      Спасибо, нужно посмотреть. Интересно, какой принцип там используется. Там возможна глубокая кастомизация без изменения исходного кода? По моему опыту слоты и АПИ дают только некое подобие кастомизации


      1. nin-jin
        08.10.2022 13:57

        Там все вложенные компоненты и прочие биндинги выносятся в свойства класса и их можно переопределять как при наследовании так и при инстанцировании. Тут об этом рассказывается.


        1. via-site Автор
          08.10.2022 20:59

          Совсем забыл еще и за такой подход. Помню в 2015 году сталкивался с Sencha Ext JS. Популярности из-за своей сложности он не снискал. Там ребята вместо HTML использовали классы и ООП во всей его красе. Мне кажется, мы с вами используем 2 крайности. Не знаю, уместна ли аналогия, но мне кажется это как если бы я на бекенде старался перетащить больше логики в базу данных. А у вас получается другая крайность.


  1. lair
    07.10.2022 23:09

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


    1. via-site Автор
      08.10.2022 10:06

      Спасибо за комментарий. Прямо сейчас это можно увидеть на примере виджета локализации: https://uiwebkit.com/wgt/loc/2/menu/?type=element. Там есть табы, переключаясь между ними можно увидеть разницу. Исходники: https://github.com/uiwebkit/localize. Еще, как писал выше, сейчас я готовлю к публикации проект поменьше и там этот эффект выглядит нагляднее.


      1. lair
        08.10.2022 14:32
        +2

        Ээээ… я из этого примера не понял ничего.


  1. WVitek
    07.10.2022 23:27

    На сайте, указанном в тексте статьи, на данный момент картинки не прогружались, "красивостей" увидеть не удалось...


  1. Croakerx64
    08.10.2022 09:46

    а чем вам Web-Components не угодили?


    1. via-site Автор
      08.10.2022 09:48

      CDD как раз с ними отлично сочетается. Но данный принцип/подход можно использовать не только с Веб-компонентами.


  1. PavelZubkov
    09.10.2022 18:05
    +2

    Когда-то размышлял на тему кастомизации, получилась такая картинка.

    Место расширения -> в месте определения -> добавления кода: имеется ввиду случай, когда нужно изменить существующий компонент, что-то в него добавив

    Аспекты расширения -> компоновка: этот пункт про иерархию вложенности компонентов

    Стратегия расширяемости ->...-> DSL: компоненты в определенных терминах, описывается на отдельном декларативном языке, из которого генерируется более низкоуровневое представление, отвечающее требуемым возможностям по расширению, добавлению поведения/оформления

    Стратегия расширяемости ->...-> Вручную: это как в пункте выше, но требуемое более низкоуровневое представлении пишется руками