S: one responsibility per class (one reason to change); O: extend behavior without modifying existing code; L: subtypes must keep the contract of the base type; I: prefer small, focused interfaces; D: depend on abstractions, not concrete implementations (DI).