# configuration/principle/data/design.solid.data.json

> 268 lines of code and 0 definitions.

Tree: GovLab Context
Language: json
Layer: domain
Canonical: https://banes-lab.com/anatomy/context#file-context-configuration-principle-data-design-solid-data-json
Source text: https://banes-lab.com/source/context/configuration/principle/data/design.solid.data.json.txt

Listed in [configuration/principle/data](https://banes-lab.com/api/source/context/configuration/principle/data.md), after [configuration/principle/data/design.modular.data.json](https://banes-lab.com/source/context/configuration/principle/data/design.modular.data.json.md) and before [configuration/principle/data/event.data.json](https://banes-lab.com/source/context/configuration/principle/data/event.data.json.md).

## Contained in

- [configuration/principle/data](https://banes-lab.com/anatomy/context/folder-context-configuration-principle-data.md)

## Source

```json
{
    "category": "SOLID / Object-Oriented Design",
    "check": {
        "population": "every interface, class hierarchy and dependency edge in the object model",
        "freshness": "a verdict stands until an interface, an override or a dependency changes",
        "refusal": "the dependency rule or the contract test fails a change that breaks substitution, segregation or dependency direction",
        "observation": "interface usage, override contracts and dependency direction, read from source and contract tests",
        "evidence": "none: the catalog states this check as a class, so a watched run belongs to each system that adopts it",
        "authority": "the interface contract, which every implementation and override conforms to"
    },
    "records": [
        {
            "id": "interface-segregation",
            "aliases": [
                "ISP",
                "Interface Segregation Principle"
            ],
            "name": "Interface Segregation Principle (ISP)",
            "definition": "A design rule that a client depends on an interface holding only the methods it uses.",
            "type": "principle",
            "scope": [
                "interface",
                "service",
                "module"
            ],
            "requires": ["Role-Specific Interfaces"],
            "reinforces": [
                "SRP",
                "Low Coupling"
            ],
            "enables": ["Consumer-Specific Contracts"],
            "conflicts_with": [
                "Fat Interface",
                "Repository Dump"
            ],
            "tensions_with": ["Interface Proliferation"],
            "violated_by": ["lexicon:fat-interface"],
            "detected_by": ["unused interface method implementations"],
            "measured_by": ["interface method usage ratio"],
            "refactored_by": [
                "lexicon:split-interface",
                "lexicon:extract-role-interface"
            ],
            "enforced_by": [
                "interface usage analysis",
                "lint rules"
            ],
            "severity": "mandatory",
            "exemplar": {
                "before": "interface FooWorker {\n  load(id: FooId): Foo;\n  save(foo: Foo): void;\n  delete(id: FooId): void;\n  export(): string;\n}\nclass FooReader implements FooWorker {}",
                "after": "interface FooReader { load(id: FooId): Foo; }\ninterface FooWriter { save(foo: Foo): void; }\ninterface FooRemover { delete(id: FooId): void; }\nclass CachedFooReader implements FooReader {\n  load(id: FooId) { return fooCache.get(id)!; }\n}",
                "lang": "ts"
            }
        },
        {
            "id": "dependency-inversion",
            "distinctFrom": [
                {
                    "id": "architecture:inversion-of-control",
                    "reason": "Dependency inversion fixes which side owns the abstraction, while inversion of control moves object creation and control flow to a framework or composition root."
                }
            ],
            "aliases": [
                "DIP",
                "Dependency Inversion Principle"
            ],
            "name": "Dependency Inversion Principle (DIP)",
            "definition": "A design rule that high-level policy and low-level detail both depend on an abstraction owned by the policy.",
            "type": "principle",
            "scope": [
                "module",
                "component",
                "layer"
            ],
            "requires": [
                "Abstraction",
                "Stable Interfaces"
            ],
            "reinforces": [
                "Low Coupling",
                "Clean Architecture"
            ],
            "enables": [
                "Dependency Injection",
                "Ports and Adapters"
            ],
            "conflicts_with": ["Concrete Dependency"],
            "tensions_with": ["Runtime Indirection"],
            "violated_by": ["architecture:concrete-coupling"],
            "detected_by": ["dependency direction violations"],
            "measured_by": ["inward dependency ratio"],
            "refactored_by": [
                "lexicon:extract-interface",
                "lexicon:introduce-port",
                "architecture:dependency-injection"
            ],
            "enforced_by": [
                "dependency graph rules",
                "architecture tests"
            ],
            "severity": "mandatory",
            "exemplar": {
                "before": "class FooService {\n  private readonly store = new SqlFooStore();\n  save(foo: Foo) { return this.store.save(foo); }\n}",
                "after": "interface FooStore { save(foo: Foo): Promise<void>; }\nclass FooService {\n  constructor(private readonly store: FooStore) {}\n  save(foo: Foo) { return this.store.save(foo); }\n}",
                "lang": "ts"
            }
        },
        {
            "id": "open-closed",
            "distinctFrom": [
                {
                    "id": "architecture:composability",
                    "reason": "The open/closed principle adds behavior without editing existing code, while composability combines parts through compatible interfaces."
                }
            ],
            "aliases": [
                "OCP",
                "Open-Closed Principle"
            ],
            "name": "Open/Closed Principle (OCP)",
            "definition": "A design rule that a module gains new behavior by adding code at an extension point, leaving its existing code unchanged.",
            "canon": ["open-closed"],
            "type": "principle",
            "scope": [
                "class",
                "module",
                "component"
            ],
            "requires": [
                "Abstraction",
                "Extension Points"
            ],
            "reinforces": [
                "Plugin Architecture",
                "Strategy Pattern"
            ],
            "enables": ["Feature Extension without Modification"],
            "conflicts_with": ["Switch-Based Extension"],
            "tensions_with": ["Simplicity"],
            "violated_by": ["lexicon:switch-based-extension"],
            "detected_by": [
                "growing conditionals",
                "repeated edits to central classes"
            ],
            "measured_by": ["modification frequency of core modules"],
            "refactored_by": [
                "architecture:strategy-pattern",
                "architecture:extension-points",
                "architecture:plugin-architecture"
            ],
            "enforced_by": [
                "extension policies",
                "change analysis"
            ],
            "severity": "recommended",
            "exemplar": {
                "before": "function priceFoo(kind: string, value: number) {\n  if (kind === \"foo\") return value;\n  if (kind === \"bar\") return value * 2;\n  throw new Error(\"unknown kind\");\n}",
                "after": "interface FooPricing { price(value: number): number; }\nconst registry = new Map<string, FooPricing>();\nexport function registerPricing(kind: string, pricing: FooPricing) { registry.set(kind, pricing); }\nexport function priceFoo(kind: string, value: number) {\n  const pricing = registry.get(kind);\n  if (!pricing) throw new Error(`unknown kind ${kind}`);\n  return pricing.price(value);\n}\nregisterPricing(\"bar\", { price: value => value * 2 });",
                "lang": "ts"
            }
        },
        {
            "id": "liskov-substitution",
            "aliases": [
                "LSP",
                "Liskov Substitution Principle",
                "Behavioral Subtyping"
            ],
            "name": "Liskov Substitution Principle (LSP)",
            "definition": "A design rule that a subtype can replace its base type anywhere, because it keeps the base type's preconditions, postconditions and invariants.",
            "type": "principle",
            "scope": [
                "class",
                "interface",
                "type hierarchy"
            ],
            "requires": [
                "Contract Preservation",
                "Preconditions",
                "Postconditions",
                "Invariant"
            ],
            "reinforces": [
                "Polymorphism",
                "Type Safety"
            ],
            "enables": [
                "Safe Substitution",
                "Substitutability"
            ],
            "conflicts_with": [
                "Broken Inheritance",
                "Incompatible Override"
            ],
            "tensions_with": ["Narrow Specialized Behavior"],
            "violated_by": ["lexicon:broken-inheritance"],
            "detected_by": ["overridden method contract divergence"],
            "measured_by": ["contract test pass rate across subtypes"],
            "refactored_by": [
                "lexicon:replace-inheritance-with-delegation",
                "lexicon:extract-interface",
                "lexicon:split-hierarchy"
            ],
            "enforced_by": [
                "contract tests",
                "type tests"
            ],
            "severity": "mandatory",
            "exemplar": {
                "before": "class FooStore {\n  save(foo: Foo): Promise<Receipt> { return persist(foo); }\n}\nclass ReadOnlyFooStore extends FooStore {\n  save(): Promise<Receipt> { throw new Error(\"not supported\"); }\n}",
                "after": "class FooStore {\n  save(foo: Foo): Promise<Receipt> { return persist(foo); }\n}\nclass AuditedFooStore extends FooStore {\n  async save(foo: Foo): Promise<Receipt> {\n    const receipt = await super.save(foo);\n    audit.record(receipt);\n    return receipt;\n  }\n}",
                "lang": "ts"
            }
        },
        {
            "id": "polymorphism",
            "distinctFrom": [
                {
                    "id": "architecture:dynamic-dispatch",
                    "reason": "Polymorphism is one interface with several implementations, while dynamic dispatch is the runtime selection of which one runs, from the receiver or a keyed table."
                },
                {
                    "id": "architecture:type-safety",
                    "reason": "Polymorphism varies the implementation behind a type, while type safety rejects operations on the wrong type."
                }
            ],
            "name": "Polymorphism",
            "definition": "A mechanism that lets one interface have several implementations, with the implementation chosen by the object that receives the call.",
            "type": "mechanism",
            "scope": [
                "class",
                "interface",
                "runtime"
            ],
            "requires": [
                "Abstraction",
                "Substitutability"
            ],
            "reinforces": [
                "OCP",
                "Strategy Pattern"
            ],
            "enables": [
                "Dynamic Dispatch",
                "Interchangeability"
            ],
            "conflicts_with": ["Type Switching"],
            "tensions_with": ["Traceability"],
            "violated_by": ["lexicon:type-switching"],
            "detected_by": [
                "conditional type checks",
                "duplicated branching"
            ],
            "measured_by": ["polymorphic dispatch ratio"],
            "refactored_by": ["lexicon:replace-conditional-with-polymorphism"],
            "enforced_by": [
                "code review",
                "static analysis rules"
            ],
            "severity": "recommended",
            "exemplar": {
                "before": "function renderFoo(kind: string, foo: Foo) {\n  if (kind === \"text\") return foo.name;\n  if (kind === \"json\") return JSON.stringify(foo);\n  throw new Error(\"unknown renderer\");\n}",
                "after": "interface FooRenderer { render(foo: Foo): string; }\nclass TextFooRenderer implements FooRenderer { render(foo: Foo) { return foo.name; } }\nclass JsonFooRenderer implements FooRenderer { render(foo: Foo) { return JSON.stringify(foo); } }\nfunction renderFoo(renderer: FooRenderer, foo: Foo) { return renderer.render(foo); }",
                "lang": "ts"
            }
        }
    ]
}
```
