2

We have legacy app which keeps state of a cart in local storage on a Frontend (this decision was made long time ago by other devs). The cart is cleared from local storage after 2 hours if it is not completed.

Now we are moving towards microservices, and one of new microservice is 'Discount Coupons'. Customer can apply coupon which will reduce final price he/she needs to pay. In order to have a discount, customer needs to apply a coupon (click 'apply'). There can be only 1 coupon applied per cart.

Customer can go back and forth the cart screen, and if coupon was applied it should appear as applied (keep in mind cart is legacy part, while Coupons is new microservice).

There are 2 contradiction approaches we struggle to agree on:

approach 1: keep information if Coupon is applied in Backend, in Coupons table, in column is_applied or applied_on_date. approach 2: keep which coupon (null if none) was applied in current Frontend implementation of a cart state.

Disadvantage of approach 1 is that the final state of a cart will be distributed in 2 places (FE local storage and BE Coupons table). What is more, there is a risk of inconsistency, because in DB more than 1 customer's coupon can be in 'applied' state (unless we execute logic to prevent it on every change). Also we need to keep in sync FE local cart state with BE coupons state, which will make DiscountCoupons microservice stateful (while there is an opinion that stateless is preferable).

Disadvantage of approach 2 is that every time coupons are GET from DiscountCoupons API (about 10-20 items in single GET request) they need to be compared against local FE cart state to determine which of them (if any) is in applied state.

Here go my questions:

  1. Is 'distributed state' an anti-pattern or is it perfectly fine? I have read a lot about distributed transactions (e.g. to avoid them, and if not possible, to do saga pattern), but I'm struggle to find any articles about distributed state.
  2. Should a coupon know that it is applied, or should cart know that it has coupon applied on it?

1 Answer 1

5

I would not have the applied state associated with a coupon.

You need to check the coupons validity at two points.

  1. When the customer 'applies' it to their basket.

    This stops the customer adding used/invalid tokens

  2. When the customer purchases the basket.

    This stops the token being used twice

After the coupon has been actually used, it is invalidated.

So, if I as a sneaky customer get my coupon, open up two browsers and try to use it twice I can add it to both baskets, but after purchasing the first the second will throw an error: "sorry this coupon has already been used"

If I as a normal customer apply a coupon and then walk away, but then place the order again on a separate machine, say my mobile. The abandoned basket doesn't stop me adding the coupon and completing my purchase.

4
  • Thanks for this answer. Do you have any thoughts on that question: "Is 'distributed state' an anti-pattern or is it perfectly fine?" ? Sep 9, 2020 at 6:22
  • having the cart state on the client is a good thing. I don't think I would call it 'distributed state' though
    – Ewan
    Sep 9, 2020 at 6:40
  • If it is kept only in the client, there is no distributed state. My question was if approach 1: "keep information if Coupon is applied in Backend, in Coupons table" than this part would be on server, while remaining on client. Wouldn't it be 'distributed state' then? Sep 9, 2020 at 9:24
  • not really. I would say "distributed state" means that you have your data spread over multiple database instances or something. You have local state, and shouldn't replicate it on the server
    – Ewan
    Sep 9, 2020 at 13:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.