Designing Microservices

January 05, 2021

A sunset landscape Photo by Marek Piwnicki on Unsplash

Problem Statement

Consider that you have to build a checkout system. The microservice should have the following functionalities

  1. API to create an empty cart and associate it with a user
  2. API to add items to the cart
  3. API to delete items from the cart
  4. API to empty the cart

Part 1 - Based on the requirements given, write down functional requirements for the service. Take assumptions and write down non-functional requirements for the service

Part 2 - Break down decisions that have to be taken to build this service. Divide them into high cost and low-cost decisions

Part 3 - Use domain-driven design and relating to real-world domains to document how would a user interact with the service. Document what additional conditions happen in the real world that is not given as part of the requirements.

Part 4 - Write down what business metrics and system metrics should be generated by the system

Solution

The Cart service will be a RESTful service and our consumers should be able to access the service via the following APIs. There are some assumptions that we make while creating the design for this microservice.

Part 1 - Based on the requirements given, write down functional requirements for the service. Take assumptions and write down non-functional requirements for the service

Assumptions:

  1. There will also be a few entities like a User that we will be using during the course of designing this microservice. We are assuming that these entities exist and they will also be available via an API.

  2. The Cart microservice should be a part of a bigger Checkout system which will include the Cart microservice communicating in tandem with the Payments microservice. Certain assumptions will be made about the Payments microservice.

  3. We are assuming the existence of another service, namely the Coupon microservice which will interact with the Cart microservice to tally and calculate the total price and the discount amount. We assume that the Coupon microservice is functional for the case of this exercise.

TLDR;

Assume the existence of the following entities:

  1. User - Has a userId attribute
  2. Cart - Consists of CartItems and is associated to a user

Assume that the following microservices are functional:

  1. Coupons Microservice - To check the validity of coupons
  2. Payments Microservice - To make online payments

Functional requirements for the Cart Service:

  1. API - Given a user, create an empty cart and associate it with a user
  2. API - Given a user, add an item to a cart
  3. API - Given a user, delete the item from the cart, if it exists in the cart
  4. API - Empty the cart
  5. Entity - User - We assume the entity exists and there's a unique id userId associated with a user
  6. Entity - CartItem - A representation of the item when inside a cart. Will have a unique item id called itemId and a quantity.
  7. API - Given a cart, fetch the total amount of the items in the cart
  8. API - Given a cart, apply a coupon from the user

Non-Functional requirements

  1. Logging
  2. Load Balancer/Proxy
  3. API Protocol
  4. Tracing library

Part 2 - Break down decisions that have to be taken to build this service. Divide them into high cost and low-cost decisions

The decisions to be taken for the above functional and non-functional requirements are grouped below:

Low Cost Decisions:

  1. Logging Library
  2. Tracing Library
  3. Caching - Perhaps not needed for the given API

High Cost Decisions

  1. Load Balancer
  2. API Protocol
  3. Logging Infrastructure

Part 3 - Use domain-driven design and relating to real-world domains to document how would a user interact with the service. Document what additional conditions happen in the real world that is not given as part of the requirements.

Real-life physical carts have wheels, but we don't need them here. However, we do need the capability for the cart to hold items, the functionality to add and remove items and reflect the total cost of the items in the cart.

Following are the API interactions that a user would do with this cart:

  1. Get a cart for a particular user If a cart exists, then it's data representation can be fetched for a user. If a cart does not exist for a user, then we can create a cart object and send it off.

  2. Add an item Given a cart, the user should be able to add an item and the quantity to the cart.

  3. Remove an item Given a cart with some item, the user should be able to remove that item from the cart either completely or by decreasing the quantity of that item. Modelling against the real world, when the user removes the item completely from the cart by decreasing it's quantity to zero, then the item should be removed completely from the object representation of the cart.

  4. Empty the cart The user can abandon a full shopping cart in the store in the physical world, similarly we give the user an option to "abandon" the cart by giving them the option to empty the cart. We remove all items from the representation of the cart.

Part 4 - Write down what business metrics and system metrics should be generated by the system

We care about the following system metrics:

  1. Performance & Latency of each API
  2. Disk usage and latency caused by logging systems
  3. CPU, Memory, Disk space of the server
  4. Error and success rates of each API
  5. Resource usage
  6. Processes

For business metrics, these are the line items:

  1. Analytics of the items, which items are often added to a cart and which are removed.
  2. How many times the Empty cart functionality is used.
  3. How many times a user goes into the checkout flow from the cart.
Donate