
Введение
Сегодня мы покажем инструмент, который помог избавиться от хардкода в одной из legacy систем. Он здорово облегчил жизнь разработчикам и команде сопровождения. Возможно, кто-то найдет в нашем тексте решение и своей похожей проблемы.
Инструмент постараемся описать простым языком, без использования математических формул и заумных формулировок, ведь мы хотим продемонстрировать его практическое применение. Речь пойдет о аналитической подсистеме в CRM (далее по тексту просто «система»), которая отвечает за создание стратегии взаимодействия с потенциальным клиентом.
Немного предыстории
Опишем ситуацию, в которую мы попали около 5 лет назад. Возможно, кто-то узнает в ней себя, потому что история типовая.
На сопровождение и развитие нам передали CRM-систему. Если с частью системы, которая отвечает за работу операторов – звонки, сбор и накопление данных – все было понятно, то аналитическая часть, которая выстраивала стратегию взаимодействия с потенциальными клиентами, оказалась черным ящиком, да еще и со своими «скелетами в шкафу».
Проблемы, с которыми мы столкнулись:
-
Практически любое изменение бизнес-правил приводило к корректировке кода. Условно говоря, добавлялся новый «IF». С ростом бизнеса скорость и объем вывода новых изменений постоянно увеличивались. Изменения нужно было применять, что называется, на лету, однако текущий подход не позволял этого делать. Система превратилась в «кладбище с привидениями».
-
В случае возникновения вопросов отсутствовала возможность без привлечения разработчиков понять, почему был сделан тот или иной выбор. Разбор кейсов занимал длительное время.
Рефакторинг. Новые требования к системе
Всем стало ясно, что для дальнейшего развития системы нужны кардинальные изменения.
После анализа мы сформулировали ряд требований для рефакторинга. Вот они:
-
Вынести все бизнес-правила из кода приложения в настройки.
-
Заложить потенциал к подключению UI для визуализации бизнес правил.
-
Добавить возможность повторить расчет с учетом параметров субъекта на момент принятия решения.
-
Заложить возможность перенастройки основного объема бизнес-правил «на горячую» — без простоя системы. Сложность состояла в том, что надо было все запланированные требования выполнить без изменения бизнес-логики существующих процессов. А еще переход надо было совершить плавно, чтобы конечные пользователи не заметили никаких изменений.
Наше решение
В заголовке статьи мы намекнули, что ставку сделали на «дерево принятия решения» (далее просто дерево) и так называемые аналитические признаки.
Сначала раскроем суть некоторых терминов.
Дерево — структура данных, состоящая из узлов, которые соединены направленными дугами. В каждый узел ведет только одна дуга (кроме корневого, у которого вообще нет входящих дуг – см. рис.1).
Корневой узел — это начальный узел, не имеющий предков
Лист — это конечный узел, из которого не выходит ни одной дуги.

Структуру можно считать деревом, если выполняются следующие условия:
-
Есть только один корневой узел. Из него стартует обход узлов дерева.
-
Каждый некорневой узел имеет только одного предка. Аналитический признак предлагаем рассматривать как некий параметр, значение которого анализируется при принятии решения. Это может быть:
-
Простой параметр – статический, например, продукт из интернет-заявки, возраст субъекта, пол и т.п.
-
Более сложный – динамический, вычисляемый в моменте и зависящий от ряда фактов.
Факты могут быть самыми изощренными из разряда «наличие интернет-заявок за последние 30 дней, поданных субъектом с определенным продуктом после дождичка в четверг, когда семь планет выстроились в ряд» и т.п.
Таким образом, аналитические признаки дают нам механизм, который позволяет упаковать экзотические требования заказчика и далее, жонглируя ими, настраивать бизнес-правила в деревьях.
Структуры в базе данных
Упростим структуры данных до минимума, который позволит продемонстрировать рассматриваемое решение. Даже замахнемся на святое — нормализацию ?.
Справочник аналитических признаков T_ANALYSIS_UNITS
|
Наименование |
Тип |
Комментарий |
|
ANALYSIS_NAME |
Строка |
Уникальное наименование |
|
ANALYSIS_DESCR |
Строка |
Описание |
|
DATA_TYPE |
Строка |
Тип аналитического признака (строка, число, дата) |
Таблица дерева T_TREE
|
Наименование |
Тип |
Комментарий |
|
ID |
Число |
Ид. Первичный ключ |
|
ID_PARENT |
Число |
Ид записи родителя |
|
ANALYSIS_NAME |
Строка |
Аналитический признак |
|
PRIORITY |
Число |
Приоритет обхода дерева на уровне |
|
ANALYSIS_COMPARE_VALUE |
Строка |
Значение аналитического признака для сравнения |
|
OPERATOR_TYPE |
Строка |
Оператор сравнения (=, >, <, >=, <=, !=, in) |
|
TARGET_VALUE |
Строка |
Целевое значение |
Графическую перечисленные структуры мы отобразили на рис 2.

Алгоритм принятия решения
Целью работы алгоритма является определение целевого значения. Этим значением для разных типов деревьев может быть: дата вывода на обзвон, дата отправки информационного сообщения, выбор финансового консультанта, выбор причины исключения из обзвона и т.п.
В демонстрационном примере будем выбирать абстрактную стратегию взаимодействия с клиентом.
Ниже представлены записи в таблицах T_ANALYSIS_UNITS и T_TREE, которые задают структуру дерева на рис 2.
|
T_ANALYSIS_UNITS |
||
|
ANALYSIS_NAME |
ANALYSIS_DESCR |
DATA_TYPE |
|
А1 |
Тип события |
Строка |
|
А2 |
Город проживания |
Строка |
|
А3 |
Продукт |
Число |
|
А4 |
Сумма кредита |
Строка |
|
А5 |
Время поступления интернет-заявки. После 21:00 принимает значение ‘Y’, иначе ‘N’. |
Строка |
|
T_TREE |
||||||
|
ID |
ID_PARENT |
ID_ANALYSIS_UNIT |
PRIORITY |
ANALYSIS_COMPARE_VALUE |
OPERATOR_TYPE |
TARGET_VALUE |
|
1 |
А1 |
100 |
EventInternetApp |
= |
||
|
2 |
1 |
А2 |
100 |
Казань |
= |
|
|
3 |
1 |
А2 |
100 |
Саратов |
= |
|
|
4 |
2 |
А3 |
100 |
Продукт_01 |
= |
Стратегия_01 |
|
5 |
2 |
А3 |
100 |
Продукт_02 |
= |
Стратегия_02 |
|
6 |
3 |
А5 |
120 |
Y |
!= |
Стратегия_03 |
|
7 |
3 |
А3 |
100 |
Продукт_03 |
= |
Стратегия_04 |
|
8 |
3 |
А3 |
100 |
Продукт_04 |
= |
|
|
9 |
3 |
А3 |
100 |
Продукт_05 |
= |
Стратегия_05 |
|
10 |
8 |
А4 |
100 |
100000 |
<= |
Стратегия_06 |
|
11 |
8 |
А4 |
100 |
100000 |
> |
Стратегия_07 |
Как все это работает?
Предварительно рассчитываем значения всех аналитических признаков. Получаем их в виде коллекции. Начинаем пробегать дерево. Обход стартует с корня. Движемся сверху вниз.
Порядок обхода узлов дерева, находящихся на одном уровне, определяется их приоритетом. Приоритет нужен в случае, когда на одном уровне встречаются узлы с разными аналитическими признаками.
Чтобы провалиться в узел, мы должны выполнить его условия. Для этого:
-
Из узла берем аналитический признак.
-
Подтягиваем заранее посчитанное для него значение.
-
Сравниваем с эталонным значением, применяя оператор сравнения, указанный в узле.
-
Если результат операции сравнения true, то проваливаемся в узел.
-
Если false, то путь закрыт – переходим к следующему узлу.
Обход завершается при наступлении одного из событий:
-
мы достигли любого листа дерева (получили целевое значение),
-
обошли все дерево, но так и не удалось добраться до листа (ничего не выбрали).
Примеры
На вход дерева подадим коллекцию значений аналитических признаков.
Пример №1:
А1 = EventInternetApp, А2= Казань, А3= Продукт_02, А4= 80000, А5= Y

Результат выбора: Стратегия_0
Пример №2:
А1 = EventInternetApp, А2= Саратов, А3= Продукт_03, А4= 80000, А5= N

Результат выбора: Стратегия_03
История расчета
Все посчитанные значения аналитических признаков сохраняются в базу данных. Это позволяет при возникновении вопросов или спорных ситуаций повторить расчет по дереву и провести анализ. Объем данных большой, поэтому период хранения ограничен: в нашем случае 6 месяцев.
Подведем итоги
На этом, пожалуй, все. Материал пытались изложить максимально кратко, не перегружая подробностями реализации. Цель – поделиться опытом и продемонстрировать удачное решение в действии. Как бывает в жизни: есть алгоритмы или математические модели, но как их применить на практике – не всегда очевидно.
Классическое решение в виде «дерева выбора» обладает двумя ключевыми свойствами:
-
Гибкость настройки (добавил/переместил узел дерева – получил желаемую логику).
-
Простота визуализации (для отображения прикрутить UI не составит особого труда).
Последнее свойство дарит еще такую плюшку как «самодокументирование».
Функционал дерева можно постоянно расширять под свои задачи. Например, на начальных этапах у нас были простые операторы сравнения в узлах, позже мы добавили операторы работы со множествами. Область применения ограничивается только вашей фантазией ? Спасибо за внимание! Надеемся, что материал был для вас полезен.
ссылка на оригинал статьи https://habr.com/ru/company/sovcombank_technologies/blog/597799/
Добавить комментарий