[Clean Architecture] 9장. LSP: 리스코프 치환 원칙

Introduction Link to heading

  • 1988년 바바라 리스코프는 하위 타입(subtype) 에 대해 아래와 같이 정의

여기에서 필요한 것은 다음과 같은 치환 substitution 원칙이다. S 타입의 객체 o1 각각에 대응하는 T 타입 객체 o2 가 있고, T 타입을 이용해서 정의한 모든 프로그램 P 에서 o2 의 자리에 o1 을 치환하더라도 P 의 행위가 변하지 않는다면, S 는 T 의 하위타입이다.

상속을 사용하도록 가이드하기 Link to heading

0.jpg

  • 이 설계는 LSP 를 준수함
    • Billing 애플리케이션의 행위가 License 하위 타입 중 무엇을 사용하는지에 전혀 의존하지 않기 때문
    • 이들 하위 타입은 모두 License 타입을 치환할 수 있다.

정사각형/직사각형 문제 Link to heading

  • LSP 를 위반하는 유명한 문제

1.jpg

  • Square 는 Rectangle 의 하위 타입으로는 적합하지 않음
  • 이런 형태의 LSP 위반을 막기 위한 유일한 방법은 (if 문 등을 이용해서) Rectangle 이 실제로는 Square 인지를 검사하는 매커니즘을 User 에 추가하는 것
    • 하지만 이렇게 하면 User 의 행위가 사용하는 타입에 의존하게 되므로 결국 타입을 서로 치환할 수 없게 됨

LSP와 아키텍처 Link to heading

  • LSP 는 시간이 지나면서 인터페이스와 구현체에도 적용되는 더 광범위한 소프트웨어 설계 원칙으로 변모해옴
    • 여기에서 말하는 인터페이스는 다양한 형태로 나타남
  • 잘 정의된 인터페이스와 그 인터페이스의 구현체끼리의 상호 치환 가능성에 기대는 사용자들이 존재함
  • 아키텍처 관점에서 LSP 를 이해하는 최선의 방법은 이 원칙을 어겼을 때 시스템 아키텍처에서 무슨 일이 일어나는지 관찰하는 것

LSP 위배 사례 Link to heading

  • 다양한 택시 파견 서비스
  • 이때 acme 에서 기존에 /destination 으로 쓰던 필드를 /dest 로 축약한 경우가 발생
  • 아키텍트는 이와 같은 버그로부터 시스템을 격리해야 함
    • 별도의 설정용 데이터베이스를 만들거나…
    • REST 서비스들의 인터페이스가 서로 치환가능하지 않다는 사실을 처리하는 중요하고 복잡한 매커니즘을 추가하거나…

결론 Link to heading

  • LSP 는 아키텍처 수준까지 확장할 수 있고, 반드시 확장해야만 함
  • 치환 가능성을 조금이라도 위배하면 시스템 아키텍처가 오염되어 상당량의 별도 메커니즘을 추가해야 할 수 있기 때문