# SOLID / Object-Oriented Design

> Every principle in this category is listed as a record.

Page: Ontology · Principles
Canonical: https://banes-lab.com/ontology#arch-category-solid-object-oriented-design

Every principle in this category is listed as a record. Each record carries its kind, its severity, the scopes it applies at and the layer it lives in, then the edge relations that join it to other records, the records that point back at it, the contracts that answer to it and the tensions it takes part in. The descriptors say how it is violated, detected, measured, repaired and enforced. Where the record carries one, an exemplar shows the shape before and after the principle is applied.

Relations diagram

The relations inside this category.

```mermaid
flowchart LR
n_interface_segregation["Interface Segregation Principle (ISP)"]
n_dependency_inversion["Dependency Inversion Principle (DIP)"]
n_open_closed["Open/Closed Principle (OCP)"]
n_liskov_substitution["Liskov Substitution Principle (LSP)"]
n_polymorphism["Polymorphism"]
n_liskov_substitution --> n_polymorphism
n_polymorphism --> n_open_closed
```

### Interface Segregation Principle (ISP)

- Kind: [principle](https://banes-lab.com/records/kind/principle.md)
- Severity: mandatory
- Scope: interface, service, module
- Layer: [Structural Core](https://banes-lab.com/records/layer/structural-core.md)

Details

Requires
[Role-Specific Interfaces](https://banes-lab.com/records/lex/role-specific-interfaces.md)

Reinforces
[Single Responsibility Principle (SRP)](https://banes-lab.com/records/arch/single-responsibility.md), [Low Coupling](https://banes-lab.com/records/arch/low-coupling.md)

Enables
[Consumer-Specific Contracts](https://banes-lab.com/records/lex/consumer-specific-contracts.md)

In tension with
[Interface Proliferation](https://banes-lab.com/records/lex/interface-proliferation.md)

Conflicts with
[Fat Interface](https://banes-lab.com/records/lex/fat-interface.md), [Repository Dump](https://banes-lab.com/records/arch/repository-dump.md)

Tensions
[Interface Segregation Principle (ISP) Interface Proliferation](https://banes-lab.com/records/tension/interface-proliferation-interface-segregation-principle-isp.md)

Violated by
clients depending on unused methods

Detected by
unused interface method implementations

Measured by
interface method usage ratio

Refactored by
Split Interface, Extract Role Interface

Enforced by
interface usage analysis, lint rules

Before

```typescript
interface FooWorker {
load(id: FooId): Foo;
save(foo: Foo): void;
delete(id: FooId): void;
export(): string;
}
class FooReader implements FooWorker {}
```

After

```typescript
interface FooReader { load(id: FooId): Foo; }
interface FooWriter { save(foo: Foo): void; }
interface FooRemover { delete(id: FooId): void; }
class CachedFooReader implements FooReader {
load(id: FooId) { return fooCache.get(id)!; }
}
```

### Dependency Inversion Principle (DIP)

- Kind: [principle](https://banes-lab.com/records/kind/principle.md)
- Severity: mandatory
- Scope: module, component, layer
- Aliases: DIP
- Layer: [Structural Core](https://banes-lab.com/records/layer/structural-core.md)

Details

Requires
[Abstraction](https://banes-lab.com/records/arch/abstraction.md), [Stable Interfaces](https://banes-lab.com/records/arch/stable-interfaces.md)

Reinforces
[Low Coupling](https://banes-lab.com/records/arch/low-coupling.md), [Clean Architecture](https://banes-lab.com/records/arch/clean-architecture.md)

Enables
[Dependency Injection](https://banes-lab.com/records/arch/dependency-injection.md), [Ports and Adapters](https://banes-lab.com/records/lex/ports-and-adapters.md)

In tension with
[Runtime Indirection](https://banes-lab.com/records/lex/runtime-indirection.md)

Conflicts with
[Concrete Dependency](https://banes-lab.com/records/lex/concrete-dependency.md)

Referenced by
[Ports and Adapters Architecture](https://banes-lab.com/records/arch/ports-and-adapters-architecture.md), [Clean Architecture](https://banes-lab.com/records/arch/clean-architecture.md), [Interface-Based Design](https://banes-lab.com/records/arch/interface-based-design.md), [Abstraction](https://banes-lab.com/records/arch/abstraction.md), [Replaceability](https://banes-lab.com/records/arch/replaceability.md), [Testability](https://banes-lab.com/records/arch/testability.md), [Inversion of Control (IoC)](https://banes-lab.com/records/arch/inversion-of-control.md), [Dependency Injection](https://banes-lab.com/records/arch/dependency-injection.md), [Service Locator Pattern](https://banes-lab.com/records/arch/service-locator-pattern.md)

Tensions
[Dependency Inversion Principle (DIP) Runtime Indirection](https://banes-lab.com/records/tension/dependency-inversion-principle-dip-runtime-indirection.md)

Violated by
domain importing infrastructure

Detected by
dependency direction violations

Measured by
inward dependency ratio

Refactored by
Extract Interface, Introduce Port, Inject Dependency

Enforced by
dependency graph rules, architecture tests

Before

```typescript
class FooService {
private readonly store = new SqlFooStore();
save(foo: Foo) { return this.store.save(foo); }
}
```

After

```typescript
interface FooStore { save(foo: Foo): Promise<void>; }
class FooService {
constructor(private readonly store: FooStore) {}
save(foo: Foo) { return this.store.save(foo); }
}
```

### Open/Closed Principle (OCP)

- Kind: [principle](https://banes-lab.com/records/kind/principle.md)
- Severity: recommended
- Scope: class, module, component
- Aliases: OCP
- Layer: [Structural Core](https://banes-lab.com/records/layer/structural-core.md)

Details

Requires
[Abstraction](https://banes-lab.com/records/arch/abstraction.md), [Extension Points](https://banes-lab.com/records/arch/extension-points.md)

Reinforces
[Plugin Architecture](https://banes-lab.com/records/arch/plugin-architecture.md), [Strategy Pattern](https://banes-lab.com/records/arch/strategy-pattern.md)

Enables
[Feature Extension without Modification](https://banes-lab.com/records/lex/feature-extension-without-modification.md)

In tension with
[Simplicity](https://banes-lab.com/records/lex/simplicity.md)

Conflicts with
[Switch-Based Extension](https://banes-lab.com/records/lex/switch-based-extension.md)

Referenced by
[Strategy Pattern](https://banes-lab.com/records/arch/strategy-pattern.md), [Command Pattern](https://banes-lab.com/records/arch/command-pattern.md), [State Pattern](https://banes-lab.com/records/arch/state-pattern.md), [Chain of Responsibility Pattern](https://banes-lab.com/records/arch/chain-of-responsibility-pattern.md), [Visitor Pattern](https://banes-lab.com/records/arch/visitor-pattern.md), [Factory Pattern](https://banes-lab.com/records/arch/factory-pattern.md), [Factory Method Pattern](https://banes-lab.com/records/arch/factory-method-pattern.md), [Plugin Architecture](https://banes-lab.com/records/arch/plugin-architecture.md), [Extension Points](https://banes-lab.com/records/arch/extension-points.md), [Dynamic Dispatch](https://banes-lab.com/records/arch/dynamic-dispatch.md), [Runtime Extensibility](https://banes-lab.com/records/arch/runtime-extensibility.md), [Polymorphism](https://banes-lab.com/records/arch/polymorphism.md), [Decorator Pattern](https://banes-lab.com/records/arch/decorator-pattern.md), [Composite Pattern](https://banes-lab.com/records/arch/composite-pattern.md)

Tensions
[Open/Closed Principle (OCP) Simplicity](https://banes-lab.com/records/tension/open-closed-principle-ocp-simplicity.md)

Violated by
repeated modification of stable core for variants

Detected by
growing conditionals, repeated edits to central classes

Measured by
modification frequency of core modules

Refactored by
Extract Strategy, Add Extension Point, Introduce Plugin

Enforced by
extension policies, change analysis

Before

```typescript
function priceFoo(kind: string, value: number) {
if (kind === "foo") return value;
if (kind === "bar") return value * 2;
throw new Error("unknown kind");
}
```

After

```typescript
interface FooPricing { price(value: number): number; }
const registry = new Map<string, FooPricing>();
export function registerPricing(kind: string, pricing: FooPricing) { registry.set(kind, pricing); }
export function priceFoo(kind: string, value: number) {
const pricing = registry.get(kind);
if (!pricing) throw new Error(`unknown kind ${kind}`);
return pricing.price(value);
}
registerPricing("bar", { price: value => value * 2 });
```

### Liskov Substitution Principle (LSP)

- Kind: [principle](https://banes-lab.com/records/kind/principle.md)
- Severity: mandatory
- Scope: class, interface, type hierarchy
- Aliases: LSP
- Layer: [Structural Core](https://banes-lab.com/records/layer/structural-core.md)

Details

Requires
[Contract Preservation](https://banes-lab.com/records/lex/contract-preservation.md), [Preconditions](https://banes-lab.com/records/arch/preconditions.md), [Postconditions](https://banes-lab.com/records/arch/postconditions.md), [Invariants](https://banes-lab.com/records/arch/invariants.md)

Reinforces
[Polymorphism](https://banes-lab.com/records/arch/polymorphism.md), [Type Safety](https://banes-lab.com/records/arch/type-safety.md)

Enables
[Safe Substitution](https://banes-lab.com/records/lex/safe-substitution.md), [Substitutability](https://banes-lab.com/records/lex/substitutability.md)

In tension with
[Narrow Specialized Behavior](https://banes-lab.com/records/lex/narrow-specialized-behavior.md)

Conflicts with
[Broken Inheritance](https://banes-lab.com/records/lex/broken-inheritance.md), [Incompatible Override](https://banes-lab.com/records/lex/incompatible-override.md)

Referenced by
[Design by Contract](https://banes-lab.com/records/arch/design-by-contract.md)

Tensions
[Liskov Substitution Principle (LSP) Narrow Specialized Behavior](https://banes-lab.com/records/tension/liskov-substitution-principle-lsp-narrow-specialized-behavior.md)

Violated by
subclass weakening postconditions or strengthening preconditions

Detected by
overridden method contract divergence

Measured by
contract test pass rate across subtypes

Refactored by
Replace Inheritance, Extract Interface, Split Hierarchy

Enforced by
contract tests, type tests

Before

```typescript
class FooStore {
save(foo: Foo): Promise<Receipt> { return persist(foo); }
}
class ReadOnlyFooStore extends FooStore {
save(): Promise<Receipt> { throw new Error("not supported"); }
}
```

After

```typescript
class FooStore {
save(foo: Foo): Promise<Receipt> { return persist(foo); }
}
class AuditedFooStore extends FooStore {
async save(foo: Foo): Promise<Receipt> {
const receipt = await super.save(foo);
audit.record(receipt);
return receipt;
}
}
```

### Polymorphism

- Kind: [mechanism](https://banes-lab.com/records/kind/mechanism.md)
- Severity: recommended
- Scope: class, interface, runtime
- Layer: [Structural Core](https://banes-lab.com/records/layer/structural-core.md)

Details

Requires
[Abstraction](https://banes-lab.com/records/arch/abstraction.md), [Substitutability](https://banes-lab.com/records/lex/substitutability.md)

Reinforces
[Open/Closed Principle (OCP)](https://banes-lab.com/records/arch/open-closed.md), [Strategy Pattern](https://banes-lab.com/records/arch/strategy-pattern.md)

Enables
[Dynamic Dispatch](https://banes-lab.com/records/arch/dynamic-dispatch.md), [Interchangeability](https://banes-lab.com/records/arch/interchangeability.md)

In tension with
[Traceability](https://banes-lab.com/records/arch/traceability.md)

Conflicts with
[Type Switching](https://banes-lab.com/records/lex/type-switching.md)

Referenced by
[Strategy Pattern](https://banes-lab.com/records/arch/strategy-pattern.md), [State Pattern](https://banes-lab.com/records/arch/state-pattern.md), [Null Object Pattern](https://banes-lab.com/records/arch/null-object-pattern.md), [Abstraction](https://banes-lab.com/records/arch/abstraction.md), [Interchangeability](https://banes-lab.com/records/arch/interchangeability.md), [Dynamic Binding](https://banes-lab.com/records/arch/dynamic-binding.md), [Dynamic Dispatch](https://banes-lab.com/records/arch/dynamic-dispatch.md), [Liskov Substitution Principle (LSP)](https://banes-lab.com/records/arch/liskov-substitution.md)

Tensions
[Polymorphism Traceability](https://banes-lab.com/records/tension/polymorphism-traceability.md)

Violated by
instanceof/switch dispatch over types

Detected by
conditional type checks, duplicated branching

Measured by
polymorphic dispatch ratio

Refactored by
[Replace Conditional with Polymorphism](https://banes-lab.com/records/lex/replace-conditional-with-polymorphism.md)

Enforced by
[code review](https://banes-lab.com/records/arch/code-review.md), static analysis rules

Before

```typescript
function renderFoo(kind: string, foo: Foo) {
if (kind === "text") return foo.name;
if (kind === "json") return JSON.stringify(foo);
throw new Error("unknown renderer");
}
```

After

```typescript
interface FooRenderer { render(foo: Foo): string; }
class TextFooRenderer implements FooRenderer { render(foo: Foo) { return foo.name; } }
class JsonFooRenderer implements FooRenderer { render(foo: Foo) { return JSON.stringify(foo); } }
function renderFoo(renderer: FooRenderer, foo: Foo) { return renderer.render(foo); }
```

## Links to

- [principle](https://banes-lab.com/records/kind/principle.md)
- [Structural Core](https://banes-lab.com/records/layer/structural-core.md)
- [Role-Specific Interfaces](https://banes-lab.com/records/lex/role-specific-interfaces.md)
- [Single Responsibility Principle (SRP)](https://banes-lab.com/records/arch/single-responsibility.md)
- [Low Coupling](https://banes-lab.com/records/arch/low-coupling.md)
- [Consumer-Specific Contracts](https://banes-lab.com/records/lex/consumer-specific-contracts.md)
- [Interface Proliferation](https://banes-lab.com/records/lex/interface-proliferation.md)
- [Fat Interface](https://banes-lab.com/records/lex/fat-interface.md)
- [Repository Dump](https://banes-lab.com/records/arch/repository-dump.md)
- [Interface Segregation Principle (ISP) / Interface Proliferation](https://banes-lab.com/records/tension/interface-proliferation-interface-segregation-principle-isp.md)
- [Abstraction](https://banes-lab.com/records/arch/abstraction.md)
- [Stable Interfaces](https://banes-lab.com/records/arch/stable-interfaces.md)
- [Clean Architecture](https://banes-lab.com/records/arch/clean-architecture.md)
- [Dependency Injection](https://banes-lab.com/records/arch/dependency-injection.md)
- [Ports and Adapters](https://banes-lab.com/records/lex/ports-and-adapters.md)
- [Runtime Indirection](https://banes-lab.com/records/lex/runtime-indirection.md)
- [Concrete Dependency](https://banes-lab.com/records/lex/concrete-dependency.md)
- [Ports and Adapters Architecture](https://banes-lab.com/records/arch/ports-and-adapters-architecture.md)
- [Interface-Based Design](https://banes-lab.com/records/arch/interface-based-design.md)
- [Replaceability](https://banes-lab.com/records/arch/replaceability.md)
- [Testability](https://banes-lab.com/records/arch/testability.md)
- [Inversion of Control (IoC)](https://banes-lab.com/records/arch/inversion-of-control.md)
- [Service Locator Pattern](https://banes-lab.com/records/arch/service-locator-pattern.md)
- [Dependency Inversion Principle (DIP) / Runtime Indirection](https://banes-lab.com/records/tension/dependency-inversion-principle-dip-runtime-indirection.md)
- [Extension Points](https://banes-lab.com/records/arch/extension-points.md)
- [Plugin Architecture](https://banes-lab.com/records/arch/plugin-architecture.md)
- [Strategy Pattern](https://banes-lab.com/records/arch/strategy-pattern.md)
- [Feature Extension without Modification](https://banes-lab.com/records/lex/feature-extension-without-modification.md)
- [Simplicity](https://banes-lab.com/records/lex/simplicity.md)
- [Switch-Based Extension](https://banes-lab.com/records/lex/switch-based-extension.md)
- [Command Pattern](https://banes-lab.com/records/arch/command-pattern.md)
- [State Pattern](https://banes-lab.com/records/arch/state-pattern.md)
- [Chain of Responsibility Pattern](https://banes-lab.com/records/arch/chain-of-responsibility-pattern.md)
- [Visitor Pattern](https://banes-lab.com/records/arch/visitor-pattern.md)
- [Factory Pattern](https://banes-lab.com/records/arch/factory-pattern.md)
- [Factory Method Pattern](https://banes-lab.com/records/arch/factory-method-pattern.md)
- [Dynamic Dispatch](https://banes-lab.com/records/arch/dynamic-dispatch.md)
- [Runtime Extensibility](https://banes-lab.com/records/arch/runtime-extensibility.md)
- [Polymorphism](https://banes-lab.com/records/arch/polymorphism.md)
- [Decorator Pattern](https://banes-lab.com/records/arch/decorator-pattern.md)
- [Composite Pattern](https://banes-lab.com/records/arch/composite-pattern.md)
- [Open/Closed Principle (OCP) / Simplicity](https://banes-lab.com/records/tension/open-closed-principle-ocp-simplicity.md)
- [Contract Preservation](https://banes-lab.com/records/lex/contract-preservation.md)
- [Preconditions](https://banes-lab.com/records/arch/preconditions.md)
- [Postconditions](https://banes-lab.com/records/arch/postconditions.md)
- [Invariants](https://banes-lab.com/records/arch/invariants.md)
- [Type Safety](https://banes-lab.com/records/arch/type-safety.md)
- [Safe Substitution](https://banes-lab.com/records/lex/safe-substitution.md)
- [Substitutability](https://banes-lab.com/records/lex/substitutability.md)
- [Narrow Specialized Behavior](https://banes-lab.com/records/lex/narrow-specialized-behavior.md)
- [Broken Inheritance](https://banes-lab.com/records/lex/broken-inheritance.md)
- [Incompatible Override](https://banes-lab.com/records/lex/incompatible-override.md)
- [Design by Contract](https://banes-lab.com/records/arch/design-by-contract.md)
- [Liskov Substitution Principle (LSP) / Narrow Specialized Behavior](https://banes-lab.com/records/tension/liskov-substitution-principle-lsp-narrow-specialized-behavior.md)
- [mechanism](https://banes-lab.com/records/kind/mechanism.md)
- [Open/Closed Principle (OCP)](https://banes-lab.com/records/arch/open-closed.md)
- [Interchangeability](https://banes-lab.com/records/arch/interchangeability.md)
- [Traceability](https://banes-lab.com/records/arch/traceability.md)
- [Type Switching](https://banes-lab.com/records/lex/type-switching.md)
- [Null Object Pattern](https://banes-lab.com/records/arch/null-object-pattern.md)
- [Dynamic Binding](https://banes-lab.com/records/arch/dynamic-binding.md)
- [Liskov Substitution Principle (LSP)](https://banes-lab.com/records/arch/liskov-substitution.md)
- [Polymorphism / Traceability](https://banes-lab.com/records/tension/polymorphism-traceability.md)
- [Replace Conditional with Polymorphism](https://banes-lab.com/records/lex/replace-conditional-with-polymorphism.md)
- [Code Review](https://banes-lab.com/records/arch/code-review.md)

## Linked from

- [The layer topology](https://banes-lab.com/ontology/schema/the-layer-topology.md)
- [The membership](https://banes-lab.com/ontology/schema/the-membership.md)
