One-Call Checkout Across Five Subsystems
Every client controller independently instantiates and choreographs five separate subsystems (`CartValidator`, `InventoryLock`, `PaymentGateway`, `RiderDispatcher`, `NotificationBus`). When the mobile team forgot to release inventory locks upon payment failure, restaurant stock leaked for hours. Duplicating 30+ lines of fragile orchestration and rollback glue across callers creates catastrophic reliability bugs.
The mobile controller developer handled payment failure but omitted inventory.releaseLock(lockId). Because orchestration is duplicated, human errors cause critical resource leaks.
Provide a unified, simplified interface to a complex set of interfaces in a subsystem, making the subsystem easier to use without hiding its underlying classes.
We introduce CheckoutFacade which aggregates CartValidator, InventoryLock, PaymentGateway, RiderDispatcher, and NotificationBus. It exposes a single method: CheckoutResult placeOrder(const OrderRequest&). The facade enforces the exact sequence (validate β lock β charge β dispatch β notify) and guarantees automatic compensation rollback if any intermediate step fails.
Across Sprints 1 through 8 (A1βA8), we built modular, robust domain subsystems: interchangeable payment strategies, SRP-compliant pricing and repositories, observer event buses, lifecycle state machines, factory fulfillment dispatchers, DIP test doubles, ISP role interfaces, and 3rd-party vendor adapters.
We need to expose a simple, unified order placement entry point (CheckoutFacade / PlaceOrderFacade) for our Mobile App, Web App, and Voice Assistant controllers, coordinating all checkout subsystems in exact sequence.
Every client controller independently instantiates and choreographs five separate subsystems (CartValidator, InventoryLock, PaymentGateway, RiderDispatcher, NotificationBus). When the mobile team forgot to release inventory locks upon payment failure, restaurant stock leaked for hours. Duplicating 30+ lines of fragile orchestration and rollback glue across callers creates catastrophic reliability bugs.
The Facade pattern (CheckoutFacade / PlaceOrderFacade) bundles all subsystems behind a single clean placeOrder(request) method with guaranteed automated rollback on failure, completing our end-to-end Food Delivery architecture. With SOLID principles and core GoF patterns mastered on a consumer platform, you are now ready for Story B (Low-Latency Trading Engine)!
The product ticket
Placing an order requires orchestrating 5 separate subsystems in exact sequential order: CartValidator, InventoryLock, PaymentGateway, RiderDispatcher, and NotificationBus. Currently, our Mobile API, Web API, and Alexa Voice Assistant controllers each call all 5 subsystems directly. Yesterday, the Mobile controller suffered a major incident: when payment failed, it forgot to call InventoryLock::releaseLock(), leaving restaurant inventory locked for hours and preventing customers from ordering.
- β’
Provide a unified
CheckoutFacadewith a simpleplaceOrder(OrderRequest)entry point. - β’
Encapsulate the exact execution pipeline and compensation rollback: if payment fails, unlock reserved inventory; if rider dispatch fails, refund payment and unlock inventory.
- β’
Eliminate duplicated subsystem wiring and fragile error handling across mobile, web, and voice controllers.
Subsystems must remain independently accessible for specialised non-checkout operations (such as warehouse stock audits or standalone customer notifications) without being hidden inside private monolithic classes.
Step 1 β The naive code & why it breaks
Every client controller independently instantiates and orchestrates all 5 subsystems, duplicating glue code and frequently forgetting rollback steps on failure.
#include <format>
#include <print>
#include <string>
#include <unordered_set>
struct OrderRequest {
std::string orderId;
std::string customerId;
std::string restaurantId;
std::string itemName;
int amountRupees;
};
// 1. Cart Validator Subsystem
class CartValidator {
public:
bool validate(const OrderRequest& req) {
if (req.amountRupees <= 0 || req.itemName.empty()) {
std::println("[CartValidator] Invalid order request: {}", req.orderId);
return false;
}
std::println("[CartValidator] Cart valid for order {}", req.orderId);
return true;
}
};
// 2. Inventory Lock Subsystem
class InventoryLock {
std::unordered_set<std::string> activeLocks_;
int lockCounter_{100};
public:
std::string acquireLock(const std::string& restaurantId, const std::string& item) {
std::string lockId = std::format("LOCK_{}_{}", restaurantId, ++lockCounter_);
activeLocks_.insert(lockId);
std::println("[InventoryLock] Acquired {} for item '{}' (Active locks: {})",
lockId, item, activeLocks_.size());
return lockId;
}
void releaseLock(const std::string& lockId) {
activeLocks_.erase(lockId);
std::println("[InventoryLock] Released {} (Active locks: {})", lockId, activeLocks_.size());
}
void commitLock(const std::string& lockId) {
activeLocks_.erase(lockId);
std::println("[InventoryLock] Committed {} permanently (Active locks: {})", lockId, activeLocks_.size());
}
[[nodiscard]] size_t activeLockCount() const { return activeLocks_.size(); }
};
// 3. Payment Gateway Subsystem
struct PaymentResult {
bool success;
std::string txId;
};
class PaymentGateway {
public:
PaymentResult charge(const std::string& customerId, int amountRupees, bool shouldFail = false) {
if (shouldFail) {
std::println("[PaymentGateway] Declined payment of Rs.{} for {}", amountRupees, customerId);
return {false, ""};
}
std::string txId = std::format("TXN_{}", amountRupees * 7);
std::println("[PaymentGateway] Charged Rs.{} to {} (Tx: {})", amountRupees, customerId, txId);
return {true, txId};
}
};
// 4. Rider Dispatcher Subsystem
class RiderDispatcher {
public:
std::string dispatchRider(const std::string& restaurantId) {
std::string riderId = "RIDER_42";
std::println("[RiderDispatcher] Assigned {} for pickup at {}", riderId, restaurantId);
return riderId;
}
};
// 5. Notification Bus Subsystem
class NotificationBus {
public:
void notify(const std::string& channel, const std::string& message) {
std::println("[NotificationBus:{}] {}", channel, message);
}
};
// Naive: MobileController juggles all 5 subsystems by hand and forgets rollback!
class NaiveMobileOrderController {
CartValidator validator_;
InventoryLock inventory_;
PaymentGateway payment_;
RiderDispatcher dispatcher_;
NotificationBus notifications_;
public:
void handleMobileCheckout(const OrderRequest& req, bool forcePaymentFailure) {
std::println("--- Naive Mobile Checkout Initiated ---");
if (!validator_.validate(req)) return;
std::string lockId = inventory_.acquireLock(req.restaurantId, req.itemName);
auto pay = payment_.charge(req.customerId, req.amountRupees, forcePaymentFailure);
if (!pay.success) {
std::println("[NaiveMobileController] Payment failed! Returning error to user.");
// BUG: Developer forgot inventory_.releaseLock(lockId)!
// The item remains locked indefinitely, blocking other customers!
return;
}
std::string riderId = dispatcher_.dispatchRider(req.restaurantId);
inventory_.commitLock(lockId);
notifications_.notify("Customer", "Order placed successfully!");
}
[[nodiscard]] size_t leakedLocks() const { return inventory_.activeLockCount(); }
};
int main() {
NaiveMobileOrderController mobileController;
OrderRequest req{"ORD-801", "cust_99", "REST_MUM_01", "Tandoori Chicken", 480};
// Simulate payment failure where naive controller forgets rollback
mobileController.handleMobileCheckout(req, true);
std::println("\n[ALERT] Leaked active locks in inventory subsystem: {}",
mobileController.leakedLocks());
return 0;
}The mobile controller developer handled payment failure but omitted inventory.releaseLock(lockId). Because orchestration is duplicated, human errors cause critical resource leaks.
Mobile, web, and voice controllers all implement the exact same 5-step choreography. Any change to subsystem signatures requires updating every caller.
Every client controller directly depends on 5 separate classes. Upgrading payment or inventory APIs forces widespread regressions across client adapters.
Step 2 β The fix: Facade
Provide a unified, simplified interface to a complex set of interfaces in a subsystem, making the subsystem easier to use without hiding its underlying classes.
We introduce CheckoutFacade which aggregates CartValidator, InventoryLock, PaymentGateway, RiderDispatcher, and NotificationBus. It exposes a single method: CheckoutResult placeOrder(const OrderRequest&). The facade enforces the exact sequence (validate β lock β charge β dispatch β notify) and guarantees automatic compensation rollback if any intermediate step fails.
CheckoutFacade β coordinates the 5 checkout subsystems, implements rollback logic on failures, and provides a clean placeOrder() entry point.
CartValidator, InventoryLock, PaymentGateway, RiderDispatcher, NotificationBus β handle focused domain tasks and remain directly usable.
MobileController, WebController, VoiceAssistant β invoke only CheckoutFacade::placeOrder() without knowing subsystem details.
Unlock Full UML Diagram & C++23 Solution
The interactive UML architecture diagrams, refactored C++23 code, real-world extensions, and interview Q&A are part of Brute2Best Pro. All 7 foundation chapters are 100% free.
First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.