Design Patterns
Junior Questions
Junior
1
What are DRY, KISS, and YAGNI?
- DRY (Don't Repeat Yourself): Every piece of knowledge should have a single authoritative representation. Eliminate duplication via abstraction — but don't abstract premature similarities (WET: Write Everything Twice — duplicate once, then generalise).
- KISS (Keep It Simple, Stupid): Simplest solution that works. Resist over-engineering. Complexity is the enemy of maintainability.
- YAGNI (You Ain't Gonna Need It): Don't build features until they're actually needed. Avoid speculative abstractions.
- These principles are in tension: DRY encourages abstraction; YAGNI discourages premature abstraction. Judgement is required.
What problems does this solve?
- DRY/KISS/YAGNI are the most cited principles in code review — understanding the tensions between them shows engineering maturity.
Junior
2
What are Higher-Order Functions?
- A Higher-Order Function (HOF) takes a function as an argument, returns a function, or both.
- Built-in JS HOFs:
Array.map,filter,reduce,sort. - Patterns: Currying (partial application), function composition, decorators, middleware.
- Foundation of functional programming in JS — enables point-free style and reusable abstractions.
What problems does this solve?
- HOFs are fundamental to functional JS — map/filter/reduce and function composition are the building blocks of clean, declarative code.
Junior
6
What are the SOLID principles?
- S — Single Responsibility: A class/function should have one reason to change.
- O — Open/Closed: Open for extension, closed for modification. Add behaviour by adding code, not changing existing code.
- L — Liskov Substitution: Subtypes must be substitutable for their base types without altering correctness.
- I — Interface Segregation: Clients shouldn't depend on interfaces they don't use. Prefer small, focused interfaces.
- D — Dependency Inversion: Depend on abstractions, not concretions. High-level modules shouldn't depend on low-level modules.
- SOLID guides object-oriented design but applies equally to functional and component-based code.
What problems does this solve?
- SOLID is the most commonly asked design principles question — a confident answer shows architectural thinking beyond just writing working code.
Junior
17
What is the Factory pattern?
- Factory provides an interface for creating objects without specifying their concrete classes. The factory decides which class to instantiate.
- Factory Function (JS): A function that returns a new object — no
newkeyword needed. - Abstract Factory: A factory of factories — groups related object creation behind a single interface.
- Use cases: Creating framework controls based on OS/platform, dependency injection containers, test doubles.
What problems does this solve?
- Factory is the most practical creational pattern in JS — used constantly in framework internals and DI containers.
Junior
21
What is the Module pattern?
- Module encapsulates related functionality into a self-contained unit, exposing only a public API and keeping internals private.
- IIFE module (pre-ES6): Immediately-invoked function expression to create a closure with private scope.
- ES modules (ES6+): Native module system —
import/export. File scoping is private by default. Only exported names are public. - ES modules are the modern standard. Singletons by default.
What problems does this solve?
- The evolution from IIFE modules to ES modules is a key JS history story — understanding both shows breadth.
Junior
27
What is the Singleton pattern?
- Singleton ensures a class has only one instance and provides a global access point to it.
- Use cases: Database connection pools, config objects, loggers, browser-side state stores.
- In JavaScript: ES modules are singletons by default — the exported object is instantiated once and shared across all imports.
- Pitfalls: Hidden global state makes code harder to test (can't easily swap the instance). Overuse leads to tight coupling.
What problems does this solve?
- Singleton is the most recognisable pattern — understanding its pitfalls (global state, testability) is more important than just knowing its definition.
Mid-Level Questions
Mid
3
What are MVC, MVP, and MVVM?
- MVC (Model-View-Controller): Model (data/logic), View (UI), Controller (handles input, updates model). Traditional server-rendered apps (Rails, Laravel). Controller mediates user actions.
- MVP (Model-View-Presenter): View is passive. Presenter handles all UI logic and manipulates the view via an interface. Better testability — presenter tested without UI.
- MVVM (Model-View-ViewModel): ViewModel exposes observable data/commands. View binds to ViewModel via two-way data binding. Angular, Vue, Knockout. No direct DOM manipulation needed.
- React is closest to MVC — component is controller+view. Pinia/Redux is the model.
What problems does this solve?
- MVC/MVVM comes up constantly in framework comparisons — knowing which paradigm each framework follows shows architectural context.
Mid
4
What are Render Props and Slots?
- Render Props (React): A prop whose value is a function that returns JSX — the parent controls what gets rendered inside the child. Enables logic sharing without HOCs.
- Slots (Vue): Vue's equivalent — named and scoped slots pass template fragments from parent to child, enabling the same flexible composition.
- Both patterns are largely superseded by Custom Hooks (React) and Composables (Vue) for logic sharing, but still used for UI composition.
What problems does this solve?
- Render Props and Slots represent the evolution of component composition before hooks — knowing them contextualises why hooks were introduced.
Mid
5
What are common anti-patterns to avoid?
- God Object/Component — One class/component doing everything. Fix: decompose using SRP.
- Spaghetti code — Tangled control flow with no clear structure. Fix: refactor to clear modules/functions.
- Prop drilling — Passing props many levels deep. Fix: Context, state management library.
- Premature optimisation — Optimising before profiling. "Premature optimisation is the root of all evil." — Knuth.
- Magic numbers/strings — Unexplained literals. Fix: named constants.
- Mutating props/external state directly — Breaks reactivity and predictability.
- Callback hell — Deeply nested callbacks. Fix: async/await, Promises.
- Cargo culting — Using patterns without understanding why (e.g., applying Redux to a simple counter app).
What problems does this solve?
- Anti-patterns are as important as patterns — showing you recognise them and can refactor away is a hallmark of experienced engineers.
Mid
7
What is Dependency Injection?
- DI is a technique where a component receives its dependencies from the outside rather than creating them itself — an implementation of Inversion of Control.
- Benefits: Decoupling, easier testing (inject mocks), configurable.
- In JS/React: Pass dependencies as props or function arguments. React Context provides implicit DI. Testing: pass mock stores/services as props.
- Frameworks: Angular's DI system, NestJS's decorator-based IoC container.
What problems does this solve?
- DI is the mechanism that makes code testable — showing you understand why it matters, not just what it is, is the senior signal.
Mid
9
What is the Adapter pattern?
- Adapter converts the interface of a class into another interface the client expects — makes incompatible interfaces work together.
- JS example: Wrapping a legacy API or third-party library so your code doesn't depend on its specific interface.
- Also known as Wrapper. Commonly used when integrating third-party code or migrating legacy systems.
What problems does this solve?
- Adapter is used every time you integrate a third-party library — recognising it as a named pattern helps reason about interfaces.
Mid
13
What is the Composite pattern?
- Composite lets you compose objects into tree structures and treat both individual objects and compositions uniformly.
- Classic example: File system (files and folders both support
getSize()). React component tree (components can be leaves or contain other components). - Enables recursive structures where clients don't need to differentiate between simple and complex nodes.
What problems does this solve?
- Composite explains the tree-shaped structure underlying component frameworks — recognising it shows conceptual depth.
Mid
14
What is the Compound Components pattern?
- Compound Components is a React/Vue pattern where a set of components share implicit state through context, giving the consumer flexible control over layout and structure.
- Examples: HTML's
<select>+<option>. UI kit components:<Tabs>,<TabList>,<TabPanel>. - Avoids an explosion of props on a single component while still allowing customisation of internals.
What problems does this solve?
- Compound Components is the gold standard for reusable, flexible UI components — showing you can design and implement them is a strong senior signal.
Mid
16
What is the Facade pattern?
- Facade provides a simplified interface to a complex subsystem, hiding internal complexity from the client.
- Examples: jQuery was a facade over complex DOM/AJAX APIs. SDK wrapper around multiple network calls. Service layer in a web app that orchestrates DB, cache, and email.
- Reduces coupling between client code and complex subsystems.
What problems does this solve?
- Facade is the pattern behind every good SDK and service layer — recognising it shows architectural awareness.
Mid
18
What is the Flux / Redux pattern?
- Flux is a unidirectional data flow architecture: Action → Dispatcher → Store → View. Introduced by Meta to manage complex state in React apps.
- Redux: Single global store, pure reducer functions, actions describe changes. Predictable, debuggable (time-travel), but verbose.
- Redux Toolkit (RTK): Official, opinionated Redux — reduces boilerplate with
createSlice,createAsyncThunk. - Key insight: Redux actions are the Command pattern applied to state management.
- Pinia, Zustand, and Jotai are modern alternatives with far less ceremony.
What problems does this solve?
- Flux/Redux defined how frontend state management evolved — understanding it contextualises every modern alternative.
Mid
19
What is the Iterator pattern?
- Iterator provides a standard way to traverse a collection without exposing its internal structure.
- In JS: Built into the language via the Iterator Protocol (
Symbol.iterator).for...of, spread (...), destructuring all use it. Arrays, Maps, Sets, Strings, generators are all iterable.
What problems does this solve?
- Iterator is baked into ES6+ — understanding it reveals how for...of, spread, and generators work under the hood.
Mid
22
What is the Observer pattern?
- Observer defines a one-to-many dependency between objects so that when one object (subject) changes state, all its dependents (observers) are notified automatically.
- JS examples:
EventEmitter(Node.js),addEventListener, RxJS Observables, Vue's reactivity, Pinia subscriptions, Redux store subscribers. - vs Pub/Sub: Observer has direct subject-observer coupling. Pub/Sub uses a message broker (event bus) — observers don't know about the subject.
What problems does this solve?
- Observer is the foundation of event-driven programming and reactivity — it appears in virtually every framework.
Mid
25
What is the Pub/Sub pattern?
- Publishers emit events to a message bus/event channel. Subscribers register interest in event types. They are decoupled — publishers don't know about subscribers.
- vs Observer: Observer has direct subject→observer coupling. Pub/Sub introduces an intermediary event channel.
- Examples: Browser CustomEvents, Node.js EventEmitter used as event bus, Redis pub/sub, Kafka.
- Trade-off: Very decoupled, but harder to trace event flows and debug (events "disappear into the bus").
What problems does this solve?
- Pub/Sub is the backbone of cross-component communication and message queues — the distinction from Observer shows nuanced pattern knowledge.
Mid
26
What is the Repository pattern?
- Repository mediates between the domain and data mapping layers, providing a collection-like interface for accessing domain objects.
- Abstracts the data source (DB, REST API, localStorage) behind a consistent interface.
- Benefits: Easy to swap data sources (e.g., real DB in prod, in-memory in tests). Centralises query logic.
What problems does this solve?
- Repository is the standard pattern for data access in backend/full-stack JS — it's the bridge between business logic and persistence.
Mid
29
What is the Strategy pattern?
- Strategy defines a family of algorithms, encapsulates each one, and makes them interchangeable. Lets the algorithm vary independently from the clients that use it.
- JS example: Sorting strategies, payment methods, form validation rules, compression algorithms.
- Eliminates conditionals — instead of
if (method === 'credit') { ... }, pass the strategy as a function/class.
What problems does this solve?
- Strategy is the pattern behind configuration-driven and extensible systems — it replaces complex switch/if chains with composable units.
Senior Questions
Senior
8
What is Inversion of Control?
- Inversion of Control (IoC) is a principle where the framework calls your code rather than your code calling the framework — "Don't call us, we'll call you."
- Frameworks implement IoC: React calls your component render functions; Express calls your route handlers; Angular calls lifecycle hooks.
- DI is one form of IoC — control over dependency creation is inverted to a container.
- IoC enables extensibility — plug in your code into defined extension points.
What problems does this solve?
- IoC is the meta-principle that explains how frameworks work — understanding it reveals why all frameworks have lifecycle hooks and extension points.
Senior
10
What is the Builder pattern?
- Builder separates the construction of a complex object from its representation, allowing the same process to create different results.
- Useful when an object has many optional or ordered configuration steps.
- Common in query builders, HTTP client configuration, test data factories.
What problems does this solve?
- Builder's fluent/chaining interface is ubiquitous in JS libraries — recognising and implementing it is a practical skill.
Senior
11
What is the Chain of Responsibility pattern?
- Pass a request along a chain of handlers — each handler decides to process the request or pass it to the next handler.
- JS examples: Express/Koa middleware chains (
next()), browser event propagation (capture/bubble), authentication middleware pipelines.
What problems does this solve?
- Chain of Responsibility is what Express middleware is — naming the pattern connects everyday code to classic CS vocabulary.
Senior
12
What is the Command pattern?
- Command encapsulates a request as an object, enabling parameterisation, queuing, logging, and undo/redo.
- Structure: Command object with
execute()and optionallyundo(). Invoker calls commands. Receiver does the actual work. - Examples: Text editor undo/redo, Redux actions (each action is a command), task queues, macro recording.
What problems does this solve?
- Redux is an implementation of the Command pattern for state management — recognising this connects React ecosystem knowledge to classic CS.
Senior
15
What is the Decorator pattern?
- Decorator attaches additional responsibilities to an object dynamically without modifying its class — a flexible alternative to subclassing.
- JS examples: TypeScript/Babel decorators (
@), HOCs in React, middleware in Express (wrapping the next handler). - Respects the Open/Closed principle — adds behaviour without modifying the original.
What problems does this solve?
- Decorator is fundamental to functional composition and middleware chains — it appears everywhere in modern JS codebases.
Senior
20
What is the Mediator pattern?
- Mediator defines an object that coordinates communication between components, reducing direct dependencies between them.
- Without mediator: Components communicate directly (tight coupling, combinatorial dependencies).
- With mediator: Components communicate only with the mediator (event bus, message broker).
- Examples: Event bus (Vue's
$emitpatterns), chat room (server as mediator between clients), air traffic control.
What problems does this solve?
- Mediator is what underpins event buses and message brokers — it trades direct coupling for centralized coordination.
Senior
23
What is the Prototype pattern?
- Prototype creates new objects by cloning an existing object (the prototype), rather than instantiating from a class.
- In JavaScript: Prototype chain is the language's built-in mechanism.
Object.create(proto)creates an object inheriting fromproto. Structuring clone with spread:{'{ ...original, override }'}. - Use cases: Cloning complex configuration objects, undo/redo stacks (clone state before mutation), game entities.
What problems does this solve?
- Prototype is JavaScript's native object system — understanding prototypal inheritance distinguishes JS-native thinking from class-centric thinking.
Senior
24
What is the Proxy pattern?
- Proxy provides a surrogate or placeholder for another object to control access to it.
- Types: Virtual proxy (lazy init), protection proxy (access control), caching proxy, logging proxy.
- In JS: ES6
Proxyobject intercepts operations (get, set, apply) on any object — used in Vue 3's reactivity system (wraps reactive objects to track/trigger updates).
What problems does this solve?
- ES6 Proxy powers Vue 3's reactivity — understanding the pattern explains how modern frameworks track state changes.
Senior
28
What is the State pattern?
- State allows an object to alter its behaviour when its internal state changes — the object appears to change its class.
- Use cases: Traffic lights, vending machines, form wizard steps, UI state machines.
- State machines (XState): Finite State Machines formalise state transitions — prevent invalid states by making impossible states impossible.
- Eliminates sprawling
if/elseorswitchblocks for state-dependent logic.
What problems does this solve?
- The State pattern and state machines are increasingly used in complex UI — XState is a popular production tool worth mentioning.
Senior
30
What is the Template Method pattern?
- Template Method defines the skeleton of an algorithm in a base class, deferring some steps to subclasses. Subclasses override specific steps without changing the overall structure.
- JS functional equivalent: A higher-order function that calls customisable callback hooks at defined points.
- Examples: Lifecycle hooks in frameworks (React's render cycle, Vue's lifecycle), Express middleware, test suite setup/teardown hooks (
beforeEach,afterEach).
What problems does this solve?
- Template Method is the pattern behind all lifecycle hooks — understanding it explains how React and Vue's lifecycle systems work.