Interview Q&A · 80 questions · 26 answered publicly

Design Patterns Interview Questions

Ordered by how often they're asked. Sign in free to see every answer, rate your confidence and run timed mock interviews.

  1. Most asked What is a design pattern, and why are they useful?

    Summary

    A design pattern is a named, reusable solution shape for a design problem that keeps recurring. Patterns give teams a shared vocabulary and proven trade-offs, so one word like "Strategy" can explain a whole design.

    Longer Answer

    The Gang of Four book (1994) describes each pattern by its name, the problem it addresses, the solution (roles and collaborations, not finished code) and its consequences. Patterns are not libraries you install; you arrange your own code in that shape, adapted to your language.

    Their main value is communication and judgement: recognising "this is an Adapter situation" brings known benefits and costs with it. They are tools for specific problems, not goals. Simple code without patterns is often the best design.

    Key Points

    • Named solution shapes for recurring design problems.
    • Name, problem, solution, consequences.
    • Shared vocabulary in design discussions and reviews.
    • Use when the problem exists, not by default.

    Deep dive: Design Patterns, Explained Simply: What a Design Pattern Is

    Permalink

  2. Most asked Explain the SOLID principles.

    Summary

    SOLID is five object-oriented design principles: Single Responsibility (one reason to change), Open/Closed (extend without modifying), Liskov Substitution (subtypes keep the parent's promises), Interface Segregation (small, focused interfaces) and Dependency Inversion (depend on abstractions, not concrete details).

    Longer Answer

    • S: a class should answer to one group of people, so changes for different reasons don't collide.
    • O: add behaviour by adding code (a new class or strategy), not by editing code that already works.
    • L: any code that works with a parent type must work with a subtype without surprises.
    • I: clients shouldn't depend on methods they don't use; split large interfaces.
    • D: high-level policy and low-level details both depend on abstractions, which the high-level side owns. Dependencies are passed in.

    They are guidelines that make code easier to test and change. Applied mechanically, they can produce too many tiny classes; use them where changes actually collide.

    Key Points

    • Five principles for maintainable OO design.
    • Each one reduces the cost of a specific kind of change.
    • DIP is the principle; DI is the technique.
    • Guidelines, not laws: apply where change happens.

    Deep dive: Design Patterns, Explained Simply: SOLID, Part 1

    Permalink

  3. Most asked What is the difference between dependency inversion, dependency injection and inversion of control?

    Summary

    Dependency inversion is a design principle (high-level code depends on abstractions it owns). Dependency injection is a technique for supplying dependencies from outside (usually through the constructor). Inversion of control is the broader idea that a framework or container calls your code and manages wiring, instead of your code controlling everything.

    Longer Answer

    • DIP (the D in SOLID): OrderService depends on an OrderStore interface, not on MySqlOrderStore.
    • DI: OrderService(store) receives its store; a composition root or container creates the real one.
    • IoC: "don't call us, we'll call you"; frameworks call your controllers, event handlers and lifecycle hooks. DI containers are one form of IoC.

    You can apply DIP and DI with plain constructors and no framework at all.

    Key Points

    • DIP: principle about the direction of dependencies.
    • DI: technique for passing dependencies in.
    • IoC: framework controls the flow and wiring.
    • DI doesn't require a container.

    Deep dive: Design Patterns, Explained Simply: Dependency Injection Without a Framework

    Permalink

  4. Most asked Why is composition often preferred over inheritance?

    Summary

    Composition (an object holds other objects it delegates to) lets you combine behaviours freely and change them at runtime, without the class explosion and tight coupling of deep inheritance hierarchies.

    Longer Answer

    Using inheritance to mix features (walking, flying, swimming robots) needs a subclass per combination, couples every subclass to its parent's internals (the fragile base class problem), and fixes behaviour at compile time. With composition, a Robot holds a Movement object, so three movement classes cover every robot and a robot can switch movement at runtime.

    Inheritance is still right for genuine "is-a" relationships with stable shared behaviour, such as a framework's base controller.

    Key Points

    • Avoids class explosion for combinations.
    • Allows runtime changes.
    • Looser coupling than base classes.
    • Inheritance still fits real is-a relationships.

    Deep dive: Design Patterns, Explained Simply: Program to Interfaces, Favour Composition

    Permalink

  5. Most asked What is dependency injection, and what forms does it take?

    Summary

    Dependency injection means an object receives its collaborators from outside instead of creating them. The forms are constructor injection (the default), setter or property injection (optional or changeable dependencies) and method injection (one call needs it).

    Longer Answer

    DI makes dependencies explicit and swappable: tests pass fakes (an in-memory mailer, a fixed clock), and production wires real implementations in one composition root. Frameworks like Spring, Laravel's container, NestJS and FastAPI's Depends automate the wiring.

    Inject things that do I/O, hold state or need faking: databases, HTTP clients, clocks, random numbers. Ten constructor parameters signal an SRP problem, not a DI problem.

    Code Example

    class FixedClock:
        def today(self):
            return "2030-01-01"
    
    
    class Signup:
        def __init__(self, clock):  # constructor injection
            self.clock = clock
    
        def welcome(self, email):
            return f"{email} joined on {self.clock.today()}"
    
    
    print(Signup(FixedClock()).welcome("[email protected]"))
    

    Key Points

    • Pass dependencies in.
    • Constructor injection is the default.
    • Composition root wires real objects.
    • Too many dependencies = too many responsibilities.

    Deep dive: Design Patterns, Explained Simply: Dependency Injection Without a Framework

    Permalink

  6. Most asked Explain the Factory Method pattern and how it differs from a simple factory.

    Summary

    Factory Method lets subclasses decide which product to create by overriding a creation method that a shared algorithm calls. A simple factory is one function or class with a conditional that returns the right object; it isn't a GoF pattern but solves the same 'who decides the class' problem without subclassing.

    Longer Answer

    In Factory Method, the creator's algorithm (export()) calls create_formatter(); CsvReport and JsonReport override it. The algorithm only depends on the product interface, so new products need no changes to it. It suits frameworks where users extend a base class.

    A simple factory (create_formatter("csv"), or a dictionary from names to classes) is more common in application code. With first-class functions, passing the product or a function that creates it is often simplest.

    Code Example

    class Csv:
        def format(self, row):
            return ",".join(row)
    
    
    class Pipe:
        def format(self, row):
            return " | ".join(row)
    
    
    class Report:
        def create_formatter(self):  # the factory method
            raise NotImplementedError
    
        def export(self, row):
            return self.create_formatter().format(row)
    
    
    class CsvReport(Report):
        def create_formatter(self):
            return Csv()
    
    
    class PipeReport(Report):
        def create_formatter(self):
            return Pipe()
    
    
    for report in [CsvReport(), PipeReport()]:
        print(report.export(["1", "Ada"]))
    

    Key Points

    • Creator calls an overridable creation method.
    • Subclasses choose the concrete product.
    • Simple factory = one creating function/lookup.
    • Java's Collection.iterator() is a factory method.

    Deep dive: Design Patterns, Explained Simply: Factory Method

    Permalink

  7. Most asked What problem does the Builder pattern solve? Show an example.

    Summary

    Builder assembles complex objects step by step with named, chainable methods and a final build() that validates the combination. It replaces telescoping constructors and unreadable positional arguments.

    Longer Answer

    A builder keeps defaults, lets callers set only what they need (.timeout(5).header(...)), and checks invalid combinations (a GET with a body) in build(), close to where the object is assembled. The product can be immutable.

    In Python, PHP 8 and TypeScript, named arguments and object literals remove much of the need; builders still shine for validation, fluent APIs (query builders) and test data builders.

    Code Example

    class PizzaBuilder:
        def __init__(self):
            self.size, self.toppings = "medium", []
    
        def large(self):
            self.size = "large"
            return self  # returning self allows chaining
    
        def topping(self, name):
            self.toppings.append(name)
            return self
    
        def build(self):
            if len(self.toppings) > 3:
                raise ValueError("max 3 toppings")
            return f"{self.size} pizza with {', '.join(self.toppings) or 'cheese'}"
    
    
    print(PizzaBuilder().large().topping("olives").topping("basil").build())
    print(PizzaBuilder().build())
    

    Key Points

    • Named, chainable steps; build() validates.
    • Replaces telescoping constructors.
    • Product can be immutable.
    • Named arguments often suffice in Python/PHP/TS.

    Deep dive: Design Patterns, Explained Simply: Builder

    Permalink

  8. Most asked How do you implement a Singleton, and why is it often considered an anti-pattern?

    Summary

    A Singleton has a private constructor and a static accessor that creates the single instance on first use and returns it afterwards. It's criticised because its global access hides dependencies, shares mutable state across tests and requests, and makes swapping implementations hard.

    Longer Answer

    The "exactly one instance" guarantee is sometimes useful (a connection pool, a hardware interface), but the global access point is the problem: any code can reach it, tests leak state into each other, and parallel code needs thread safety (in Java: a synchronized accessor, the holder idiom, or an enum).

    The usual alternative: create one instance at startup and inject it, or register it with singleton scope in a DI container (Spring's default scope, Laravel's singleton()). In Python, a module-level object is the idiomatic singleton.

    Code Example

    class Config:
        _instance = None
    
        @classmethod
        def instance(cls):
            if cls._instance is None:  # created lazily, on first use
                cls._instance = cls()
            return cls._instance
    
    
    print("same object:", Config.instance() is Config.instance())
    

    Key Points

    • Private constructor + static accessor.
    • Global access hides dependencies and leaks state.
    • Thread-safe lazy init in Java: holder idiom or enum.
    • Prefer one injected instance or container singleton scope.

    Deep dive: Design Patterns, Explained Simply: Singleton

    Permalink

  9. Most asked What is the Adapter pattern? Give an example.

    Summary

    Adapter wraps a class that has an incompatible interface and translates calls to the interface your code expects. For example, a LegacyBillingAdapter implements your PaymentProvider.charge(cents) by converting cents to a dollar string and calling the legacy submit().

    Longer Answer

    The client sees only the target interface; all translation (method names, units, result shapes, error types) lives in the adapter. That keeps vendor-specific details out of business logic and makes it easy to switch or add providers.

    Real examples: Laravel's filesystem adapters (local, S3, FTP behind one API), Java's InputStreamReader and Arrays.asList(), DB-API drivers in Python.

    Code Example

    class LegacyBilling:  # third-party: amount as a dollar string
        def submit(self, amount):
            return {"ref": f"LB-{amount}"}
    
    
    class BillingAdapter:  # our interface: charge(cents) -> id
        def __init__(self, legacy):
            self.legacy = legacy
    
        def charge(self, cents):
            return self.legacy.submit(f"{cents // 100}.{cents % 100:02d}")["ref"]
    
    
    print(BillingAdapter(LegacyBilling()).charge(1250))
    

    Key Points

    • Translates an incompatible interface to the expected one.
    • Client stays unchanged.
    • Ideal for third-party and legacy code.
    • Keeps vendor types out of the domain.

    Deep dive: Design Patterns, Explained Simply: Adapter

    Permalink

  10. Most asked What is the Decorator pattern? How is it different from inheritance?

    Summary

    Decorator wraps an object in another object with the same interface that adds behaviour before or after delegating. Unlike inheritance, decorators are combined at runtime and stack in any order, so you don't need a subclass for every combination of features.

    Longer Answer

    Typical uses are cross-cutting concerns: logging, caching, retries, metrics, authorization, compression. LoggingFetcher(CachingFetcher(RetryFetcher(http))) composes three features without changing HttpFetcher. Order matters: logging outside the cache logs every call; inside it, only real fetches.

    Java I/O streams are the textbook example; Python's @decorator applies the same idea to functions; HTTP middleware is a decorator chain around a handler.

    Code Example

    class Http:
        def get(self, url):
            return f"<{url}>"
    
    
    class Logged:  # decorator: same get(), adds logging
        def __init__(self, inner):
            self.inner = inner
    
        def get(self, url):
            print(f"GET {url}")
            return self.inner.get(url)
    
    
    class Cached:  # decorator: same get(), adds caching
        def __init__(self, inner):
            self.inner, self.cache = inner, {}
    
        def get(self, url):
            if url not in self.cache:
                self.cache[url] = self.inner.get(url)
            return self.cache[url]
    
    
    client = Cached(Logged(Http()))  # logging inside the cache: only real fetches are logged
    print(client.get("/a"))
    print(client.get("/a"))
    

    Key Points

    • Same interface, wraps and delegates.
    • Adds behaviour without changing the class.
    • Stackable at runtime; order matters.
    • Java I/O streams, Python decorators, middleware.

    Deep dive: Design Patterns, Explained Simply: Decorator

    Permalink

  11. Most asked Explain the Observer pattern and give examples from real frameworks.

    Summary

    Observer lets a subject notify any number of subscribers when something happens, without knowing what they do. Subscribers register and unregister at runtime. Examples: DOM addEventListener, Node.js EventEmitter, RxJS, Laravel events and model observers, Django signals, Spring application events.

    Longer Answer

    It decouples the source of an event from its reactions: order placement doesn't import email, analytics and inventory code; they subscribe. Decide how ordering and errors are handled (one failing observer shouldn't break the subject unless it must), and always unsubscribe to avoid memory leaks.

    Across processes or services, use Pub/Sub with a broker instead of in-process observers.

    Code Example

    class Events:
        def __init__(self):
            self.subscribers = []
    
        def subscribe(self, fn):
            self.subscribers.append(fn)
    
        def publish(self, order_id):
            for fn in self.subscribers:
                fn(order_id)
    
    
    events = Events()
    events.subscribe(lambda oid: print(f"email: receipt for {oid}"))
    events.subscribe(lambda oid: print(f"stock: reserve for {oid}"))
    events.publish(42)
    

    Key Points

    • Subject notifies subscribers it doesn't know.
    • Subscribe/unsubscribe at runtime.
    • Handle observer errors and ordering deliberately.
    • Unsubscribe to avoid leaks.

    Deep dive: Design Patterns, Explained Simply: Observer

    Permalink

  12. Most asked Explain the Strategy pattern with an example.

    Summary

    Strategy puts interchangeable algorithms behind one interface; a context holds one strategy and delegates to it, so the algorithm can be chosen at runtime without if/else. Shipping cost rules (standard, express, pickup) are a typical example.

    Longer Answer

    Each strategy is testable alone, and new ones are added without editing the context (Open/Closed). Selection usually happens once, through configuration or a lookup table. In Python, TypeScript, modern Java and PHP a strategy is often just a function or lambda; comparators passed to sort functions are strategies.

    Code Example

    STRATEGIES = {  # strategies as plain functions in a lookup table
        "standard": lambda subtotal: 0 if subtotal >= 5000 else 499,
        "express": lambda subtotal: 1299,
        "pickup": lambda subtotal: 0,
    }
    
    
    def total(subtotal, method):
        return subtotal + STRATEGIES[method](subtotal)
    
    
    for method in ["standard", "express", "pickup"]:
        print(method, total(4200, method))
    

    Key Points

    • Interchangeable algorithms behind one interface.
    • Context delegates; no if/else.
    • Often just a function.
    • Pick via lookup table or configuration.

    Deep dive: Design Patterns, Explained Simply: Strategy

    Permalink

  13. Most asked What is the difference between the Strategy and State patterns?

    Summary

    Both delegate to an interchangeable object, but in Strategy the client chooses the algorithm and strategies don't know each other, while in State the state objects themselves trigger transitions to other states as the object's lifecycle progresses.

    Longer Answer

    Strategy answers "how should this be done?" (shipping cost: standard, express); the choice is usually made once from configuration or user input. State answers "what is allowed right now?" (an order that is pending, then paid, then shipped); behaviour changes as the object moves through states, and the states know their successors.

    Their class diagrams look almost identical; the difference is who changes the delegate and why.

    Key Points

    • Same structure, different intent.
    • Strategy: chosen by the client, independent.
    • State: transitions driven by states.
    • Strategy = how; State = what's allowed now.

    Deep dive: Design Patterns, Explained Simply: Choosing the Right Pattern

    Permalink

  14. Most asked Compare Adapter, Decorator, Proxy and Facade.

    Summary

    All four wrap something. Adapter gives an existing object a different interface so it fits; Decorator keeps the same interface and adds behaviour (stackable); Proxy keeps the same interface and controls access (lazy, permissions, remote); Facade offers a new, simpler interface over a whole subsystem.

    Longer Answer

    The code shape can be nearly identical (a class holding another and delegating), so the distinction is intent:

    Pattern Interface Intent
    Adapter different make it fit
    Decorator same add behaviour
    Proxy same control access
    Facade new, simpler, over many classes simplify

    Naming the wrapper by its intent tells the next reader why it exists.

    Key Points

    • Adapter: fit a different interface.
    • Decorator: add behaviour, same interface.
    • Proxy: control access, same interface.
    • Facade: simplify a subsystem.

    Deep dive: Design Patterns, Explained Simply: Choosing the Right Pattern

    Permalink

  15. Most asked What is the difference between Observer and Pub/Sub?

    Summary

    In Observer, the subject holds direct references to its observers and usually notifies them synchronously in the same process. In Pub/Sub, publishers and subscribers only know a broker and topic names; delivery is typically asynchronous, can cross processes and services, and failures are isolated with retries and dead-letter queues.

    Longer Answer

    Observer is simpler and immediate (UI events, in-process domain events). Pub/Sub decouples further and scales across services (SNS/SQS, Kafka, RabbitMQ, Google Pub/Sub), at the cost of eventual consistency, duplicate deliveries (subscribers must be idempotent) and harder debugging.

    Key Points

    • Observer: direct references, synchronous, in-process.
    • Pub/Sub: broker and topics, asynchronous.
    • Pub/Sub isolates failures but brings eventual consistency.
    • Make Pub/Sub subscribers idempotent.

    Deep dive: Design Patterns, Explained Simply: Pub/Sub and the Event Bus

    Permalink

  16. Most asked What is the Repository pattern, and when is it worth using?

    Summary

    A repository is a collection-like interface (add, get, overdue_invoices()) that hides how domain objects are stored. It's worth using when business logic is mixed with queries and you want it testable with in-memory implementations or decoupled from the storage technology.

    Longer Answer

    Repositories come from Martin Fowler's Patterns of Enterprise Application Architecture and are central to Domain-Driven Design and hexagonal architecture. Spring Data repositories are a framework version.

    They add little in simple CRUD apps where an Active Record ORM already provides query methods, and generic repositories that just mirror the ORM (find_by(any_field)) are a common anti-pattern. Make methods domain-specific.

    Key Points

    • Collection-like interface over storage.
    • Business logic testable with in-memory repos.
    • Domain-specific methods, not generic wrappers.
    • Often unnecessary for simple CRUD.

    Deep dive: Design Patterns, Explained Simply: Repository and Unit of Work

    Permalink

  17. Most asked When should you NOT use a design pattern?

    Summary

    When the problem it solves isn't present yet: one implementation, no variation, or simple code that's easy to change later. Apply YAGNI and the rule of three, prefer language features (functions, named arguments, generators), and add the pattern when the variation becomes real.

    Longer Answer

    Each pattern adds indirection that readers must follow. A strategy interface with one implementation, a factory that only calls new, or a builder for a two-field object costs more than it saves. Refactoring toward a pattern later, with tests in place, is cheap when the need is real.

    Key Points

    • No problem, no pattern.
    • YAGNI and the rule of three.
    • Language features often replace patterns.
    • Refactor toward patterns when variation appears.

    Deep dive: Design Patterns, Explained Simply: Anti-Patterns and Over-Engineering

    Permalink

  18. Most asked Scenario: your checkout supports card and PayPal, and the business adds a new payment provider every quarter. How would you design it?

    Summary

    Use Strategy: a PaymentMethod interface with one implementation per provider, chosen through a lookup table or factory from the customer's choice. Wrap each vendor SDK in an Adapter so provider quirks stay out of checkout. New providers become new classes plus a registration line.

    Longer Answer

    Checkout depends only on PaymentMethod.charge(). Each provider's adapter handles units, idempotency keys, error mapping and webhooks for that vendor. Tests use a fake payment method. Selection lives in one place (a map from method name to implementation), so no if/else grows in checkout.

    Key Points

    • Strategy for interchangeable providers.
    • Adapter per vendor SDK.
    • Lookup table/factory for selection.
    • Checkout unchanged when providers are added.

    Deep dive: Design Patterns, Explained Simply: Capstone: Refactor a Tangled Checkout

    Permalink

  19. Most asked What are the three categories of Gang of Four design patterns?

    Summary

    Creational patterns deal with object creation (Factory Method, Abstract Factory, Builder, Prototype, Singleton), structural patterns with composing objects (Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy), and behavioral patterns with how objects communicate and share responsibilities (Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor, Interpreter).

    Longer Answer

    The 23 classic patterns split 5 / 7 / 11 across the three families. A quick way to remember them: creational answers "how do I create objects flexibly?", structural answers "how do I fit objects together?", and behavioral answers "how do objects divide work and talk to each other?".

    Modern codebases add patterns beyond the original 23, such as dependency injection, repository, middleware and pub/sub, which build on the same ideas.

    Key Points

    • Creational: 5 patterns about creating objects.
    • Structural: 7 patterns about composing objects.
    • Behavioral: 11 patterns about communication and responsibility.

    Deep dive: Design Patterns, Explained Simply: What a Design Pattern Is

    Permalink

  20. Most asked Explain the Liskov Substitution Principle with an example.

    Summary

    Subtypes must be usable wherever their parent type is expected, without breaking the parent's promises. The classic violation: Square extends Rectangle, where setting the height also changes the width, so code expecting area 5 x 4 = 20 gets 16.

    Longer Answer

    LSP is about behavioural compatibility, not vocabulary. A square "is a" rectangle in geometry, but not a correct subtype of a mutable Rectangle class whose contract says width and height change independently.

    Signs of violations: overridden methods that throw "not supported", stricter preconditions, weaker results, and callers that need instanceof checks. Fixes include modelling by shared behaviour (an immutable Shape with area()), or composition instead of inheritance.

    Key Points

    • Subtypes must keep the parent's contract.
    • Square/Rectangle is the classic violation.
    • Smells: 'not supported' overrides, instanceof checks.
    • Fix by modelling shared behaviour or composing.

    Deep dive: Design Patterns, Explained Simply: SOLID, Part 2

    Permalink

  21. Most asked What is the Facade pattern?

    Summary

    Facade provides one simple, task-focused interface to a complex subsystem. An OrderFacade.place_order() coordinates inventory, payments, shipping and email in the right order, so callers don't repeat that sequence.

    Longer Answer

    The subsystem classes keep working and remain available for advanced use; the facade is a convenience, not a wall. It reduces duplication and coupling to the subsystem's details, and it is a natural boundary when layering a system.

    Risk: a facade that does everything becomes a god object. Keep facades focused on one area.

    Key Points

    • Simple front door to a complex subsystem.
    • Coordinates calls in the right order.
    • Subsystem still usable directly.
    • Keep it focused to avoid a god object.

    Deep dive: Design Patterns, Explained Simply: Facade

    Permalink

  22. Most asked How would you implement undo/redo with the Command pattern?

    Summary

    Make each action an object with execute() and undo() that stores what it needs to reverse itself. An invoker runs commands and pushes them on a history stack; undo pops and calls undo() (moving the command to a redo stack); any new command clears the redo stack.

    Longer Answer

    The invoker never knows what a command does, so new actions (bold, paste) are new command classes. Commands are also how job queues work (a serialised command run later by a worker), and how macros and audit logs are built.

    For actions with external side effects (an email, a card charge), "undo" means a compensating action (a correction, a refund), not restoring previous state.

    Key Points

    • Command = action as an object with execute/undo.
    • History stack for undo, redo stack for redo.
    • New command clears redo.
    • External side effects need compensating actions.

    Deep dive: Design Patterns, Explained Simply: Command

    Permalink

  23. Most asked Compare Factory Method, Abstract Factory and Builder.

    Summary

    Factory Method creates one product, with the concrete class chosen by a subclass; Abstract Factory creates a matching family of related products through one factory object; Builder creates one complex product step by step with validation at the end.

    Longer Answer

    Choose Factory Method (or a simple factory) when the question is "which class?"; Abstract Factory when several objects must match (theme widgets, vendor drivers); Builder when the question is "how do I assemble this complex object readably?" (many optional parts, invalid combinations).

    They combine: an abstract factory can use builders internally, and a builder can be returned by a factory.

    Key Points

    • Factory Method: which class, via subclass.
    • Abstract Factory: matching families.
    • Builder: step-by-step assembly.

    Deep dive: Design Patterns, Explained Simply: Choosing the Right Pattern

    Permalink

  24. Most asked What is MVC, and which design patterns does it combine?

    Summary

    Model-View-Controller separates data and business rules (model), presentation (view) and input handling (controller). Classic MVC combines Observer (views observe the model), Strategy (the controller is the view's strategy for handling input) and Composite (nested views).

    Longer Answer

    Web frameworks (Rails, Laravel, Django's MTV, Spring MVC, ASP.NET MVC) adapt it: a controller handles an HTTP request, works with models, and renders a view or JSON. Variants include MVP and MVVM (data binding in Vue, Angular, WPF).

    The common pitfall is fat controllers; move business logic into models or services.

    Key Points

    • Model, view, controller separation.
    • Built from Observer, Strategy and Composite.
    • Web MVC is a request-based adaptation.
    • Avoid fat controllers.

    Permalink

  25. Most asked What is an anti-pattern? Name a few common ones.

    Summary

    An anti-pattern is a common response to a recurring problem that looks reasonable but usually causes more harm than good. Common ones: the god object, singleton used as a global variable, service locator, golden hammer (one favourite solution for everything), speculative generality, copy-paste programming and the anemic domain model.

    Longer Answer

    Recognising them matters as much as knowing patterns: a 3,000-line OrderManager (god object) or container.get() calls inside business classes (service locator) are more common than missing patterns. Each has a known remedy: split by responsibility, inject dependencies, start from the problem, wait for the second case.

    Key Points

    • Looks right, causes harm.
    • God object, singleton-as-global, service locator.
    • Golden hammer, speculative generality.
    • Each has a known remedy.

    Deep dive: Design Patterns, Explained Simply: Anti-Patterns and Over-Engineering

    Permalink

  26. Most asked Scenario: when an order is placed, several systems (email, inventory, analytics, loyalty) must react, and more will be added. How do you design it?

    Summary

    Publish an OrderPlaced event and let each system subscribe: Observer in-process, or Pub/Sub through a broker if the reactions are slow, unreliable or in other services. Order placement no longer knows its consumers.

    Longer Answer

    With a broker (SQS/SNS, Kafka, RabbitMQ), use the transactional outbox pattern so the event is published only if the order is committed, make subscribers idempotent (at-least-once delivery), and add dead-letter queues. In-process observers are fine for fast, reliable reactions in a monolith.

    Key Points

    • Event + subscribers.
    • Observer in-process, Pub/Sub across services.
    • Outbox for reliable publishing.
    • Idempotent subscribers and DLQs.

    Deep dive: Design Patterns, Explained Simply: Pub/Sub and the Event Bus

    Permalink

  27. What does the Single Responsibility Principle mean in practice?
  28. How do you apply the Open/Closed Principle?
  29. What kinds of Proxy are there, and what does each do?
  30. What is the State pattern? When would you use it?
  31. What is the Circuit Breaker pattern?
  32. How do you safely refactor existing code toward a design pattern?
  33. What is the Interface Segregation Principle?
  34. What does "program to an interface, not an implementation" mean?
  35. What are coupling and cohesion, and how do design patterns affect them?
  36. When would you use the Abstract Factory pattern?
  37. What is the Prototype pattern, and what is the main pitfall when implementing it?
  38. What is the Bridge pattern?
  39. Explain the Composite pattern with a real-world example.
  40. Explain Chain of Responsibility and give a web-development example.
  41. What is the Iterator pattern, and how do modern languages support it?
  42. What is the Template Method pattern?
  43. When would you use a Decorator instead of subclassing?
  44. Template Method or Strategy: how do you choose?
  45. Is HTTP middleware Chain of Responsibility or Decorator?
  46. What is the Unit of Work pattern?
  47. What is CQRS, and how does it relate to the Command pattern?
  48. Which design patterns do you see in React?
  49. Which design patterns do Laravel and Spring use internally?
  50. What is the Middleware (pipeline) pattern used for?
  51. How would you refactor a god object?
  52. Why is a service locator considered worse than dependency injection?
  53. Scenario: you need undo/redo in a drawing or text editor. Which pattern would you use?
  54. Scenario: a third-party SDK you must use has a completely different interface from the rest of your code. What do you do?
  55. Scenario: a class has a constructor with ten parameters, many optional. How would you improve it?
  56. Scenario: you need to add caching and logging to an existing service without modifying it. How?
  57. Scenario: every method of an `Order` class starts with a switch on `status`. How would you refactor it?
  58. How would you explain to a junior developer how to choose the right design pattern?
  59. What is the difference between Active Record and Data Mapper?
  60. Which design patterns does the Java standard library use?
  61. Which design patterns do Python features replace or simplify?
  62. Which design patterns do you use in PHP and Laravel day to day?
  63. Which design patterns are common in TypeScript and Node.js code?
  64. How do design patterns relate to testability?
  65. What is the Flyweight pattern, and when is it worth using?
  66. What is the Mediator pattern?
  67. What is the Memento pattern?
  68. What is the Visitor pattern, and what is its main trade-off?
  69. What is the Interpreter pattern?
  70. Command or Memento for undo: which would you use?
  71. How is Mediator different from Observer?
  72. What is the difference between Bridge and Adapter?
  73. How do Composite and Decorator differ, given both use recursive composition?
  74. When would you use a simple factory, and when a dependency injection container?
  75. What is the Null Object pattern, and when can it be harmful?
  76. What is the Specification pattern?
  77. Scenario: product categories contain products and subcategories to any depth, and you need totals per category. Which pattern fits?
  78. What is the Object Pool pattern, and where do you meet it?
  79. What is the Strangler Fig pattern, and how do design patterns help with it?
  80. Is it a good idea to name classes after patterns, such as `PaymentStrategy` or `UserFactory`?