← Back to Design Principles

Observer

Design PrinciplesMid

The Question

What is the Observer pattern and when would you use it?

What a Strong Answer Covers

  • subject notifies observers
  • "decoupled

Senior-Level Answer

The Observer pattern (also called Publish-Subscribe or Event Listener) defines a one-to-many dependency between objects: when the **subject** (publisher/observable) changes state, all registered **observers** (subscribers/listeners) are notified and updated automatically.

The core problem it solves: how do you avoid tight coupling between an object that produces events and the objects that react to those events? Without Observer, the subject would need to know about every interested party and call them directly.

**Structure:** - **Subject/Observable:** maintains a list of observers, provides `subscribe(observer)` and `unsubscribe(observer)` methods, calls `notify()` on all observers when state changes - **Observer interface:** defines the `update(event)` method all observers implement - **Concrete Observers:** implement specific reactions

Python example (stock price monitor):

```python from abc import ABC, abstractmethod from typing import List

class Observer(ABC): @abstractmethod def update(self, price: float): ...

class StockTicker: def __init__(self): self._observers: List[Observer] = [] self._price: float = 0.0

def subscribe(self, obs: Observer): self._observers.append(obs)

def set_price(self, price: float): self._price = price for obs in self._observers: obs.update(price)

class AlertObserver(Observer): def update(self, price: float): if price > 100: print(f'Alert: price is {price}') ```

**When to use:** - One object's change requires updating an unknown number of other objects (GUI event systems, event buses, reactive programming) - Decoupling is more important than call-graph clarity (different subsystems reacting to domain events) - Real-world examples: Django signals, `EventEmitter` in Node.js, `Observable` in RxJS, `UIControl` target-action in iOS, pytest hooks

**Pitfalls:** - **Memory leaks:** If observers hold strong references to the subject (or vice versa), neither can be garbage collected. Use `weakref` for observer lists in long-lived subjects. - **Unexpected notification order:** Observers are notified in registration order by default. Don't write code that depends on this ordering. - **Cascading updates:** An observer that modifies the subject triggers another notification cycle — can cause infinite loops or hard-to-trace bugs. - **Synchronous blocking:** In Python's standard Observer, `notify()` is synchronous. A slow observer blocks the subject. For high-throughput systems, push to a message queue instead. - **Debugging difficulty:** The implicit call graph makes stack traces hard to follow. Structured logging in observers and subjects is essential.

Distinguish from Strategy: Observer is about communication between objects; Strategy is about swappable algorithms.

What Separates a 2/3 from a 3/3

2/3 — Passing but Incomplete

Correctly defines the one-to-many notification mechanism, gives a concrete real-world example, and names subscribe/unsubscribe/notify as the core interface.

3/3 — Strong Answer

Covers structure, real examples (Django signals, EventEmitter), memory leak via strong references, cascading update risk, synchronous blocking limitation, and distinguishes from Strategy/Pub-Sub variants.

Common Mistakes

  • Confusing Observer with Strategy — they solve different problems
  • Not discussing memory leaks from strong references — a common production bug in long-lived observable systems
  • Forgetting that synchronous Observer blocks — in distributed or high-throughput systems this is a design constraint
  • Treating Observer and Pub-Sub as identical — Pub-Sub adds a message broker, decoupling publishers and subscribers completely

Follow-Up Questions

  • How does Observer differ from the Pub-Sub pattern? — Observer: subject knows its observers (direct reference). Pub-Sub: a message broker sits between — publisher and subscriber never know each other. Pub-Sub is more decoupled.
  • How would you prevent a memory leak in a long-lived Observable? — Store observers as weakref.ref() or use weakref.WeakSet. When the observer is garbage collected, the weak reference becomes None and can be cleaned up.
  • What happens if an observer modifies the subject during notification? — Triggers another notify() call during iteration — can infinite loop or mutate the observer list mid-iteration. Solution: snapshot the list before iterating or use a re-entrant flag.
  • How is Django's signal system an implementation of Observer? — Signal = Subject. Receivers = Observers. connect/disconnect = subscribe/unsubscribe. send() = notify(). dispatch_uid prevents duplicate registration.

Related Questions

  • Singleton
  • Factory
  • Strategy
  • IoC / Dependency Injection
  • High Cohesion / Loose Coupling

Can You Explain This Cold?

Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.

Get Graded — Free Assessment
GrindQuestionsAITechnical interview assessment
TermsPrivacyAbout