Bird
Raised Fist0
LLDsystem_design~25 mins

Notification on state change in LLD - System Design Exercise

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
Design: Notification on State Change System
Design covers detection of state changes, notification dispatch, subscription management, and audit logging. Out of scope are the internal state management of entities and third-party notification service implementations.
Functional Requirements
FR1: Detect changes in the state of an entity (e.g., order status, device status).
FR2: Send notifications to users or systems when a state change occurs.
FR3: Support multiple notification channels (e.g., email, SMS, push notifications).
FR4: Allow users to subscribe or unsubscribe from notifications for specific state changes.
FR5: Ensure notifications are delivered reliably and in a timely manner.
FR6: Provide an audit log of all state changes and notifications sent.
Non-Functional Requirements
NFR1: Handle up to 10,000 state changes per minute.
NFR2: Notification delivery latency should be under 5 seconds for 95% of notifications.
NFR3: System availability should be at least 99.9% uptime.
NFR4: Support eventual consistency for notification delivery status.
NFR5: Ensure data privacy and security for user contact information.
Think Before You Design
Questions to Ask
❓ Question 1
❓ Question 2
❓ Question 3
❓ Question 4
❓ Question 5
❓ Question 6
Key Components
State Change Detector
Notification Dispatcher
Subscription Management Service
Notification Channels (Email, SMS, Push)
Audit Logging Service
Message Queue for decoupling
Database for storing subscriptions and logs
Design Patterns
Observer pattern for state change detection
Publish-Subscribe pattern for notification dispatch
Retry and dead-letter queue for failed notifications
Circuit breaker for external notification services
Event sourcing for audit logging
Reference Architecture
 +-------------------+       +-----------------------+       +---------------------+
 |                   |       |                       |       |                     |
 | State Change      |       | Subscription          |       | Notification        |
 | Detector          +------>+ Management Service    +------>+ Dispatcher          |
 |                   |       |                       |       |                     |
 +-------------------+       +-----------+-----------+       +----------+----------+
                                         |                              |
                                         |                              |
                                         v                              v
                              +-------------------+          +---------------------+
                              |                   |          |                     |
                              | Database          |          | Message Queue       |
                              | (Subscriptions,   |          | (Notification Jobs) |
                              | Audit Logs)       |          |                     |
                              +-------------------+          +----------+----------+
                                                                        |
                                                                        v
                                                      +-----------------------------+
                                                      |                             |
                                                      | Notification Channels        |
                                                      | (Email, SMS, Push)           |
                                                      |                             |
                                                      +-----------------------------+
Components
State Change Detector
Custom service or hooks in existing systems
Detects when an entity's state changes and emits events.
Subscription Management Service
REST API with database backend
Manages user subscriptions and preferences for notifications.
Notification Dispatcher
Worker service consuming from message queue
Processes notification jobs and sends notifications via channels.
Message Queue
RabbitMQ or Kafka
Decouples state change detection from notification sending for reliability and scalability.
Database
Relational DB like PostgreSQL
Stores subscriptions, audit logs, and notification statuses.
Notification Channels
Third-party APIs (SMTP, Twilio, Firebase Cloud Messaging)
Deliver notifications via email, SMS, and push notifications.
Audit Logging Service
Part of database or separate logging system
Records all state changes and notification delivery attempts.
Request Flow
1. 1. State Change Detector detects a change in an entity's state.
2. 2. It publishes a state change event to the Subscription Management Service.
3. 3. Subscription Management Service queries the database for users subscribed to this state change.
4. 4. For each subscribed user, it creates notification jobs and pushes them to the Message Queue.
5. 5. Notification Dispatcher consumes jobs from the Message Queue.
6. 6. Dispatcher sends notifications through the appropriate Notification Channels.
7. 7. Notification Dispatcher updates the notification status in the database.
8. 8. Audit Logging Service records the state change event and notification delivery details.
Database Schema
Entities: - User (user_id, contact_info, preferences) - Subscription (subscription_id, user_id, entity_type, state_change_type) - Notification (notification_id, subscription_id, state_change_event_id, status, timestamp) - StateChangeEvent (event_id, entity_id, old_state, new_state, timestamp) Relationships: - User 1:N Subscription - Subscription 1:N Notification - StateChangeEvent 1:N Notification
Scaling Discussion
Bottlenecks
High volume of state change events causing message queue overload.
Notification Dispatcher becoming a bottleneck under heavy load.
Database write contention for audit logs and notification statuses.
Latency in third-party notification channels causing delays.
Managing user subscription data growth.
Solutions
Partition message queue topics by entity type or region to distribute load.
Scale Notification Dispatcher horizontally with multiple worker instances.
Use batch writes and optimized indexing in the database; consider sharding audit logs.
Implement retries with exponential backoff and circuit breakers for third-party APIs.
Archive old subscription and audit data; use caching for frequently accessed subscription info.
Interview Tips
Time: Spend 10 minutes clarifying requirements and constraints, 15 minutes designing the architecture and data flow, 10 minutes discussing scaling and trade-offs, and 10 minutes answering questions.
Clarify what state changes and notification channels are needed.
Explain how decoupling with message queues improves reliability and scalability.
Describe subscription management and user preference handling.
Discuss how audit logging supports traceability and debugging.
Address failure handling and retry mechanisms for notifications.
Highlight scaling strategies and bottleneck mitigation.

Practice

(1/5)
1. What is the main purpose of a notification system on state change in software design?
easy
A. To inform interested components immediately when data changes
B. To store data permanently in a database
C. To increase the size of the application
D. To delay updates until the user refreshes manually

Solution

  1. Step 1: Understand the role of notifications

    Notifications alert parts of a system or users when something important changes.
  2. Step 2: Identify the purpose of state change notifications

    They ensure components get updates immediately without waiting or manual refresh.
  3. Final Answer:

    To inform interested components immediately when data changes -> Option A
  4. Quick Check:

    Notification = Immediate update [OK]
Hint: Notifications alert on change, not store or delay [OK]
Common Mistakes:
  • Confusing notification with data storage
  • Thinking notifications delay updates
  • Assuming notifications increase app size
2. Which of the following is the correct method name to notify observers in a typical observer pattern implementation?
easy
A. unsubscribe()
B. updateState()
C. subscribe()
D. notifyObservers()

Solution

  1. Step 1: Recall observer pattern methods

    Common methods include subscribe, unsubscribe, and notifyObservers.
  2. Step 2: Identify the method that sends updates

    notifyObservers() is used to alert all subscribed observers about changes.
  3. Final Answer:

    notifyObservers() -> Option D
  4. Quick Check:

    Notify method = notifyObservers() [OK]
Hint: Notify method usually named notifyObservers() [OK]
Common Mistakes:
  • Confusing subscribe with notify
  • Using updateState() which changes state, not notify
  • Mixing unsubscribe with notification
3. Consider this simplified code snippet for a notification system:
class Subject:
    def __init__(self):
        self.observers = []
    def subscribe(self, observer):
        self.observers.append(observer)
    def notify(self, message):
        for obs in self.observers:
            obs.update(message)

class Observer:
    def update(self, message):
        print(f"Received: {message}")

subject = Subject()
obs1 = Observer()
subject.subscribe(obs1)
subject.notify("State changed")
What will be the output when subject.notify("State changed") is called?
medium
A. Error: update method missing
B. No output
C. Received: State changed
D. Received: None

Solution

  1. Step 1: Trace subscription and notification

    Observer obs1 is subscribed to subject, so it is in the observers list.
  2. Step 2: Check notify method behavior

    notify calls update on each observer with the message "State changed".
  3. Final Answer:

    Received: State changed -> Option C
  4. Quick Check:

    Observer prints message on notify [OK]
Hint: Subscribed observers receive and print messages [OK]
Common Mistakes:
  • Assuming notify does nothing without explicit call
  • Thinking update method is missing
  • Expecting no output if observers list is empty
4. In the following code, what is the main issue that prevents observers from receiving notifications?
class Subject:
    def __init__(self):
        self.observers = set()
    def subscribe(self, observer):
        self.observers.add(observer)
    def notify(self, message):
        for obs in self.observers:
            obs.receive(message)

class Observer:
    def update(self, message):
        print(f"Got: {message}")

subject = Subject()
obs1 = Observer()
subject.subscribe(obs1)
subject.notify("Update")
medium
A. Observers are stored in a set instead of a list
B. Method notify calls obs.receive but Observer has update method
C. subscribe method uses add instead of append
D. Observer class is missing

Solution

  1. Step 1: Check method called in notify

    notify() calls obs.receive(message).
  2. Step 2: Check Observer class methods

    Observer defines update(message), but no receive() method.
  3. Final Answer:

    Method notify calls obs.receive but Observer has update method -> Option B
  4. Quick Check:

    Method name mismatch causes AttributeError [OK]
Hint: Check method names called vs defined in observers [OK]
Common Mistakes:
  • Confusing set vs list for storing observers
  • Ignoring method name mismatches
  • Assuming missing class when it exists
5. You are designing a scalable notification system for state changes in a distributed application. Which design choice best supports efficient notifications to thousands of subscribers without blocking the main process?
hard
A. Use asynchronous message queues to dispatch notifications
B. Notify all subscribers synchronously in a loop
C. Store notifications in a database and poll subscribers
D. Send notifications only when the system restarts

Solution

  1. Step 1: Understand scalability needs

    Thousands of subscribers require non-blocking, efficient notification delivery.
  2. Step 2: Evaluate design options

    Synchronous loops block main process; polling adds delay; restart notifications are impractical.
  3. Step 3: Identify best practice

    Asynchronous message queues decouple notification sending, allowing scalable, fast delivery.
  4. Final Answer:

    Use asynchronous message queues to dispatch notifications -> Option A
  5. Quick Check:

    Async queues = scalable notifications [OK]
Hint: Async queues handle many subscribers efficiently [OK]
Common Mistakes:
  • Using synchronous loops causing delays
  • Relying on polling which is slow
  • Sending notifications only on restart