This is close to guaranteed to come up given how explicitly the email flags it. Have one crisp
sentence and one concrete micro-example ready per letter — not just the acronym expansion.
S — Single Responsibility: a class should have one reason to change. The DiscountService
in the email's example actually already respects SRP (it only calculates discounts) — its problem
is Open/Closed, which is the more subtle, more senior observation to make.
O — Open/Closed: open for extension, closed for modification. The if/else chain on
customerType means adding a new customer type requires editing DiscountService. The Strategy
refactor (see Design Patterns) fixes exactly this: adding VipDiscountStrategy requires zero changes
to existing code.
L — Liskov Substitution: a subtype must be usable anywhere its base type is expected without
breaking correctness. Classic violation: a Rectangle/Square inheritance where setting Square.Width
silently changes Height too, breaking code that assumed independent Width/Height on any Rectangle.
I — Interface Segregation: many small, focused interfaces beat one fat interface that forces
implementers to stub out methods they don't need. E.g. split IRepository with 15 methods into
IReadRepository / IWriteRepository if most consumers only ever read.
D — Dependency Inversion: depend on abstractions, not concretions — and both high- and
low-level modules depend on the abstraction, not one depending on the other directly. This is the
principle behind "prefer DI and composition over inheritance," which the email calls out explicitly
as the client's house style.
State the Open/Closed Principle in one sentence, and name the concrete smell that violates it in the email's DiscountService example.
tap to reveal answer
Software entities should be open for extension but closed for modification. The if/else chain on customerType means every new customer type requires editing DiscountService's existing code — that's the violation, more so than SRP.
What's the classic Liskov Substitution Principle violation example, and why does it actually break LSP?
tap to reveal answer
Square inheriting from Rectangle where setting Width also changes Height (to stay square) — it breaks any code that relied on a Rectangle's Width and Height being independently settable, so Square isn't truly substitutable for Rectangle.
What does Interface Segregation actually push you toward in practice?
tap to reveal answer
Splitting one large interface into several small, cohesive ones so implementers/consumers only depend on the methods they actually use — avoids forcing classes to implement methods they don't need (often via NotImplementedException, a smell).
State Dependency Inversion precisely — not just 'use interfaces'.
tap to reveal answer
High-level modules should not depend on low-level modules; both should depend on abstractions. And: abstractions should not depend on details; details should depend on abstractions. It's about who owns the interface, not just that one exists.
Why does the client's stated preference for 'DI and composition over inheritance' map onto SOLID?
tap to reveal answer
It's Dependency Inversion (depend on injected abstractions) combined with avoiding LSP risk — composition (has-a, via an injected interface) doesn't create the tight coupling and substitutability contract that inheritance (is-a) does, so it's harder to accidentally violate LSP or OCP.
Which SOLID principle does the Strategy Pattern most directly serve, and why?
tap to reveal answer
Open/Closed — new strategies (e.g. new discount types) are added as new classes implementing the shared interface, with zero modification to the code that consumes the strategy.