Привет, Хабр! Последние 6 лет я работаю системным аналитиком и понимаю, что при внедрении разного рода учётного функционала аналитикам часто приходится переносить остатки из старых систем с сомнительным качеством данных. В этой статье я расскажу, как разработать сервис балансового учёта так, чтобы не пришлось переносить остатки.
Перенос остатков для аналитиков и разработчиков — удовольствие ниже среднего, потому что:
- Приходится копаться в невероятно большом количестве данных, накопленных за много лет:
- Такая информация, как правило, не стандартизирована, так как программное обеспечение, которое её сохраняет и читает, постоянно дорабатывается. Например, у нас был случай, когда оказалось, что стоимость товара указывается в поле «Cost» только последние пять лет, а раньше было вообще по-другому. И тот факт, что мы это узнали, — просто счастливая случайность.
- Вместе с огромным количеством данных накапливается огромное количество ошибок, так как внесение практически любой информации так или иначе связано с ручным вводом данных, а человеческий фактор никто не отменял.
- Команда хочет заниматься именно разработкой нового программного обеспечения. Копание в цифрах и попытки свести их с другими цифрами — это не то, что коллеги будут делать с удовольствием и должным вовлечением.
Итак, как же можно решить проблему переноса остатков?
Для начала давайте определимся с терминологией. Под сервисом балансового учёта я понимаю инструмент, который учитывает изменения состояний объектов таким образом, чтобы, просуммировав эти данные, можно было получить картину на любой момент времени.
Приведу пример из моей практики в Ozon.
Разработка производилась для Ozon 3PL — сервиса, с помощью которого мы доставляем товары внешних интернет-магазинов (принципалов) с использованием логистической инфраструктуры Ozon.
Функционал, о котором я расскажу:
- Зачисляет на баланс стоимость товаров от внешних интернет-магазинов в тот момент, когда они передают их в Ozon 3PL.
- Списывает с баланса стоимость товаров от внешних интернет-магазинов, когда они:
- вручаются получателю;
- возвращаются отправителю;
- ломаются или теряются в процессе перевозки.
Путём суммирования сформированных сервисом данных можно быстро определить, сколько товаров от внешних интернет-магазинов было у нас в любой момент времени. Этот показатель и есть «баланс».
Понимание, сколько товаров и на какую сумму было у нас в тот или иной момент времени, помогает глубже анализировать стоимость наших ошибок, а это, в свою очередь, является важной частью работы по непрерывному улучшению.
Запуская в промышленную эксплуатацию эту программу, мы понимали, что на момент запуска у нас будет какое-то количество товаров от внешних интернет-магазинов. Мы могли бы вычислить их общую стоимость аналитически:
Но делать это всё мы, конечно, не будем.
Предлагаю вашему вниманию четыре простых (или не очень) шага по разработке сервиса балансового учёта, в который не нужно переносить остатки.
Шаг 1. Определение объекта балансового учёта
В рассматриваемом примере объект учёта — это стоимость товаров внешних интернет-магазинов, которые физически находятся в логистической инфраструктуре Ozon.
Что такое логистическая инфраструктура
Под логистической инфраструктурой понимаются:
- Сортировочные центры.
- Пункты выдачи заказов.
- Машины.
- Курьеры.
- И так далее.
Если вы собираетесь автоматизировать балансовый учёт, у вас наверняка будут другие объекты. Но предположу, что наше решение подойдёт почти для любого. Если же объектов учёта множество, его можно применять для каждого из них параллельно.
Шаг 2. Определение состояний объекта балансового учёта
Перечислим состояния объекта учёта, которые могут нас интересовать. В нашем случае это:
- Стоимость товара внешнего интернет-магазина появляется, когда покупатель его заказывает (я знаю о практике некоторых интернет-магазинов не фиксировать стоимость товара в момент его заказа покупателем, но мы такое пока не поддерживаем).
- Стоимость товара меняет своего владельца на компанию, которая доставит товар покупателю.
- Стоимость товара меняет своего владельца на физическое или юридическое лицо, которому его доставила транспортная компания.
- Стоимость товара меняет своего владельца на интернет-магазин отправителя ввиду возврата товара или компенсации его утраты.
Шаг 3. События, которые являются причинами изменений состояния
Рассмотрим события, которые изменяют состояние объекта учёта.
Поскольку нас не интересуют события и состояния товара (и его стоимости) во внешнем интернет-магазине, их мы обрабатывать не будем.
В вашем проекте могут быть другие события и состояния. Просто подставьте их в эту модель.
Как наложить свою задачу на мою модель
Например, вам нужно автоматизировать учёт загруженности отдела, который вручную проверяет договоры, то есть сделать штуку, которая будет отвечать на вопросы вроде «Сколько договоров сейчас находится на проверке в отделе?», «Сколько их было вчера?» и так далее. Целью такой разработки может быть получение возможности видеть, когда отдел перегружен, а потом, глядишь, и прогнозировать это, чтобы предотвращать.
Берёте мою модель и накладываете на неё свои данные:
Берёте мою модель и накладываете на неё свои данные:
Далее находим способ автоматизированной ловли интересующих нас событий. Я не буду описывать тот, что я применил в Ozon, так как он оказался осуществим благодаря более или менее стандартизованной трансляции событий из различных систем (есть вероятность, что этот способ мало где ещё может быть применим).
После того как мы поймали событие, которое предполагает новое состояние объекта учёта, нам необходимо определить текущее состояние последнего. Таким образом, мы будем иметь:
- Текущее состояние объекта учёта, потому что мы его только что определили.
- Предполагаемое состояние объекта учёта, потому что оно соответствует событию, которое мы поймали.
С этими данными нужно обратиться к таблице сочетаний текущих и предполагаемых состояний объекта.
Шаг 4. Сочетания текущих и предполагаемых состояний объекта учёта
Таблица сочетаний текущих и предполагаемых состояний объекта учёта нужна для того, чтобы:
- Не списывать с баланса те объекты учёта, которые на него не зачислялись.
- Выявлять ошибочные действия пользователей в системе и на основании этого:
- ничего не делать с балансовым учётом
- откатить старые неверные балансовые движения, заменяя их на новые верные.
Для создания такой таблицы необходимо определить все возможные парные сочетания состояний объекта балансового учёта. Для этого я рекомендую воспользоваться калькулятором комбинаций. Его интерфейс прост и интуитивно понятен. Я уверен, что вы легко разберётесь в нём самостоятельно, но всё же покажу, какие данные нужно вводить, чтобы получить все возможные парные комбинации состояний объекта учёта, которые разбираются в нашем примере.
В результате мы получим таблицу со всеми возможными комбинациями текущих состояний объекта учёта и его предполагаемых состояний.
Как вы можете заметить, мы разделили полученные комбинации на следующие типы:
- Нереальные (выделены серым цветом и зачёркнуты).
- Желаемые (выделены зелёным цветом).
- Ошибочно тупиковые (это проблемы, которые мы не можем решить откатом предыдущей операции с товаром, они выделены жёлтым цветом).
- Ошибочно нетупиковые (проблемы, которые мы можем решить откатом, они выделены голубым цветом).
Но это ещё не окончательный вариант нашей таблицы. Для каждого сочетания ещё нужно:
- Составить список действий, которые должен совершить сервис.
- Определить направление движения сторнирующих движений (если они нужны).
- Написать текст ошибки (если вы собираетесь вести лог).
Короче, у меня получилось вот это:
Повторный краткий обзор того, как будет работать предполагаемый сервис
Давайте ещё раз повторим, как будет работать наш сервис:
Внедрение без переноса остатков
Благодаря применённой технологии (назовём её «Подумай дважды») система не спишет с балансового учёта те объекты, которые на него не зачислялись. Таким образом, тот факт, что в момент внедрения решения система не знает о тех объектах учёта, которые уже должны были быть в учёте, не заставит учёт уйти в минус.
Объекты учёта, которые мы не перенесли, в довольно скором времени физически примут конечный учётный статус и снимутся с забаланса.
Через какое-то время наш сервис будет показывать точное количество объектов учёта на балансе (так как новые стабильно будут фиксироваться). И эти показания будут точнее, чем даже если бы мы мигрировали остатки, потому что большое количество данных почти всегда содержит большое количество ошибок.