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

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

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

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

Проблема 

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

Идея

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

Реализация

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

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

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

 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Итоги

 Этот механизм позволяет нам решить несколько проблем.

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

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

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

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