Иногда в интерфейсе наших приложений СБИС возникает необходимость «группировать» часть записей в каком-либо списке (например, сообщения служебного чата, контакты и телефонные звонки).
Хорошо, если все эти записи будут из одного источника, но если из разных сервисов, да с курсорной навигацией — алгоритм реализации становится весьма нетривиальным.
Я намеренно не буду приводить здесь реализацию «в коде», а опишу исключительно алгоритмический подход к решению, чтобы при необходимости вы могли самостоятельно масштабировать его под свои задачи.
Так.
Постановка задачи
У нас есть два сервиса.Их могло быть и больше, но, судя по предыдущей картинке, пусть будут для уверенности.
Услуги звонков и контактов .
Спасибо коллегам из CRM за интересное задание.
Мы хотим, чтобы это было в карточке организации в непрерывном хронологическом порядке отображать контакты и звонки по дате, но все звонки между соседними записями контактов «свернуть» в одну запись с указанием их количества.
Но в то же время интерфейс должен оставаться «живым» для пользователя — то есть не должно быть длинных пауз, когда мы чего-то ждем, но не рисуем список.
Группировка нескольких звонков в одну запись Сразу оговоримся, что сервисы работают с базой данных адекватно, есть все необходимые индексы, а запросы строятся качественно, примерно так, как я описывал в предыдущих статьях:
- Антипаттерны PostgreSQL: давайте выполним тяжелое соединение со словарем
- Антипаттерны PostgreSQL: навигация по реестру
- SQL HowTo: написание цикла while непосредственно в запросе, или «Ээлементарный трехшаг»
Плохое решение №1: «отдай мне все»
Понятно, что это возможно вычесть все сразу и слить его на бизнес-логику, но это приведет к тому, что интерфейс будет ждать хоть какой-то реакции, пока BL это не сделает все работа.И его действительно может быть много – только один могут быть сотни звонков .
А для сервиса задача «все отдать» совсем непростая, если есть данные за несколько лет работы.
Но зачем нам «все», если пользователь редко прокручивает дальше первой страницы ?
Неудачное решение №2: «тонкая расческа»
Значит, нам не нужно группировать контакты?.Давайте тогда сделаем это запросить первую страницу (20 записей) у службы контактов , А для каждого интервала даты между «соседними» контактами, спросим, что в звонках и сразу получим количество.
Теперь представим, что все наши звонки (или их много) были хронологически «выше» первого контакта — что произойдет? А будут такие же тормоза в интерфейсе , как и в предыдущей версии.
Кроме того, мы или мы отправим много запросов в сервис (для каждого из интервалов), что создаст избыточную нагрузку.
Или мы отправим один запрос со списком всех интервалов , но это, очевидно, займет много времени.
Успешное решение №1: «чтение по сегментам»
Допустив некоторые ошибки из предыдущих решений, приходим к выводу, что нам нужно запросить данные из обоих сервисов курсором — сколько записей (пусть будет 20), начиная с некоторого индексного ключа.Что делать дальше с двумя упорядоченными сегментами данных вполне очевидно — объединить( объединить заказы ) и отрезать ( предел ) из упорядоченных всех записей после ближайшего из «крайних» ключей от каждого из сервисов.
Например, в нашем примере оказалось, что клавиша времени последнего звонка соответствует только 15 из 20 прочитанных контактов.
О порядке остальных 5 контактов и других вызовов мы ничего сказать не можем, потому что "других вызовов" в обозримом пространстве нет - поэтому мы пока не можем их нарисовать .
Плохое решение №3: «Одно кольцо, чтобы править всеми»
Как любой разработчик хочет сразу упростить себе жизнь в предыдущей версии? Конечно, помните только один ключ — последняя нарисованная запись, чтобы затем можно было выполнить итерацию для следующего сегмента от нее.Но с этим вариантом некоторые данные будут прочитаны снова снова и снова — именно те, которые мы отбросили на предыдущей итерации и не отобразили.
В особо клиническом случае, типа «сначала много-много звонков, потом начинаются контакты», тот же самый первый сегмент контактов можно запрашивать много-много раз , с каждым сегментом вызова.
Плохое решение №4: «два ключа на стороне сервера»
Обратим предыдущую проблему себе на пользу - вспомним независимые ключи , отдельно для каждого источника.Это правильный ход, но он не избавит нас от проблемы повторного чтения одних и тех же данных, если нам негде их хранить .
Поскольку у нас есть серверный BL без сохранения состояния , то либо мы их не спасём, либо будем вынуждены их где-то городить отдельный государственный магазин .
Это можно сделать, но это совсем не просто:
- сегменты должны храниться уникальным образом ключ экземпляра -выборов на странице
- необходимый политика инвалидности эти данные со временем, чтобы память не «утекла»
- работа с этим репозиторием подразумевает дополнительные накладные расходы на сериализацию -пересылка-десериализация
Успешное решение №2: «два ключа на стороне клиента»
Собственно, зачем нам все это выносить на серверную часть, если все нам нужны только данные о клиенте ?.Оставим их там.
То есть именно те данные, которые «не были нарисованы», должны быть сохранены на клиенте (например, прямо в памяти вкладок, даже не в localStorage), пока нам не понадобится их отрисовать.
В нашем предыдущем примере вы получите что-то вроде:
- читать 20 контактов и 20 звонков параллельно
- звонки были «сгруппированы» в 5 записей
- сделал 5 «групповых» звонков + 15 контактов
- На складе осталось 5 невытянутых контактов
- Чего-то не хватает до 20? мы запрашиваем! (контактов и звонков по 20, параллельно со своих «крайних» клавиш)
- «задача сведена к предыдущей», только у нас уже 25 контактов на 20 звонков
Краевые случаи
По сути, единственный отрицательный эффект такого решения – это последний разыгранный "групповая" запись может "покрутить счётчик" , а мы дочитываем все новые и новые записи, «втекающие» в него.К счастью, эта ситуация вполне положительно воспринимается в интерфейсе , потому что мы показываем пользователю: «Ой, всё хорошо, мы не умерли, не зависли, мы работаем!» Теги: #Алгоритмы #программирование #ERP-системы #sql #sql советы и рекомендации #sbis
-
Бреаль, Мишель
19 Oct, 24 -
Виоль, Жюль
19 Oct, 24 -
4K-Видео Сатурна И Его Спутников
19 Oct, 24 -
Поставщики Инфраструктур Сущностей Ado.net
19 Oct, 24 -
Обычная История В Автосалоне Nokia
19 Oct, 24 -
Как Сайты Могут Удерживать Рекламодателей
19 Oct, 24