Заглавная картинка служит для того, чтобы показать, во что превратится ваш пользовательский интерфейс и система дизайна, если вы начнете полагаться на паттерн Server-Driven UI в своем проекте для создания экранов и компонентов. Основная идея этой статьи заключается в том, чтобы отговорить вас делегировать ответственность за дизайн и определения фронтенда вашему серверу. Я уже имел дело с несколькими проектами, которые пытались реализовать этот ужасный паттерн, и все они приносили огромную головную боль своим инженерам, будь то ошибки, сбои, неожиданные изменения пользовательского интерфейса в разных версиях или несогласованность.
Что такое управляемый сервером пользовательский интерфейс
Многие считают его паттерном дизайна, но я считаю его антипаттерном. По сути, это способ делегировать определение пользовательского интерфейса (цвета, шрифты, макет и так далее) бэкенду, который на самом деле должен заботиться о других задачах, таких как безопасность, манипуляция данными и удаленные ресурсы.
Server-Driven UI может иметь несколько различных способов отправки данных пользовательского интерфейса на фронтенд, что усложняет разбор всего этого. Допустим, у вас есть экран, который реализует хаб в приложении электронной коммерции, где есть список товаров, которые можно купить. SDUI может состоять из отправки свойств для этого экрана, таких как размер шрифта заголовка, цвет фона элементов тела или даже ограничения расстояния между ними. Единственная обязанность вашего мобильного фронтенда — разобрать информацию, пришедшую в виде строк (нет, вы не можете отправить объект Color в JSON), на соответствующие модели пользовательского интерфейса и представить их в сцене.
Люди приводят несколько весомых преимуществ этого (я хочу быть честным в своем анализе), но они не оправдывают проблем:
- Возможность настраивать тему приложения с помощью небольших изменений данных в бэкенде (например, если вы хотите изменить основной цвет на красный в рождественский праздник).
- Издание других приложений становится простым с разными ответами бэкенда для разных целей (что можно сделать с помощью фиче флагов)
- Возможность вносить огромные изменения в дизайн вашего приложения без необходимости выпуска нового релиза в магазине.
Однако, как я уже говорил, все эти плюсы могут быть гарантированы и при использовании различных подходов.
Я предоставлю вам 6 веских причин, чтобы вы никогда не думали о применении этого подхода в своих проектах. Надеюсь, вам понравится, а отзывы и различные точки зрения приветствуются.
1. Тесная связь между пользовательским интерфейсом и бэкендом
Я изучал и применял чистые архитектуры и принципы SOLID на протяжении всей своей карьеры, и одна из самых важных вещей, которую я узнал, и которой меня учили даже в университете, — это то, что пользовательский интерфейс и бизнес-логика должны быть разделены. Они должны быть полностью изолированы друг от друга, и это включает в себя не только разделение кода, но и отсутствие даже понятия о существовании другого.
Именно поэтому я не рекомендую называть классы ViewModel как ScreenViewModel и предоставлять им доступ к свойствам пользовательского интерфейса, таким как цвета и шрифты. Что происходит в Server-Driven UI, так это то, что вы создаете взаимозависимость между обеими сторонами приложения. Ваш бэкенд становится ответственным за принятие решений и предоставление каждого элемента пользовательского интерфейса, что ужасно по многим причинам. Теперь любой новый вопрос с представлением вовлекает множество различных заинтересованных сторон.
2. Сложности с отладкой
Нет единого мнения о том, кто именно должен отвечать за кодовую базу SDUI, однако, если возникает какая-либо ошибка или сбой, ее гораздо сложнее отладить и исправить, поскольку пользовательский интерфейс распределен по нескольким кодовым базам.
Иногда мы не можем быть уверены, что вызвало проблему — определение UI на сервере или парсинг JSON во фронтенде. Ситуация становится еще сложнее, если мы используем гибридный подход, когда только часть пользовательского интерфейса поступает из бэкенда, а остальная верстка и другие обязанности остаются в мобильном проекте. Синхронизация всех инженеров фронта и бэка, чтобы разобраться с этим, потребует огромных усилий (и очень долгих совещаний).
3. Отсутствие определения ответственности
Этот пункт напрямую связан с предыдущим, поскольку вызывает много путаницы и взаимозависимости между фронтом и бэком, но я рассмотрю это с точки Agile. При определении доски спринта, кто должен отвечать за создание и поддержку пользовательского интерфейса?
Некоторые говорят, что мобильные инженеры должны отвечать за часть бэкенд-код, другие утверждают, что он должен оставаться в ведении команды API. Какой слой сервера должен обеспечивать пользовательский интерфейс, и как сделать его гибким для изменений? За это тоже должна отвечать команда дизайнеров? С моей самой общей точки зрения, бэк и команда дизайнеров — это совершенно разные миры, и они никогда не должны разделять подобные задачи.
Когда возникает ошибка, кто должен ее исправлять? Кто должен определять временную сложность? Кто должен обращать внимание на сбои?
4. Вы полностью уничтожаете смысл дизайн-системы
Дизайн-система (Design System) — это решение для повторного использования всех элементов пользовательского интерфейса и изоляции от бизнес-правил. Она улучшает тестируемость, повторное использование и синхронизацию между командами разработчиков и инженеров. Однако, полагаясь на серверно-управляемый подход, вы нарушаете это.
Одна из самых прекрасных вещей в системе дизайна — это возможность создать компонент в полностью изолированном виде и сделать его тестируемым для QA и команды разработчиков без необходимости наличия функции, в которую он вписывается. Вы можете создать всего лишь небольшой пример приложения для визуализации каждого из состояний компонента или даже просто сделать экран для демонстрации.
В SDUI нужны все данные для заполнения макета — это JSON-поля и объекты, которые приходится каждый раз инстанцировать, что снижает тестируемость за счет добавления ненужной сложности (представьте, как писать скриншот-тесты).
5. Зависимость от сетевого подключения
Еще один момент, который важно затронуть, и я думаю, что это худшая часть с точки зрения UX: вы всегда зависите от интернета, чтобы представить каждый из ваших экранов. Я знаю, что сложное приложение и так будет полагаться на сеть для получения данных из бэкенда, но есть простые экраны и сценарии использования, которым это не нужно (например, экран оформления заказа), и SDUI только добавит к ним ненужные требования.
Если ваш пользователь завершает транзакцию в банковском приложении после перевода денег, он просто хочет увидеть сообщение об успехе. Представьте себе головную боль от ошибки сети, когда сценарий использования фактически завершен и успешен.
6. Несоответствия модели данных
Теперь, с точки зрения кода, представьте, что вы отправляете с сервера строки, представляющие различные данные макета, например, цвет. Взгляните на этот код Dart:
import 'package:flutter/material.dart'; class SomeViewModel { // Function to parse color names to Color objects Color parseColorFromName(String colorName) { if (colorName == "red") { return Colors.red; } else if (colorName == "green") { return Colors.green; } else if (colorName == "blue") { return Colors.blue; } else if (colorName == "yellow") { return Colors.yellow; } else if (colorName == "orange") { return Colors.orange; } else if (colorName == "purple") { return Colors.purple; } else if (colorName == "black") { return Colors.black; } else if (colorName == "white") { return Colors.white; } else if (colorName == "grey") { return Colors.grey; } else if (colorName) == "pink") { return Colors.pink; } else if (colorName == "brown") { return Colors.brown; } else { // Return a default color (e.g., black) if the color name is not recognized return Colors.black; } } }
Эта функция парсит строку цвета в тип Color. У вас есть предопределенные цвета, но представьте, что реакция бэкенда меняется и вы начинаете получать цвета в верхнем регистре. Это изменение приведет к тому, что ваш дизайн сломается, и единственным цветом, который вы увидите, будет черный (по крайней мере, для динамических компонентов SDUI).
Эта несогласованность может стать еще хуже, если функция возвращает null и у пользователей происходят сбои. Если подобные изменения в внутренних протоколах происходят часто, макеты ваших экранов могут стать беспорядочными, а необходимость в хорошей коммуникации между фронтом и беком будет огромной.
Заключение
Мой главный посыл в этой статье — избегайте использования Server-Driven UI, насколько это возможно (если только команда разработчиков и руководство не разработают хороший конвейер для решения всех проблем). SDUI может сделать распределение кода и ответственности беспорядочным и трудноорганизуемым, даже если все находятся на одной волне. Это решение также может лишить вас гибкости в отношении новых решений в области дизайна и функциональности. Надеюсь, вам понравилась статья, и если вы все еще не согласны со мной, я с удовольствием выслушаю ваше мнение и продолжу обсуждение.