Сложность кода IMHO можно значительно уменьшить, переосмыслив взаимодействие с пользователем.
Принцип единой ответственности - это общий принцип программирования, который можно применять в программировании где угодно. Я считаю, что это неукоснительно соблюдается при написании backend services
. Но когда дело доходит до frontend
компонентов, мы много раз пытаемся объединить обязанности и построить тяжелые компоненты.
Это повторяющаяся картина, которую я постоянно наблюдаю.
- Приложения постепенно растут с появлением новых функций
- Становится обременительным добавлять новые функции поверх существующих.
Примеры сценариев:
- Приложение, управляемое данными, сконцентрированное на табличном компоненте
- Приложение для планирования, основанное на компоненте календаря
Давайте возьмем компонент таблицы в качестве примера сценария и погрузимся глубже.
Компоненты пользовательского интерфейса
В мире многоразовых компонентов пользовательского интерфейса сильно вложенные компоненты увеличивают сложность кода по мере развития приложений. Здесь мы не говорим о вложенности DOM. Мы говорим о сильно вложенных бизнес-обязанностях. Составление компонентов и поддержка компонентов более высокого порядка имеет полный смысл. Но иногда мы теряем эту границу и начинаем строить сильно связанные тяжелые компоненты. Сигналы, чтобы понять это:
- Есть ли многие бизнес-функции внутри одного MasterComponent?
- Тратит ли команда больше времени на то, чтобы стать экспертом в использовании MasterComponent или сделать его SuperMasterComponent, который может достичь более серьезных целей?
- Является ли бизнес-функция простой, но включение ее в MasterComponent со всеми другими зависимостями делает ее такой сложной?
Компонент таблицы, который управляет приложением, управляемым данными
Допустим, у нас есть онлайн-приложение для корзины покупок. Нам нравится иметь таблицу данных для детализации данных.
Функции, которые мы хотели бы иметь
- Просмотр заказов и их основных деталей
- Просматривайте заказы с подробной информацией о продукте, чтобы мы могли проанализировать
- Просматривайте заказы в зависимости от статуса доставки, доставлены ли они / в процессе / отменены и т. Д.
- Просматривайте заказы с платежными реквизитами, чтобы мы могли анализировать платежные данные
- Просматривайте заказы с данными о клиентах, чтобы мы могли анализировать информацию о клиентах
- Просматривайте заказы с помощью shipTo деталей, чтобы мы могли анализировать обслуживаемые нами местоположения
Одна таблица, которая выполняет все вышеперечисленное
Конечно, все вышеперечисленное можно реализовать в одной таблице с библиотеками типа ag-grid. Обратите внимание, как потрясающе это выглядит с таким детальным контролем над данными.
Так почему бы не купить / не создать компонент с обширной таблицей данных, который может все?
Если вашему бизнесу нужно создать лучший из возможных столов, тогда, конечно, вперед.
Если таблица - это способ выражения ваших данных, а основной бизнес - это не создание наилучшей таблицы, то существует множество способов сделать компонент пользовательского интерфейса как можно более легким, а бизнес-результаты - как можно более весомыми.
Допустим, мы решили создать собственный компонент расширенной таблицы.
- Команда начинает добавлять функции - слой за слоем поверх компонента таблицы с открытым исходным кодом.
- Функции могут пересекаться / конфликтовать друг с другом, вызывая разные потребности
- Нарушение функциональности теперь может привести к каскадному отказу других функций.
- Добавляя любую новую функцию, команда тратит больше времени на понимание того, что уже происходит в этих потоках, чем на то, что нужно сделать для новой функции. Это тормозит развитие
- Через несколько месяцев все в команде будут уклоняться от рефакторинга / очистки кода, потому что все они верят, что происходит слишком много вещей, и не хотят нарушать текущую стабильность.
- Производительность Backend API (ов) медленно снижается, а сложность возрастает. Возникают более сложные оптимизации, которые в будущем сможет поддерживать только меньшее количество членов команды.
- Команда пытается внедрить новые функции, внося минимальные изменения в существующие потоки, иногда не задумываясь, если мы сделаем это заново, нуждается ли этот бизнес-поток в такой сложности.
- Мертвый код / неиспользуемый код начинает расти, так как некоторые области частично очищаются, а остальное остается, поскольку это не останавливает выполнение приложения.
Как мы можем решить эту проблему лучше с помощью принципа единой ответственности
Один из подходов к уменьшению ответственности компонента (или к созданию легковесного компонента) заключается в передаче управления другим компонентам для выполнения другой ответственности.
Передача управления другим компонентам
Большинство из нас, возможно, уже знакомы со следующими примерами. Обычно их называют разным юзабилити. Но есть огромное преимущество с точки зрения сложности кода, поскольку они разделяют обязанности на разные потоки.
Обратите внимание на приведенную ниже таблицу, в которой разделены детали строки и строки.
- Ответственность за строку заключается только в том, чтобы получить необходимые данные.
- Если щелкнуть строку для получения подробной информации, он просто передаст управление совершенно новому компоненту, который позаботится о том, что необходимо сделать.
- Напротив, мы могли бы достичь того же потока с помощью группы по столбцу и вложенной таблицы. Но это все усложнит.
- Ошибка во вложенной таблице нарушит представление родительской таблицы.
- Исправление ошибки в родительской таблице или добавление функции в родительскую таблицу необходимо для обеспечения целостности функций вложенной таблицы.
- При извлечении данных нам нужно решить, будем ли мы выполнять предварительную выборку вложенных данных или по запросу.
- Если у нас есть сортировка по родительской таблице, необходимо убедиться, что представление вложенной таблицы не нарушено
- Если нам нужно иметь сортировку по дочерней таблице, необходимо убедиться, что родительская таблица стабильна.
- Что делать, если у вложенной дочерней таблицы есть дочерний элемент? В этом случае повторите все вышеуказанные проверки.
Использование модели или нескольких моделей
- Мы также можем передать ответственность, делегировав модели или многомодельные компоненты - Посмотреть примеры
- Это четко разделяет, кто что делает.
- Это делает базовую таблицу легкой с точки зрения функциональности и потребностей в данных.
- В зависимости от намерений пользователя они перемещаются в разные области.
Контекстные действия
Контекстные действия, подобные описанным выше, также помогут разделить обязанности и передать управление другим соответствующим компонентам.
Несколько представлений для одних и тех же данных
Нет правила, которое гласит, например, что «Данные транзакции» должны иметь одно табличное представление. Одни и те же «данные транзакции» могут иметь несколько представлений таблиц во внешнем интерфейсе с разными бизнес-целями. Думайте об этом, как о разных представлениях базы данных, применяемых к одному и тому же набору таблиц, предоставляя достаточно информации, необходимой в разном контексте.
Вот реалистичный пример: на веб-сайте, посвященном инвестициям на рынке акций, у нас может быть таблица для всех наших инвестиций.
Мы могли бы уместить текущие активы, детали транзакций, налоговые расчеты, данные о прибылях и убытках и т. Д. В одной таблице. Ух ты. Судя по опыту пользователей, я мог осуществить все, что хотел, в одном месте. Но в основном как пользователь я не прихожу к одному экрану с 25 целями.
Предоставляя разные представления, которые, в свою очередь, имеют одни и те же базовые данные, представленные в этом конкретном контексте, мы делаем потоки более легкими.
Доверие и надежность
Комбинируя вместе сложные функции и представляя их как единое рабочее окно, возникает риск потери доверия пользователей ко всему приложению. Как ?
Допустим, у нас есть 25 функций на одном столе. С точки зрения пользователей, именно эта таблица позволяет им реализовать 25 функций. Всякий раз, когда пользователь не может достичь своего намерения, он эмоционально думает, что эта таблица ненадежна / стабильна. С точки зрения пользователя всегда есть какой-то сбой. Старая ошибка в другом функционале может быть исправлена, но новый функционал теперь нестабилен. Время - иллюзия. Это заставляет пользователя поверить, он всегда находит что-то не так и больше не доверяет отображаемому.
Это как если мы покупаем машину и каждый день всплывает какая-то проблема. Хотя это могут быть разные части, со временем вы потеряете доверие к машине и не будете полагаться на нее в течение долгой поездки. После более длительного использования вы начинаете терять доверие к бренду (производителю), поэтому вы не сможете покупать следующий автомобиль той же марки.
Отправляя пользователей в разные потоки, мы обеспечиваем им прозрачность и возможность сопереживать приложению (как существу). Если что-то пойдет не так в одном потоке, они могут посочувствовать, скажем, потоки A, B, C стабильны, а потоки D и F нестабильны.
Читать далее
- Создавайте лучшие таблицы данных Эндрю Койл
Резюме
Я полностью согласен с тем, что с точки зрения пользовательского опыта это будет серьезным толчком к утяжелению компонентов пользовательского интерфейса.
Мои 2 цента - это нормально, если можно немного снизить удобство работы пользователя, если сложность кода может быть уменьшена в несколько раз. Лучший пользовательский опыт во многих случаях оказывается простым и легким.
Принцип единой ответственности может сделать
- разработка интерфейса более стабильная и надежная
- Тестирование (ручное / автоматическое) становится проще, поскольку не нужно проверять комбинацию сценариев.
- Это помогает избежать каскадных сбоев в работе. Если что-то сломается, сломается только эта функциональность.
- Снижает риск при непрерывной доставке. Даже если что-то сломается, легче примириться с этой областью приложения и как можно скорее развернуть исправление.
Опять же, нет ничего плохого в компоновке компонентов, при условии, что то, что скомпоновано, несет их единственную ответственность, а их побочные эффекты и сбои ограничены его собственными границами.