Placing Feature Flags in an E‑commerce Backend: Deciding Where Free Shipping Logic Belongs
This article examines how to locate the free‑shipping feature‑flag decision in an e‑commerce system, arguing that the decision should be made at the web‑layer where user context is available and then passed to the checkout service, keeping each service focused on its core responsibilities.
Suppose we have an e‑commerce site and want to try a new idea: when a user's new order total exceeds 50 CNY, we offer the customer free shipping.
We want to manage this feature using a feature‑flag system, and the first obvious question is where in the code we should add this flag.
Assume the backend architecture of the e‑commerce site is as shown below, where all user interactions go through a Web service.
When a user finishes the shopping cart and proceeds to checkout, the Web application sends a request to the checkout service to create a new bill. The checkout service performs this operation and returns checkout information to the Web application.
The checkout service also includes detailed shipping‑cost information (the site only calculates shipping cost after the user completes the order and checks out).
Because the checkout service calculates shipping cost, the flag decision for “free shipping” appears to belong in that service, as illustrated below.
However, is this really the best place for the decision? If we only want to test the free‑shipping service internally (an example of the virtual UAT technique discussed earlier), we need to consider which type of user is requesting checkout. User identity must be part of the runtime context to make the correct flag decision. Currently, the checkout service knows nothing about the user; its sole responsibility is to create and manage the checkout.
One solution is to have the Web application pass the necessary user information to the checkout service via runtime context, telling it which user is requesting checkout. This allows the checkout service to make the correct flag decision locally.
Using this approach forces the checkout service to understand the concept of a “user,” which may exceed its intended scope. We prefer the checkout service to focus solely on creating and managing checkout data.
Conversely, the Web application already has full knowledge of the user and the context of the checkout request, making it better suited to decide whether the user should receive free shipping.
Now, each time a user starts checkout, the Web application uses the feature‑flag system to decide if the user qualifies for free shipping, and passes this decision as an extra parameter when requesting bill creation from the checkout service.
Note that the checkout service still retains responsibility for verifying the free‑shipping condition itself: whether the total order amount exceeds 50 CNY.
By doing this, we avoid expanding the boundaries of multiple services merely to support a flag decision, and we keep the underlying business logic for the feature in the appropriate service.
Primary Rule for Flag Placement
From this example we can extract a general rule: place the flag decision as close as possible to the business logic that drives the flag, while preserving enough runtime context to make the decision.
This ensures the flag decision is encapsulated and prevents every part of the codebase from needing to understand concepts such as user, account, or product, which often drive flag decisions.
Applying this rule can be an art of balance. When an operation request reaches the edge of our system, we usually have most of the context needed for that operation.
However, in modern systems the core business logic is often split into many small services. Therefore, we need to make the flag decision at the edge (the web layer) and then propagate that decision to downstream API calls that satisfy the request.
Continuous Delivery 2.0
Tech and case studies on organizational management, team management, and engineering efficiency
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.