Как мы решили проблему неизвестности источника модификации элемента, или «как понять, почему элемент изменился»?

Всем привет! На связи Владимир Колесников и Владимир Беневоленский из ИТ-команды подразделения ДОМ.РФ Земли. Здесь мы уже рассказывали о том, чем мы занимаемся, но напомним: в ДОМ.РФ мы создаём систему автоматизации вовлечения в оборот неиспользуемого федерального имущества. Другими словами, мы разрабатываем продукт на Б24, в котором земельные участки (ЗУ) проходят долгий путь от появления в системе до реализации на торгах. 

09d47438f1de78e69b5b1aa0510e8044.jpg

Сокращённо мы СУЗФ — система управления земельным фондом. Почему наша система работает на Битрикс24? Да бог его знает, так было задумано свыше. Но, как говорится, от своей судьбы не уйдешь. Проблема, с которой мы столкнулись, случилась бы в любом случае, независимо от того, использовали бы мы Б24 или нет.

СУЗФ — огромная система с кучей сущностей и процессов, в которой, естественно, всё работает как швейцарские часики (спасибо нашему тимлиду). Мы оперируем 25–30 сущностями и ~900 свойствами, но основные сущности — это лоты, земельные участки, торги, документы (кстати, документов у нас около трёхсот тысяч). Каждая сущность имеет свою логику создания и изменения. Это могут быть различные источники модификаций. Например, земельный участок может создаваться/модифицироваться внутри системы логикой трансформации (межевания) участков / обновляя какие-либо данные через выписку ЕГРН (единый государственный реестр) или обновляя гео-данные через интеграцию с сервисами наподобие DaData и пр. Причем нужно заметить, что обновления  так же могут происходить по событию (EventHandler) и по интервалу времени (Cron).

В среднем за день у нас происходит около 35 тысяч модификаций элементов.

Проблема 

dd72de11ca0ddcd5fe86aec98d0eb84d.jpg

И жили бы мы так долго и счастливо, но «бизнес» интересовался природой случайной модификации элемента. С ростом системы генерировать отделом разработки ответы с причинами изменений стало уже невозможно. Проблема возникла, когда мы конкретно перестали понимать, почему какой-либо элемент сущности создался или изменил свои параметры.

Идея

Возник вопрос: как бы нам красиво снять с себя ответственность за модификации элементов? Нам был нужен механизм: единая точка входа для создания/изменения элемента и разные данные в зависимости от источника.

3779a2c0fc9b6e39710c04c1f6609aa8.jpg

Реализация

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

Как это работает? Каждый раз, когда происходит создание/обновление элемента, эта система логирует источник и список измененных полей. Например, если земельный участок был изменен через выписку ЕГРН, система сохранит эту информацию и привяжет ее к элементу участка. Таким образом, у нас всегда будет доступ к полной истории изменений элемента и понимание, почему он был создан или изменен, когда и кем.

064e8ceb014ba4e585a18dbd275c24a1.jpg

 У нас есть базовый абстрактный класс для добавления и изменения элемента (рис. 1):

Рис.1. Базовый класс

Рис. 1. Базовый класс

 Внутри этого класса есть:

·        Метод getDescription (), который возвращает описание логики модификации/создания элемента

·        Метод getFields (), в котором подготавливаем поля для элемента, данные из этого метода будем получать в методе сохранения save () в базовом классе

·        Метод onBefore (), в котором мы можем валидировать переданные данные перед сохранением либо выполнять какую-то дополнительную логику, необходимую до сохранения

·        Метод onAfter () для дополнительной логики после сохранения элемента

·        Метод createOrUpdate (), который изменяет/создает элемент. В него мы можем передать ID элемента, если элемент нужно модифицировать.

Рис.2. Метод createOrUpdate()

Рис. 2. Метод createOrUpdate ()

Внутри метода createOrUpdate () мы сохраняем элемент через метод save () и сохраняем в логи результат сохранения элемента (рис. 3). Внутри метода save () мы только вызываем метод createOrUpdate (), но уже из класса для работы с элементами инфоблоков (инфоблок — одна из сущностей БД Б24).

Рис.3. Обновление/создание элемента (метод из класса для работы с элементами инфоблоков)

Рис. 3. Обновление/создание элемента (метод из класса для работы с элементами инфоблоков)

 Таким образом выглядит структура источников для элементов (рис. 5):

Рис.4 Структура источников элементов

Рис. 4 Структура источников элементов

Классы источников мы наследуем от базового класса (рис. 5):

Рис.5 Класс источника

Рис. 5 Класс источника

Если в функцию createOrUpdate () мы передаём ID элемента, элемент обновляется, если не передаём — элемент создаётся.

Сохранение элемента происходит таким образом (рис. 6):

Рис.6 Сохранение элемента

Рис. 6 Сохранение элемента

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

058ae0522920e4ade34d34a644abdd37.jpg

Сохранение элемента может быть вызвано каким-либо событием (EventHanlder) либо запущено по истечении интервала времени.

Для таких случаев у нас есть два интерфейса для класса источника: Eventable и Periodic. От Periodic добавляется метод, в котором определяется, пора ли нам запустить сохранение элемента. От Eventable — метод, в котором в класс-регистратор обработчиков событий мы возвращаем событие сразу с его обработчиком.  

Интерфейс Eventable на рис. 6. и Periodic на рис. 7.

Рис.7 Интерфейс Eventable

Рис. 7 Интерфейс Eventable

Рис.8 Интерфейс Periodic

Рис. 8 Интерфейс Periodic

На рис. 8 мы регистрируем обработчики событий.

Рис.9 Регистрация обработчиков событий

Рис. 9 Регистрация обработчиков событий

Итоги

 Этот механизм позволяет нам решить несколько проблем.
Во-первых, он упрощает процесс отладки и исправления ошибок. Если у нас возникают проблемы с элементом, мы можем быстро определить источник модификации и найти причину проблемы. Во-вторых, он помогает повысить прозрачность работы системы. Мы можем предоставить пользователям доступ к информации о модификации элемента, чтобы они могли видеть, какие действия привели к изменению элемента и убедиться в его достоверности.

Кроме того, это позволяет анализировать данные и выявлять тенденции и паттерны в модификации элементов. Мы можем использовать эти данные для оптимизации процессов и повышения эффективности работы системы.

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

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

148810d2c86a0ead09fa4385cd8289c3.jpg

© Habrahabr.ru