Topics
v6.0.0
On this page · sections

JavaScript Patterns, FP & Architecture

Can you pick a pattern because it matches the change you expect — not because it has a name?

Design patterns in JavaScript are small: Observer, Strategy, Module, Command. Functional style is the other half: pure functions, immutability, composition.

Coding pages implement EventEmitter, pipe, and LRU. This page is when to reach for them.

Questions

Patterns

  1. Observer vs Pub/Sub
  2. Strategy and Composition

Functional style

  1. Pure Functions and Immutability
  2. The Module Pattern

Senior-Level Follow-ups

  1. Flags vs a State Machine
  2. Command vs Snapshot for Undo
  3. When Patterns Become Noise

Patterns

1. Observer vs Pub/Sub

Why This Matters

React subscribe, DOM events, and Redux are variants of “notify later.”

Problem

What is the difference between Observer and Pub/Sub?

Example

Observer: the subject holds a list of observers. Direct, typed, easy to unsubscribe.

store.subscribe(fn) button.onclick = fn

Pub/Sub: a broker in the middle. Publishers do not know subscribers. Flexible, easier to leak, harder to type.

bus.emit("user:login", payload)

EventEmitter is Observer with string event names — EventEmitter.

Always snapshot listeners before emit. Always unsubscribe.

Interview Answer

“Observer is a direct list of callbacks. Pub/Sub adds a broker and event names. I use Observer for a store; I use a bus only when modules must not import each other. Either way, emit iterates a snapshot.”

2. Strategy and Composition

Why This Matters

if (type === "csv") exportCsv() grows into an unmaintainable switch.

Problem

How do you swap algorithms without rewriting the caller?

Example

const exporters = { csv: exportCsv, json: exportJson, }; function exportFile(format, data) { const fn = exporters[format]; if (!fn) throw new Error(`Unknown format: ${format}`); return fn(data); }

That is Strategy: the behavior is a value.

React composition (children, render props, hooks) is the UI version. Prefer passing a function or component over a deep class hierarchy.

Interview Answer

“Strategy makes the algorithm a parameter. I keep a map of functions or pass a callback. I use inheritance only when I have a real subtype, not to vary one method.”

Functional style

3. Pure Functions and Immutability

Why This Matters

Pure functions are easy to test and to replay. They are not a religion — I/O has to live somewhere.

Problem

What is purity, and why copy instead of mutate shared state?

Example

function add(a, b) { return a + b; } function addTag(item, tag) { return { ...item, tags: [...item.tags, tag] }; }

Same inputs → same output, no observable side effects.

HOFs (map, filter, memoize) take or return functions. They are useful when the abstraction is real.

Immutability is shallow unless you clone. Shared nested refs still mutate — Objects, Arrays & Descriptors.

pipe / curry implementations: Pipe, Compose & Curry.

Interview Answer

“A pure function depends only on its inputs and does not mutate shared state. I keep domain logic pure and push I/O to the edges. I copy on write for shared UI state, knowing spread is shallow.”

4. The Module Pattern

Problem

How did JS encapsulate before ESM, and what still applies?

Example

const api = (function () { let token = null; return { setToken(value) { token = value; }, getToken() { return token; }, }; })();

IIFE + closure = private state. ESM let at module scope is the same idea with better syntax.

Singletons at module scope are process-wide on the server. Do not store request data there.

Interview Answer

“The module pattern is a closure that returns a public API. ESM modules are the language version. I still use factories when I need multiple instances or per-request state.”

Senior-Level Follow-ups

5. Flags vs a State Machine

isLoading && isSuccess

is an impossible product state.

If states are mutually exclusive, use one value and a transition table — not a handful of booleans.

Independent flags (isDarkMode, isModalOpen) can stay booleans.

6. Command vs Snapshot for Undo

Command: store execute / undo. Cheap, needs a correct inverse.

Snapshot: store the whole state. Simple, heavy.

Editors often mix: snapshot every N commands. New user actions clear redo.

7. When Patterns Become Noise

A 40-line feature does not need Factory + Abstract Factory + Visitor.

Name the problem: notification, swappable algorithm, reversible action, exclusive UI state.

If the code is clearer as a function, skip the class diagram.

Final Interview Strategy

1. Observer for stores; bus only for decoupling 2. Snapshot emit; unsubscribe 3. Strategy = behavior as data 4. Pure core, I/O at edges 5. Module/factory for privacy and instances 6. One state string for exclusive workflows 7. Don't pattern-match for sport

Senior-level signal: Pick the pattern from the invariant you need (notify, swap, reverse, exclusive state). Then mention the production edge: leaks, SSR singletons, or impossible flags.

Last updated on