Oren Eini

aka Ayende Rahien

Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,575
|
Comments: 51,194

Copyright ©️ Ayende Rahien 2004 — 2025

Privacy Policy · Terms
filter by tags archive
stack view grid view
  • architecture (606) rss
  • bugs (450) rss
  • challanges (123) rss
  • community (377) rss
  • databases (481) rss
  • design (893) rss
  • development (640) rss
  • hibernating-practices (71) rss
  • miscellaneous (592) rss
  • performance (397) rss
  • programming (1085) rss
  • raven (1442) rss
  • ravendb.net (526) rss
  • reviews (184) rss
  • 2025
    • May (7)
    • April (10)
    • March (10)
    • February (7)
    • January (12)
  • 2024
    • December (3)
    • November (2)
    • October (1)
    • September (3)
    • August (5)
    • July (10)
    • June (4)
    • May (6)
    • April (2)
    • March (8)
    • February (2)
    • January (14)
  • 2023
    • December (4)
    • October (4)
    • September (6)
    • August (12)
    • July (5)
    • June (15)
    • May (3)
    • April (11)
    • March (5)
    • February (5)
    • January (8)
  • 2022
    • December (5)
    • November (7)
    • October (7)
    • September (9)
    • August (10)
    • July (15)
    • June (12)
    • May (9)
    • April (14)
    • March (15)
    • February (13)
    • January (16)
  • 2021
    • December (23)
    • November (20)
    • October (16)
    • September (6)
    • August (16)
    • July (11)
    • June (16)
    • May (4)
    • April (10)
    • March (11)
    • February (15)
    • January (14)
  • 2020
    • December (10)
    • November (13)
    • October (15)
    • September (6)
    • August (9)
    • July (9)
    • June (17)
    • May (15)
    • April (14)
    • March (21)
    • February (16)
    • January (13)
  • 2019
    • December (17)
    • November (14)
    • October (16)
    • September (10)
    • August (8)
    • July (16)
    • June (11)
    • May (13)
    • April (18)
    • March (12)
    • February (19)
    • January (23)
  • 2018
    • December (15)
    • November (14)
    • October (19)
    • September (18)
    • August (23)
    • July (20)
    • June (20)
    • May (23)
    • April (15)
    • March (23)
    • February (19)
    • January (23)
  • 2017
    • December (21)
    • November (24)
    • October (22)
    • September (21)
    • August (23)
    • July (21)
    • June (24)
    • May (21)
    • April (21)
    • March (23)
    • February (20)
    • January (23)
  • 2016
    • December (17)
    • November (18)
    • October (22)
    • September (18)
    • August (23)
    • July (22)
    • June (17)
    • May (24)
    • April (16)
    • March (16)
    • February (21)
    • January (21)
  • 2015
    • December (5)
    • November (10)
    • October (9)
    • September (17)
    • August (20)
    • July (17)
    • June (4)
    • May (12)
    • April (9)
    • March (8)
    • February (25)
    • January (17)
  • 2014
    • December (22)
    • November (19)
    • October (21)
    • September (37)
    • August (24)
    • July (23)
    • June (13)
    • May (19)
    • April (24)
    • March (23)
    • February (21)
    • January (24)
  • 2013
    • December (23)
    • November (29)
    • October (27)
    • September (26)
    • August (24)
    • July (24)
    • June (23)
    • May (25)
    • April (26)
    • March (24)
    • February (24)
    • January (21)
  • 2012
    • December (19)
    • November (22)
    • October (27)
    • September (24)
    • August (30)
    • July (23)
    • June (25)
    • May (23)
    • April (25)
    • March (25)
    • February (28)
    • January (24)
  • 2011
    • December (17)
    • November (14)
    • October (24)
    • September (28)
    • August (27)
    • July (30)
    • June (19)
    • May (16)
    • April (30)
    • March (23)
    • February (11)
    • January (26)
  • 2010
    • December (29)
    • November (28)
    • October (35)
    • September (33)
    • August (44)
    • July (17)
    • June (20)
    • May (53)
    • April (29)
    • March (35)
    • February (33)
    • January (36)
  • 2009
    • December (37)
    • November (35)
    • October (53)
    • September (60)
    • August (66)
    • July (29)
    • June (24)
    • May (52)
    • April (63)
    • March (35)
    • February (53)
    • January (50)
  • 2008
    • December (58)
    • November (65)
    • October (46)
    • September (48)
    • August (96)
    • July (87)
    • June (45)
    • May (51)
    • April (52)
    • March (70)
    • February (43)
    • January (49)
  • 2007
    • December (100)
    • November (52)
    • October (109)
    • September (68)
    • August (80)
    • July (56)
    • June (150)
    • May (115)
    • April (73)
    • March (124)
    • February (102)
    • January (68)
  • 2006
    • December (95)
    • November (53)
    • October (120)
    • September (57)
    • August (88)
    • July (54)
    • June (103)
    • May (89)
    • April (84)
    • March (143)
    • February (78)
    • January (64)
  • 2005
    • December (70)
    • November (97)
    • October (91)
    • September (61)
    • August (74)
    • July (92)
    • June (100)
    • May (53)
    • April (42)
    • March (41)
    • February (84)
    • January (31)
  • 2004
    • December (49)
    • November (26)
    • October (26)
    • September (6)
    • April (10)
Couchbase vs RavenDB Performance at Rakuten Kobo Whitepaper
  previous post next post  
Dec 07 2008

Designing a shopping cart

time to read 1 min | 27 words

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

image

Thoughts?

Tweet Share Share 21 comments
Tags:
  • Design

  previous post next post  

Comments

Diego Jancic
07 Dec 2008
04:47 AM
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
07 Dec 2008
05:12 AM
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
07 Dec 2008
05:14 AM
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
07 Dec 2008
05:37 AM
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
07 Dec 2008
06:00 AM
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
07 Dec 2008
06:32 AM
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
07 Dec 2008
06:52 AM
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
07 Dec 2008
09:31 AM
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
07 Dec 2008
10:11 AM
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
07 Dec 2008
12:55 PM
Waheed Sayed

I second Damien and Rik.

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

Jan Limpens
07 Dec 2008
13:30 PM
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
07 Dec 2008
13:33 PM
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
07 Dec 2008
13:36 PM
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
07 Dec 2008
14:30 PM
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
07 Dec 2008
15:13 PM
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
07 Dec 2008
17:26 PM
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
07 Dec 2008
22:44 PM
Frank Quednau

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

Roger
08 Dec 2008
09:20 AM
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
08 Dec 2008
12:38 PM
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
08 Dec 2008
13:48 PM
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
09 Dec 2008
09:58 AM
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

Comment preview

Comments have been closed on this topic.

Markdown formatting

ESC to close

Markdown turns plain text formatting into fancy HTML formatting.

Phrase Emphasis

*italic*   **bold**
_italic_   __bold__

Links

Inline:

An [example](http://url.com/ "Title")

Reference-style labels (titles are optional):

An [example][id]. Then, anywhere
else in the doc, define the link:
  [id]: http://example.com/  "Title"

Images

Inline (titles are optional):

![alt text](/path/img.jpg "Title")

Reference-style:

![alt text][id]
[id]: /url/to/img.jpg "Title"

Headers

Setext-style:

Header 1
========
Header 2
--------

atx-style (closing #'s are optional):

# Header 1 #
## Header 2 ##
###### Header 6

Lists

Ordered, without paragraphs:

1.  Foo
2.  Bar

Unordered, with paragraphs:

*   A list item.
    With multiple paragraphs.
*   Bar

You can nest them:

*   Abacus
    * answer
*   Bubbles
    1.  bunk
    2.  bupkis
        * BELITTLER
    3. burper
*   Cunning

Blockquotes

> Email-style angle brackets
> are used for blockquotes.
> > And, they can be nested.
> #### Headers in blockquotes
> 
> * You can quote a list.
> * Etc.

Horizontal Rules

Three or more dashes or asterisks:

---
* * *
- - - - 

Manual Line Breaks

End a line with two or more spaces:

Roses are red,   
Violets are blue.

Fenced Code Blocks

Code blocks delimited by 3 or more backticks or tildas:

```
This is a preformatted
code block
```

Header IDs

Set the id of headings with {#<id>} at end of heading line:

## My Heading {#myheading}

Tables

Fruit    |Color
---------|----------
Apples   |Red
Pears	 |Green
Bananas  |Yellow

Definition Lists

Term 1
: Definition 1
Term 2
: Definition 2

Footnotes

Body text with a footnote [^1]
[^1]: Footnote text here

Abbreviations

MDD <- will have title
*[MDD]: MarkdownDeep

 

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. RavenDB News (2):
    02 May 2025 - May 2025
  2. Recording (15):
    30 Apr 2025 - Practical AI Integration with RavenDB
  3. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
  4. RavenDB (13):
    02 Apr 2025 - .NET Aspire integration
  5. RavenDB 7.1 (6):
    18 Mar 2025 - One IO Ring to rule them all
View all series

RECENT COMMENTS

  • Scooletz, Yes, we look at other stuff. Most of those are _not_ allowing you to build themselves incrementally nor are they...
    By Oren Eini on Scaling HNSW in RavenDB: Optimizing for inadequate hardware
  • Have you considered other approaches, DiskSpan, Spann etc.? HNSW, as far as I know, is terrible in regards to updates and det...
    By Scooletz on Scaling HNSW in RavenDB: Optimizing for inadequate hardware
  • Steve, The check is for _equality_ - if the current version matches the value in the versions array. When the `_version` ...
    By Oren Eini on Optimizing the cost of clearing a set
  • I'm not following that part, the first 65K times (until ushort.MaxValue) it will be smaller so you'll enter the if/return, bu...
    By Steve on Optimizing the cost of clearing a set
  • Steve, No, I don't need to. It is going to wrap around anyway, after all
    By Oren Eini on Optimizing the cost of clearing a set

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}