Как стать автором
Обновить
8
0

Пользователь

Отправить сообщение
К сожалению, какого-то визуального оформления архитектуры нет. Но там в основе лежат приемы, которые были ранее описаны в статьях про подбор, регистры, иерархии и вот эта.
Как раз наоборот. Наша практика показала, что это очень гибкая схема при необходимости изменений. Например, свойство price для 4х ключей объявляется как-то, затем используется в тысячи мест. А когда нужно изменить расчет, то он просто меняется, а все остальное продолжает работать как и раньше. При этом на нативном уровнем, все продолжает компилироваться в SQL.

Поэтому было бы интересно увидеть статью именно о проектировании архитектуры достаточно сложной системы, с подробным обоснованием выбранных решений.


Собственно мы и пишем статьи о том, какие «шаблоны» мы используем при проектировании сложной системы. Она и состоит из множества таких архитектурных решений. В статье есть ссылка на сложную систему — ERP-систему для розницы.
К сожалению, пока ничего нет в это части. Мы пока акцентируем внимание на бизнес-приложениях и информационных системах, но для таких вещей есть из коробки JSON API, возможность прямо из lsFusion кода делать HTTP вызовы, и возможность спускаться на уровень ниже и писать на Java.
Кстати, да — можно через сегменты. В lsFusion это делается легко, вот так:
CLASS Segment 'Сегмент';
name 'Наименование' = DATA ISTRING[50] (Segment);
threshold 'Порог' = DATA NUMERIC[14,2] (Segment);
discount 'Скидка' = DATA NUMERIC[8,2] (Segment);

segment (Customer c) = 
    GROUP LAST Segment s 
          ORDER threshold(s), s 
          WHERE soldSum(c) >= threshold(s) MATERIALIZED;

price (Customer c, Product p, Stock st, DATE d) = 
    price(p, st, d) * (100 (-) discount(segment(c))) / 100;


soldSum по покупателю — это по какой-то формуле рассчитанный объем продаж. При этом сегменты в такой реализации будут хранится в таблице покупателей и автоматически пересчитываться при изменении суммы продаж.
Не обязательно каждый возможный. На lsFusion сначала делается логика, а потом уже в эксплуатации добавляются MATERIALIZED на промежуточные свойства, чтобы ускорить чтение, но замедлить чуть чуть запись. Более подробно мы писали вот в этой статье.

Когда добавляется новый MATERIALIZED на старте автоматически создается поле и рассчитывается по нужной формуле. Обычно это идет достаточно быстро, так как этот расчет идет не на сервере приложений, а одним запросом на SQL сервере и делается достаточно быстро (мы на практике добавляем поля как в таблицы с сотнями миллионов записей, так и где расчет зависит от таких таблиц). И это все занимало максимум один час. Добавление пустой колонки в PostgreSQL вообще мгновенная операция.

В любом случае, тут 2 варианта: либо считать в момент запроса, либо при записи инкрементно обновлять значения. Третьего не дано. И в lsFusion это все делается прозрачно, без изменения остальной логики приложения.
Хорошее быстродействие. Так как там никакого ORM не будет, а все скомпилируется в один (или чуть больше) оптимизированных SQL запросов, которые считают нужные данные.

Правда запросы будут зависеть от расставленных MATERIALIZED. Как я писал в статье: можно денормализовать через MATERIALIZED кортеж из PriceListDetail, Stock в одну таблицу и построить по ней индекс по полям (product, stock, fromDate). Тогда для каждого product и stock PostgreSQL будет находить цену по индексу за логарифм.

Если учитывать другие параметры (объемы продаж и прочее), то тоже можно сделать MATERIALIZED на них, и все будет хранится в таблицах покупателей (или других с небольшим количеством записей) и автоматически обновляться. Тогда к ним будет идти простой JOIN. Ну или не делать все эти MATERIALIZED, тогда СУБД будет их высчитывать в момент запроса (пойдут такие запросы).

У нас на практике в таких денормализованных таблицах хранятся сотни миллионов записей, и работает все достаточно быстро (хотя это относительно конечно). Но сделать быстрее в такой логике вряд ли получится.
Можно сделать вот как: есть базовые прайсы как в статье. Дальше, на основе их уже высчитаны текущие цены: см. свойство price (Product, Stock, DATE). Дальше можно его умножать, или делить, например, на скидку покупателю (или любое другое выражение). То есть:
price (Customer c, Product p, Stock st, DATE d) = price(p, st, d) * (100 — discount( c )) / 100;
И дальше использовать эту цену в заказах или где-то еще.
Не очень понял, куда именно нужно добавлять покупателя. Для каждого покупателя будут свои прайсы? Если так, то просто добавляется в шапку покупатель, а затем в расчете priceListDetail (Product p, Stock s, DATE dt) добавляется еще один параметр, который затем используется в WHERE. И получаются разные цены для разных покупателей.

Информация

В рейтинге
Не участвует
Работает в
Зарегистрирован
Активность