Chapter 25: Quiz — Design Patterns and Clean Code
Test your understanding of design patterns, clean code principles, and AI-specific idioms. Each question has one best answer unless otherwise noted.
Question 1
Which design pattern delegates object creation to a separate function or method, decoupling client code from concrete class instantiation?
- A) Observer
- B) Strategy
- C) Factory
- D) Decorator
Answer
**C) Factory.** The Factory pattern's core purpose is to encapsulate object creation, so client code requests objects through the factory rather than instantiating concrete classes directly. This decouples the client from specific implementations.Question 2
In Python, what is the most idiomatic way to implement a Singleton?
- A) Override
__new__with a class variable - B) Use a metaclass with
__call__override - C) Use a module-level instance
- D) Use a decorator that caches the first instance
Answer
**C) Use a module-level instance.** Python modules are themselves singletons—imported once and cached in `sys.modules`. Creating an instance at module level is the simplest and most Pythonic approach to the Singleton pattern. The other options work but add unnecessary complexity.Question 3
What is the key difference between typing.Protocol and abc.ABC in Python?
- A) Protocol is faster at runtime
- B) Protocol uses structural subtyping; ABC uses nominal subtyping
- C) Protocol supports multiple inheritance; ABC does not
- D) Protocol is only available in Python 3.11+
Answer
**B) Protocol uses structural subtyping; ABC uses nominal subtyping.** A class satisfies a Protocol if it has the right methods, regardless of inheritance. A class satisfies an ABC only if it explicitly inherits from it. Protocol was introduced in Python 3.8.Question 4
Which pattern would you use to make an old payment library work with your new application's expected interface?
- A) Facade
- B) Strategy
- C) Adapter
- D) Builder
Answer
**C) Adapter.** The Adapter pattern converts one interface into another that the client expects. A Facade simplifies a complex interface but does not change it to match an expected contract. The Adapter specifically bridges interface incompatibilities.Question 5
What is the primary difference between a Python decorator (language feature) and the GoF Decorator pattern?
- A) They are completely unrelated concepts
- B) Python decorators wrap functions; GoF Decorators wrap objects with additional behavior through composition
- C) Python decorators are faster
- D) GoF Decorators cannot be used in Python
Answer
**B) Python decorators wrap functions; GoF Decorators wrap objects with additional behavior through composition.** They are related concepts—both add behavior by wrapping—but Python decorators are syntactic sugar for function/class wrapping, while GoF Decorators use composition to dynamically add responsibilities to objects at runtime.Question 6
Which clean code principle is violated when the same validation logic appears in both create_user() and update_user() functions?
- A) KISS
- B) DRY
- C) YAGNI
- D) Boy Scout Rule
Answer
**B) DRY (Don't Repeat Yourself).** When the same logic is duplicated across multiple functions, a change to that logic must be made in all locations, increasing the risk of inconsistency and bugs. The remedy is to extract the shared logic into a single function.Question 7
In the Strategy pattern, what is the Pythonic way to represent simple, stateless strategies?
- A) Abstract base classes with concrete subclasses
- B) Plain functions passed as arguments
- C) Enum members with behavior
- D) Dictionary of class instances
Answer
**B) Plain functions passed as arguments.** Python's first-class functions eliminate the need for a strategy class hierarchy in most cases. When strategies are stateless, a function with a matching signature is the simplest and most Pythonic implementation.Question 8
What code smell is present when a function takes eight positional parameters?
- A) Feature Envy
- B) Long Method
- C) Long Parameter List
- D) Primitive Obsession
Answer
**C) Long Parameter List.** Functions with more than 3–4 parameters become difficult to call correctly. The typical remedy is to introduce a Parameter Object (in Python, a dataclass) that groups related parameters into a single coherent object.Question 9
Which AI-specific pattern separates the structure of a prompt from its variable content?
- A) Output Parser
- B) Conversation Manager
- C) Prompt Template
- D) Retry with Fallback
Answer
**C) Prompt Template.** The Prompt Template pattern uses a template string with placeholders that are filled in with variable data at runtime. This separates the prompt's structure from its content, making prompts reusable and maintainable.Question 10
What is the primary purpose of the Facade pattern?
- A) To convert one interface to another
- B) To provide a simplified interface to a complex subsystem
- C) To add new behavior to objects dynamically
- D) To ensure only one instance of a class exists
Answer
**B) To provide a simplified interface to a complex subsystem.** The Facade does not add new functionality; it provides a convenient entry point that shields clients from the complexity of the underlying subsystem. Unlike the Adapter, it does not change the interface to match a different contract—it simplifies.Question 11
When should you apply the YAGNI principle to a design pattern?
- A) Never—patterns always improve code quality
- B) When the pattern solves a hypothetical future problem with no current evidence of need
- C) Only during code review
- D) Only when working with legacy code
Answer
**B) When the pattern solves a hypothetical future problem with no current evidence of need.** YAGNI advises against premature abstraction. If a pattern addresses a real, current problem, use it. If it addresses a problem that *might* occur someday, wait until there is evidence it is actually needed.Question 12
What makes a frozen=True dataclass useful as a value object?
- A) It is faster to instantiate
- B) It is immutable, providing hashability and preventing accidental modification
- C) It uses less memory
- D) It automatically validates its fields
Answer
**B) It is immutable, providing hashability and preventing accidental modification.** Frozen dataclasses cannot be modified after creation, which makes them safe to use as dictionary keys, set members, and event objects that should not be altered by handlers.Question 13
Which code smell is AI-generated code most likely to exhibit?
- A) Feature Envy
- B) Over-commenting obvious code
- C) Shotgun Surgery
- D) Refused Bequest
Answer
**B) Over-commenting obvious code.** AI assistants frequently add comments that merely restate what the code does (e.g., "# Initialize empty list" before `results = []`). The remedy is to remove comments that do not add information beyond what the code itself communicates.Question 14
In the Command pattern, what feature does storing executed commands in a history list enable?
- A) Faster execution
- B) Undo and redo operations
- C) Automatic logging
- D) Thread safety
Answer
**B) Undo and redo operations.** By encapsulating operations as command objects with `execute()` and `undo()` methods, and maintaining a history stack, the Command pattern enables undoing the most recent operation and redoing previously undone operations.Question 15
What is "Java-in-Python syndrome"?
- A) Using Java's JVM to run Python code
- B) Writing Python code using verbose Java patterns instead of idiomatic Python
- C) Importing Java libraries in Python
- D) Using static typing in Python
Answer
**B) Writing Python code using verbose Java patterns instead of idiomatic Python.** This includes wrapping standalone functions in unnecessary classes, using getter/setter methods instead of properties, and creating verbose class hierarchies where Python's simpler features (functions, protocols, dataclasses) would suffice.Question 16
Which combination of patterns is typically used to build an extensible plugin architecture?
- A) Singleton and Adapter
- B) Factory and Observer
- C) Builder and Decorator
- D) Strategy and Command
Answer
**B) Factory and Observer.** The Factory pattern handles plugin creation/discovery, while the Observer pattern allows plugins to communicate through events without tight coupling. This combination provides both extensibility (new plugins) and loose coupling (event-based communication).Question 17
What does the Output Parser pattern address in AI-powered applications?
- A) Formatting prompts before sending to the AI model
- B) Extracting structured data from unstructured AI-generated text
- C) Managing conversation history
- D) Selecting which AI model to use
Answer
**B) Extracting structured data from unstructured AI-generated text.** AI models return text that may contain JSON embedded in markdown code fences, numbered lists, or other unstructured formats. The Output Parser extracts and normalizes this data into Python objects.Question 18
The "Rule of Three" suggests that you should:
- A) Never have more than three classes in a hierarchy
- B) Wait for three instances of duplication before extracting an abstraction
- C) Limit functions to three parameters
- D) Use at most three design patterns per module
Answer
**B) Wait for three instances of duplication before extracting an abstraction.** Two instances might be coincidence; three instances represent a true pattern worth abstracting. This rule prevents premature generalization while still catching genuine duplication.Question 19
Which refactoring step should come FIRST when transforming a large if-elif chain into a Strategy pattern?
- A) Create a strategy registry dictionary
- B) Extract each branch into a separate function
- C) Define a Protocol for the strategy interface
- D) Add a registration function for new strategies
Answer
**B) Extract each branch into a separate function.** The safest refactoring sequence is: (1) extract each branch into its own function, (2) create a registry dictionary mapping keys to functions, (3) replace the conditional with dictionary dispatch. Starting with extraction preserves behavior while making the code more modular.Question 20
What is the primary advantage of using dictionary dispatch over if-elif chains in a Factory?
- A) It is always faster
- B) It is more readable
- C) New types can be added without modifying the factory function
- D) It uses less memory
Answer
**C) New types can be added without modifying the factory function.** With dictionary dispatch, adding a new type means adding an entry to the dictionary (or calling a registration function). With `if-elif`, you must modify the function body itself, violating the Open/Closed Principle.Question 21
Which sign indicates that you are over-engineering with patterns?
- A) The code handles multiple concrete implementations
- B) You have an interface with only one implementation and no foreseeable need for more
- C) The code is easy to test with dependency injection
- D) New features require adding new classes rather than modifying existing ones
Answer
**B) You have an interface with only one implementation and no foreseeable need for more.** If there is only one concrete implementation and the requirements do not suggest future alternatives, the abstraction adds indirection without benefit. This is speculative generality—building for a future that may never arrive.Question 22
In the Observer pattern, why should event objects be immutable (using frozen=True dataclasses)?
- A) Immutable objects are faster to create
- B) Handlers might inadvertently modify the event, affecting subsequent handlers
- C) Python requires event objects to be hashable
- D) Immutable objects use less memory
Answer
**B) Handlers might inadvertently modify the event, affecting subsequent handlers.** When multiple observers receive the same event object, a mutation by one observer would be visible to all subsequent observers. Immutable events prevent this category of bugs entirely.Question 23
What is the Retry with Fallback pattern in AI applications?
- A) Retrying the same prompt with different wording
- B) Combining retry logic with the ability to fall back to alternative AI models
- C) Caching previous responses to avoid repeat API calls
- D) Using multiple prompts in parallel and taking the best result
Answer
**B) Combining retry logic with the ability to fall back to alternative AI models.** This pattern first retries the primary model with exponential backoff. If all retries fail, it falls back to alternative models. This provides resilience against API outages, rate limits, and transient failures.Question 24
Which clean code practice is MOST important when reviewing AI-generated code?
- A) Ensuring all classes use inheritance
- B) Verifying that naming is descriptive and consistent
- C) Adding comments to every line
- D) Converting all functions to class methods
Answer
**B) Verifying that naming is descriptive and consistent.** Clear naming is the single most impactful clean code practice. AI-generated code sometimes uses generic names like `data`, `result`, or `temp`. Renaming to reveal intent (`filtered_orders`, `monthly_revenue`, `retry_delay`) dramatically improves readability.Question 25
A developer creates an AbstractNotificationFactoryBuilderStrategy class. Which principle is most clearly being violated?
- A) DRY
- B) KISS
- C) SRP
- D) Open/Closed