Apple Questions
Design and implement a thread-safe observable/reactive data binding system.
HardTechnicalDesign Patterns25-30 minutes
Model Answer
A reactive data binding system notifies observers when data changes. Thread safety means concurrent reads and writes don't corrupt state, and observer notifications are consistent.
The core pattern: Observable wraps a value, maintains a list of observer callbacks, and notifies them on value changes. Thread safety is achieved through a locking mechanism.
Approaches
Observable with Copy-on-Notify
Copy the observers list before notifying to prevent concurrent modification issues. Use closure-based unsubscribe for clean cleanup.
class Observable {
constructor(initialValue) {
this._value = initialValue;
this._observers = [];
}
get value() {
return this._value;
}
set value(newValue) {
const oldValue = this._value;
this._value = newValue;
// Copy observers to prevent issues if observers are added/removed during notification
const snapshot = [...this._observers];
for (const observer of snapshot) {
try {
observer(newValue, oldValue);
} catch (e) {
console.error('Observer error:', e);
}
}
}
subscribe(observer) {
this._observers.push(observer);
// Return unsubscribe function
return () => {
const index = this._observers.indexOf(observer);
if (index > -1) this._observers.splice(index, 1);
};
}
}
// Usage:
const name = new Observable('Alice');
const unsub = name.subscribe((newVal, oldVal) => {
console.log(oldVal, '->', newVal);
});
name.value = 'Bob'; // logs: Alice -> Bob
unsub(); // clean upTime: O(n) per update where n is observer countSpace: O(n) for observer list
Common Mistakes
- 1.Not copying the observer list before iterating (concurrent modification during notification)
- 2.Not providing an unsubscribe mechanism (memory leak)
- 3.Using synchronous notification that blocks the writer
- 4.Not handling the case where an observer throws an exception during notification
Follow-up Questions
- How would you implement computed/derived observables?
- How would you batch multiple rapid changes into a single notification?
- How would you prevent memory leaks from observers that forget to unsubscribe?