SOLID and DRY Required
Keep the contract in every subtype
A subtype must work everywhere its parent type works. It may not demand more, promise less or throw "not supported".
How to do it
Before you extend a class, list what callers rely on. If the subtype cannot keep all of it, use a separate type or a smaller interface instead. Never override a method only to throw.
Example
// Bad: callers of Storage break on the read-only subtype
class ReadOnlyStorage extends Storage {
save(): void { throw new Error('not supported'); }
}
// Good: separate the roles, so nothing has to refuse
interface Reader { load(key: string): string; }
interface Writer { save(key: string, value: string): void; }
# Good in Python: two small protocols, so nothing has to refuse
class Reader(Protocol):
def load(self, key: str) -> str: ...
class Writer(Protocol):
def save(self, key: str, value: str) -> None: ...
How to check
Run the parent type's tests against every subtype. A grep for NotImplemented or "not supported" in overriding methods fails the build.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers architecture playbook: https://agentwranglers.se/playbook/architecture/solid-and-dry/liskov-substitution.