Bird
Raised Fist0
LLDsystem_design~7 mins

Payment handling in LLD - System Design Guide

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Problem Statement
Handling payments directly without proper abstraction leads to tightly coupled code that is hard to maintain and extend. If payment logic is scattered, adding new payment methods or handling failures becomes error-prone and slows down development.
Solution
Payment handling uses a strategy pattern to separate payment methods into interchangeable components. This allows the system to select and execute different payment processes dynamically without changing the core logic. It also centralizes error handling and logging for payments.
Architecture
PaymentClient
PaymentProcessor
CreditCardPay

This diagram shows a PaymentClient using a PaymentProcessor interface to delegate payment execution to different payment method implementations like CreditCardPay, PayPalPay, and CryptoPay.

Trade-offs
✓ Pros
Enables easy addition of new payment methods without changing existing code.
Improves code maintainability by isolating payment logic.
Centralizes error handling and logging for all payment types.
Supports dynamic selection of payment methods at runtime.
✗ Cons
Introduces additional abstraction layers which may increase initial complexity.
Requires careful interface design to cover all payment method needs.
May add slight performance overhead due to indirection.
Use when your system supports multiple payment methods or expects to add more in the future, especially if payment logic is complex or needs to be isolated for security and compliance.
Avoid if your system only supports a single, simple payment method with minimal logic, as the abstraction overhead may not justify the benefits.
Real World Examples
Stripe
Stripe uses a modular payment processing system to support many payment methods like cards, wallets, and bank debits, allowing seamless integration and extension.
PayPal
PayPal abstracts payment methods to handle credit cards, PayPal balance, and other funding sources uniformly, simplifying transaction management.
Uber
Uber uses a payment handling system that dynamically selects payment methods based on user preferences and region, ensuring smooth ride payments.
Code Example
The before code mixes payment logic in one method, making it hard to add new methods. The after code uses the strategy pattern to separate payment methods into classes implementing a common interface. PaymentProcessor delegates payment to the selected strategy, enabling easy extension and cleaner code.
LLD
### Before: tightly coupled payment handling
class PaymentHandler:
    def pay(self, method, amount):
        if method == 'credit_card':
            # process credit card payment
            print(f"Processing credit card payment of {amount}")
        elif method == 'paypal':
            # process paypal payment
            print(f"Processing PayPal payment of {amount}")
        else:
            raise ValueError("Unsupported payment method")

handler = PaymentHandler()
handler.pay('credit_card', 100)


### After: strategy pattern for payment handling
from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

class CreditCardPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Processing credit card payment of {amount}")

class PayPalPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Processing PayPal payment of {amount}")

class PaymentProcessor:
    def __init__(self, strategy: PaymentStrategy):
        self.strategy = strategy

    def pay(self, amount):
        self.strategy.pay(amount)

processor = PaymentProcessor(CreditCardPayment())
processor.pay(100)

processor.strategy = PayPalPayment()
processor.pay(200)
OutputSuccess
Alternatives
Monolithic Payment Logic
All payment methods are handled in a single code block without abstraction.
Use when: Choose when the system only supports one payment method and simplicity is paramount.
Event-Driven Payment Processing
Payments are processed asynchronously via events and queues rather than direct method calls.
Use when: Choose when high scalability and decoupling of payment steps are required.
Summary
Payment handling separates payment logic to manage multiple payment methods cleanly.
Using the strategy pattern allows dynamic selection and easy extension of payment methods.
This approach improves maintainability, error handling, and supports future growth.

Practice

(1/5)
1. What is the primary purpose of a payment handling system in software design?
easy
A. To store user profile pictures
B. To securely process and record financial transactions
C. To manage user login and authentication
D. To display product information to users

Solution

  1. Step 1: Understand the role of payment handling

    Payment handling systems focus on managing money transfers safely and reliably.
  2. Step 2: Identify the core function

    The core function is to process payments securely and keep records of transactions.
  3. Final Answer:

    To securely process and record financial transactions -> Option B
  4. Quick Check:

    Payment handling = Secure transaction processing [OK]
Hint: Payment handling means safe money transfer and record keeping [OK]
Common Mistakes:
  • Confusing payment handling with user authentication
  • Thinking it manages product display
  • Assuming it stores user media files
2. Which of the following is the correct sequence of steps in a typical payment processing flow?
easy
A. Notify user -> Record transaction -> Process payment -> Validate payment details
B. Record transaction -> Validate payment details -> Notify user -> Process payment
C. Validate payment details -> Process payment -> Record transaction -> Notify user
D. Process payment -> Notify user -> Validate payment details -> Record transaction

Solution

  1. Step 1: Identify logical payment flow order

    First, payment details must be validated to ensure correctness.
  2. Step 2: Follow with processing, recording, and notifying

    After validation, payment is processed, transaction recorded, then user notified.
  3. Final Answer:

    Validate payment details -> Process payment -> Record transaction -> Notify user -> Option C
  4. Quick Check:

    Payment flow = Validate -> Process -> Record -> Notify [OK]
Hint: Payment flows from validation to processing, then record and notify [OK]
Common Mistakes:
  • Not validating before processing
  • Not recording transaction before notifying
  • Mixing notification before processing
3. Consider this simplified payment processing pseudocode:
def process_payment(amount, card_info):
    if not validate_card(card_info):
        return "Invalid card"
    if amount <= 0:
        return "Invalid amount"
    if not charge_card(card_info, amount):
        return "Charge failed"
    record_transaction(card_info, amount)
    return "Payment successful"

What will be the output of process_payment(100, 'expired_card') if validate_card returns False for expired cards?
medium
A. "Invalid card"
B. "Charge failed"
C. "Payment successful"
D. "Invalid amount"

Solution

  1. Step 1: Check card validation result

    Since validate_card returns False for expired cards, the first if condition triggers.
  2. Step 2: Return error message immediately

    The function returns "Invalid card" without further processing.
  3. Final Answer:

    "Invalid card" -> Option A
  4. Quick Check:

    Expired card -> validate_card = False -> "Invalid card" [OK]
Hint: If validation fails, function returns error immediately [OK]
Common Mistakes:
  • Assuming charge_card runs despite invalid card
  • Confusing invalid amount with invalid card
  • Expecting success despite validation failure
4. A payment system logs duplicate transactions when retrying failed payments. Which design fix will best prevent this issue?
medium
A. Use unique transaction IDs and check before recording
B. Increase payment timeout duration
C. Remove transaction logging entirely
D. Allow multiple retries without checks

Solution

  1. Step 1: Identify cause of duplicate logs

    Retries cause repeated transaction records without uniqueness checks.
  2. Step 2: Implement unique transaction IDs and check

    Assign unique IDs and verify before logging to avoid duplicates.
  3. Final Answer:

    Use unique transaction IDs and check before recording -> Option A
  4. Quick Check:

    Unique IDs prevent duplicate transaction logs [OK]
Hint: Unique IDs stop duplicate transaction records [OK]
Common Mistakes:
  • Ignoring duplicate checks on retries
  • Removing logging which loses audit trail
  • Increasing timeout doesn't fix duplicates
5. You are designing a payment system that must handle 10,000 transactions per second with minimal latency and high reliability. Which architectural approach best supports this requirement?
hard
A. Store all payment requests in a single database table and process sequentially
B. Process all payments synchronously on a single server to ensure order
C. Use client-side scripts to process payments directly without server validation
D. Use a distributed message queue to process payments asynchronously with multiple worker nodes

Solution

  1. Step 1: Analyze scalability and latency needs

    Handling 10,000 TPS requires distributing load and minimizing blocking.
  2. Step 2: Choose asynchronous distributed processing

    Using a message queue with multiple workers allows parallel processing and reliability.
  3. Step 3: Eliminate options causing bottlenecks or insecurity

    Single server or sequential DB processing causes bottlenecks; client-side processing lacks security.
  4. Final Answer:

    Use a distributed message queue to process payments asynchronously with multiple worker nodes -> Option D
  5. Quick Check:

    High TPS + low latency = distributed async processing [OK]
Hint: Distribute load with async workers for high TPS [OK]
Common Mistakes:
  • Using single server causing bottlenecks
  • Sequential DB processing slowing throughput
  • Relying on client-side payment processing