День 1525. #ЗаметкиНаПолях
Храните Информацию в Её Высшей Форме. Окончание
Начало
Мы можем пойти дальше. Заработанные баллы – это сумма заработанных баллов по всем заказам. А использованные – сумма по всем использованиям. Поэтому мы можем хранить баллы лояльности, полученные/использованные в каждом заказе, в классе Order и список заказов в поле класса Customer:
public class Customer : Entity
{
public Order[] Orders { get; private set; }
public LoyaltyPoints Earned
=> Orders.Sum(x => x.PointsEarned);
public LoyaltyPoints Redeemed
=> Orders.Sum(x => x.PointsRedeemed);
public LoyaltyPoints Points
=> Earned - Redeemed;
…
}
Больше нет необходимости увеличивать/уменьшать заработанные баллы, так как они теперь контролируются классом Order.
Однако важно соблюдать баланс. Насколько детальной должна быть исходная информация, зависит от потребностей вашего проекта. В примере выше можно было бы остановиться на двух полях (Earned и Redeemed), если только не появятся новые требования, которые это решение не может удовлетворить.
Баланс здесь заключается между гибкостью с одной стороны, и требованиями к хранилищу, сложностью и производительностью - с другой. Сохранять источник информации - более гибко, но вы заплатите за это дополнительными требованиями к хранилищу, повышенной сложностью и даже снижением производительности:
- Если мы решим предварительно агрегировать данные, мы потеряем в гибкости и потенциально даже теряем ценную информацию (например, с одним полем Points мы уже не можем сказать, сколько всего баллов клиент заработал).
- С другой стороны, мы можем излишне усложнить наше решение, постоянно считая суммы баллов и храня заказы. На практике потребность в дополнительной гибкости может никогда не возникнуть.
Каждый проект отличается и трудно сформулировать общее правило. Можно сказать, что следует хранить источники, пока влияние недостатков от их хранения минимально:
- Для продолжительности фильма нет никакой разницы между сохранением целого числа и строки, так что это не проблема.
- Для баллов лояльности два поля также мало чем отличаются от одного — они оба могут храниться в одной таблице базы данных.
- Сохранение баллов в классе Order может быть уместным, если количество заказов на клиента невелико, и можно сделать Заказ частью агрегата Клиента.
- А если количество заказов на одного клиента велико и нужно сделать Заказ агрегатом, то лучше остановился на решении с двумя полями Earned и Redeemed.
Итого
Храните информацию в ее высшей форме. Другой способ сформулировать это правило: хранить исходник, а не его представление. Однако соблюдайте баланс, следуя этому правилу. Дополнительная гибкость достигается за счёт требований к хранилищу, повышения сложности и снижения производительности.
Источник: https://enterprisecraftsmanship.com/posts/storing-information-in-its-highest-form/