При разработке интернет-магазина почти любого рода вам обязательно придется столкнуться с придумыванием структур "корзины" и "заказа". И здесь можно попасться на одну заманчивую обманку, от которой я хочу веб-программистов предостеречь.
Дело в том, что корзина и заказ очень похожи по сути: и то, и другое хранит описание того, что клиент хочет купить в магазине. То есть, по идее, заказ - это та же корзина, но уже с подтверждением от клиента, что он закончил ее набирать и хочет расплатиться.
Сталкиваясь с таким сходством, нормальный программист, который не хочет плодить сущности, скорее всего захочет описывать корзину и заказ в одной и той же структуре, просто добавив признак типа "не оформлен/оформлен". И действительно, мне приходилось с такой моделью и работать, и в своем текущем проекте я тоже думал сделать именно так.
Но вспомнив прошлый опыт и подойдя к вопросу критическим, я понял, что так делать не нужно. Лучше держать их в разных сущностях. И вот почему.
Лишние поля
Cостояние оформленности, на практике, оказывается совсем не единственным отличием корзины и заказы. Корзине нужны атрибуты, имеющие смысл только до оформления, связанные, например, с отображением ее на сайте, какая-нибудь текущая сортировка, признак открытости/закрытости и связь с клиентской сессией. Заказ тоже после оформления обрастает своими деталями типа времени оформления, привязки к конкретному зарегистрированному клиенту и системой статусов.
Это означает, что табличка, хранящая обобщенную "заказ-корзину", обрастает кучей полей, одни из которых не нужны в одних местах кода, другие - в других. Это обычно не добавляет читаемости, а следовательно ведет к разным глупым ошибкам.
Валидация
Легко может быть, что поля заказа до оформления допустимо держать незаполенными, а после оформления они должны быть обязательно. Если это поля одной таблицы, то такой constraint не поставишь: поле должно быть либо NULL
, либо NOT NULL
.
Такую валидацию можно сделать триггером, но это ухудшает поддерживаемость кода, так как валидация становится чем-то менее предсказуемым и размазывается по разным неочевидным местам.
И вообще, все (оба!) вменяемые базоданщики, с которыми мне приходилось работать, отзывались о триггерах агрессивно в духе "это зло!" :-)
Усложнение запросов
При работе с табличкой "заказов-корзин" вам всегда придется включать в SQL-запросы условие, показывающее, с какой частью таблицы вы хотите работать (and 'оформлен'=1
). Ситуацию же, когда заказы и корзины нужны одновременно, мне представить трудно.
Большая табличка
Корзина - временное образование, она существует или пока не превратиться в заказ, или пока не протухнет. Заказы же, напротив, предполагается хранить вечно. Это означает, что табличка это будет все время расти. А значит, в тех случаях, когда вы будете обращаться к этой табличке за корзинами, вы будете заставлять базу перемалывать большой объем данных, который точно не понадобится.
Конечно, на признак оформленности можно поставить индекс, чтобы выборка по нему происходила очень быстро. Но это, насколько я понимаю, не спасает в случаях, когда выборка идет с соединением табличек. Тогда, по идее, ваша распространенная простая и быстрая СУБД сначала объединит все данные в большо-о-ое декартово произведение, а потом начнет выбирать и отсекать. Что медленнее, чем если бы этих данных просто не было.
Впрочем, врать не буду, последнее - просто умозрительный вывод, на практике я это не проверял. Базоданщики, поправьте меня, если я дурь написал :-).
Удачного проектирования!
Комментарии: 6
гхм =)
IMHO корзина, это всего лишь "табличная часть" заказа
а заказ на нее просто ссылается
IMHO корзины нужны ВСЕ =)
как еще вы будете строить внутреннюю статистику по популярности и отслеживать конверсию "положил в корзину" ->