Ayende @ Rahien

It's a girl

Designing a shopping cart

I needed to create a sample shopping cart, and this is what I came up with.

image

Thoughts?

Comments

Diego Jancic
12/07/2008 04:47 AM by
Diego Jancic

There're 3 little things:

1- I've never seen messages in a shopping cart, maybe because I'm not used to buy online or maybe because I might be thinking in something specific.

2- What is ChangeItemQuantity for? Why don't you just change the quantity?

3- Wouldn't be better to change AmountToChangeQuantity to NewAmount or NewQuantity?

Ayende Rahien
12/07/2008 05:12 AM by
Ayende Rahien

1) those are notifications for the user, for things like:

"you bought two milks, if you get a third one, we will give you 15% discount" or "you bought three milks, you get 15% discount on them!"

2) Because I don't want to change the state of the ShoppingCart, this is how you lose track of what is actually going on. This allow you to have a very clear separation of what is the original state of the cart, what is the state after we added that.

3) because this is not the new amount, this is a number that you += with the current one, and you will probably do it many times, because each time you modify the cart, you do it using this approach.

josh
12/07/2008 05:14 AM by
josh

done a few online carts.. i can see using the message info, but I don't see what the ChangeItemQuantity is for.

Rik Hemsley
12/07/2008 05:37 AM by
Rik Hemsley

How does this model cope with prices changing after they have been added to the customer's cart? Changes, especially increases should perhaps not be reflected. I would store the prices at 'add to cart' time.

Nicholas Piasecki
12/07/2008 06:00 AM by
Nicholas Piasecki

I second what Rik said above. You definitely need to preserve price at the time the product was added to the cart, so this is something that the persistence mechanism needs to be aware of.

You might also choose to store a ShipmentMethod here, in that a user could estimate a shipment cost while shopping and have that preserved as they entered checkout. You've already got Discounts here.

And a logical issue just to remember, because I've been burned by it before, is to re-validate the cart upon approaching checkout to ensure that it is still valid (i.e., non-backorderable items are still in stock, etc.).

Ayende Rahien
12/07/2008 06:32 AM by
Ayende Rahien

Rik,

I most places, the price can change while the item is in the shopping cart, only when you actually place the order do you actually set the price.

Rik Hemsley
12/07/2008 06:52 AM by
Rik Hemsley

I believe changing the price after the customer has elected to buy an item would be illegal under UK law, but I'm not qualified in law, so don't take my word for it.

Stuart
12/07/2008 09:31 AM by
Stuart

Is the discount always going to be a percentage? I have seen discounts in some online stores that are a fixed dollar amount.

Damien Guard
12/07/2008 10:11 AM by
Damien Guard

I'm with Diego - neither domain user (store or shopper) thinks of the cart as a set of quantity changes - it's a shopping cart and if they set the value from 5 to 4 they're not thinking -1 and I don't see how this offers any more flexibility. It sounds more likely that it could be a cause of confusion for devs/reporting etc.

I also don't see what ID/token you have for the cart to either associate it with a currently-unknown user (session id) or logged in user (user id).

I would also add an added date or price even though this is just a cart - some people leave carts build up for days and you at least need to let them know the price has changed since they added it.

[)amien

Waheed Sayed
12/07/2008 12:55 PM by
Waheed Sayed

I second Damien and Rik.

But, I didn't get what is the use of ShoppingCartView !!

Jan Limpens
12/07/2008 01:30 PM by
Jan Limpens

What I do usually, is to keep messages out of the cart and have it as simple as possible. Business rules as to whether apply discounts on the item, on the whole cart content, free delivery and so on, usually need a full inspection on the cart, the user etc...

So when I want to show messages, I do a conversion from cart to order and apply all the rules in this conversion. Every applied rule has some kind of semi intelligent message attached to it and saves this message in the line item. That way I have everything in one place and I don't have to constantly sync the cart with reality. I also have the guarantee that what I present the user will later show 1:1 in the purchase.

Maybe your CartView is something similar?

This doesn't take into account the kind of messages like 'if you add x, you'll get y', that clearly belong into the cart domain.

I also do not see the use of the ChangeItemQuantity. I'd rater use a LineItemAdd and let it decide to whether change quantity or add new lines. But this might be a bit up-frontey.

Jelle Hissink
12/07/2008 01:33 PM by
Jelle Hissink

I agree with prior statements however. The name MessagePriority is a bit misleading (as I don't see Discount being a priority). You should rename it to something like MessageType. Or remove the Discount from the enum (as you already have discount classes associated with items).

Regards

RafalG
12/07/2008 01:36 PM by
RafalG
  1. If you need to keep the shopping history, why not use ItemAdded/ItemRemoved records instead of ChangeItemQuantity? It will be more similar to real world.

  2. Message Priority - looks like a kind of logging library. Error/Warning/Notification- is user supposed to see errors in his basket? Discount - that's a different story, as it clearly states the message is about discount. What other messages do you have? ItemUnavailable/OutOfStock, SpecialOffer - and so on. Think about real world.

  3. Discounts. You have two ways of telling customers about discounts - by using the Discount class, or by adding Messages with Priority = Discount. Is there any reason?

    1. In real world we have to pay for the items we buy. Where are the prices?
Stephen
12/07/2008 02:30 PM by
Stephen

I think you should store copies of the products in the cart, the description and price is important.. if this can change between the user adding to the cart and checking out, I think its a little weird..

What about having an immutable cart instead if you wanted to track how the user used the cart? this way your cart itself isn't aware of state changes.. and you can have a CartSession that keeps track of all the carts..

Steve Sheldon
12/07/2008 03:13 PM by
Steve Sheldon

I worked for a major online retailer for short time.

Discounts are where the world is complicated, because they come in all shapes a sizes.

Free shipping if you spend $100

Free shipping on televisions

Free upgrade to 2nd day shipping

10% off if you spend over $100

5% off if you spend over $50

$25 off if you use paypal and order more than $200

Discounts are sometimes stackable.

You need a list of discounts that apply, and a rules engine to process them. Now granted, you are just creating a sample, but in the real world that and the whole notion of adding properties to items so you could easily search for ruby earrings in a silver setting was where all the effort was.

Cassio Tavares
12/07/2008 05:26 PM by
Cassio Tavares

Why do you need to know the original state of the cart? I've never done one but I don't get why this is important.

But if you really need to track changes, why don't you a add a shopping cart into a shopping cart? Every shopping cart could reference the previous shopping cart until you get the first shopping cart.

Something like:

public class ShoppingCart

{

public ShoppingCart PreviousShoppingCart {get; private set;}

...

...


public ShoppingCart Update(Item item, double amount)

{

    ShoppingCart newCart = new ShoppingCart();

    newCart.PreviousCart = this;


    //Handle item and amount changes

    ...

    ...

    return newCart;

}

}

Is it a bad idea?

Frank Quednau
12/07/2008 10:44 PM by
Frank Quednau

Would love it if you could change Precentage to Percentage. Ta.

Roger
12/08/2008 09:20 AM by
Roger

Why are you showing the props and not the methods in the class diagram?

I think it's easier to understand what something does when the representation shows what the entities can do rather/as a complement to it's data. "Domain model vs db scheme".

Justin Davies
12/08/2008 12:38 PM by
Justin Davies

Price changes whilst in the cart are perfectly valid and legal provided that you inform the user when they next view the cart.

Take amazon's UK help page on pricing as an example:

"Confirming Price

Items in your Shopping Basket will always reflect the most recent price displayed on the item's product detail page. Please note that this price may differ from the price shown for the item when you first placed it in your basket. Placing an item in your basket does not reserve the price shown at that time. It is also possible that an item's price may decrease between the time you place it in your basket and the time you purchase it. "

Some people use their carts as a "wish list" and effectively store what they are going to buy in the future - hence the "save for later" functionality many sites add onto their baskets.

Bunter
12/08/2008 01:48 PM by
Bunter

In some countries (like here, Estonia), you have to sell stuff with a price you present it to the customer. Well, cheaper, of course as well but not with higher price. Though e-shops are a bit gray area in that sense.

Andrew
12/09/2008 09:58 AM by
Andrew

Regarding the changing prices of shopping cart items, I'm sure I've seen this in at least two places on UK sites:

  1. while booking airline tickets, your price is never guaranteed until you actually submit credit card details

  2. i've had items in an amazon cart change price such that at checkout, it notified me of the update in price (well, it actually said something to the affect of "this item is no longer available at price X")

Imho, as long as the user is aware of the possibility of the price changing before checkout, that's fine.

In my experience, one often has to commit/kick off a number of external processes/transactions when actually checking out, ones that influence the price or possibly influence the price of items one may buy in future - so fixing the price while shopping can cause race conditions.

Andrew

Comments have been closed on this topic.