[Clean Architecture] 9장. LSP: 리스코프 치환 원칙
|Introduction
- 1988년 바바라 리스코프는 하위 타입(subtype) 에 대해 아래와 같이 정의
여기에서 필요한 것은 다음과 같은 치환 substitution 원칙이다. S 타입의 객체 o1 각각에 대응하는 T 타입 객체 o2 가 있고, T 타입을 이용해서 정의한 모든 프로그램 P 에서 o2 의 자리에 o1 을 치환하더라도 P 의 행위가 변하지 않는다면, S 는 T 의 하위타입이다.
상속을 사용하도록 가이드하기
- 이 설계는
LSP
를 준수함Billing
애플리케이션의 행위가License
하위 타입 중 무엇을 사용하는지에 전혀 의존하지 않기 때문- 이들 하위 타입은 모두
License
타입을 치환할 수 있다.
정사각형/직사각형 문제
- LSP 를 위반하는 유명한 문제
- Square 는 Rectangle 의 하위 타입으로는 적합하지 않음
- 이런 형태의 LSP 위반을 막기 위한 유일한 방법은 (if 문 등을 이용해서) Rectangle 이 실제로는 Square 인지를 검사하는 매커니즘을 User 에 추가하는 것
- 하지만 이렇게 하면 User 의 행위가 사용하는 타입에 의존하게 되므로 결국 타입을 서로 치환할 수 없게 됨
LSP와 아키텍처
- LSP 는 시간이 지나면서 인터페이스와 구현체에도 적용되는 더 광범위한 소프트웨어 설계 원칙으로 변모해옴
- 여기에서 말하는 인터페이스는 다양한 형태로 나타남
- 잘 정의된 인터페이스와 그 인터페이스의 구현체끼리의 상호 치환 가능성에 기대는 사용자들이 존재함
- 아키텍처 관점에서 LSP 를 이해하는 최선의 방법은 이 원칙을 어겼을 때 시스템 아키텍처에서 무슨 일이 일어나는지 관찰하는 것
LSP 위배 사례
- 다양한 택시 파견 서비스
- 이때 acme 에서 기존에 /destination 으로 쓰던 필드를 /dest 로 축약한 경우가 발생
- 아키텍트는 이와 같은 버그로부터 시스템을 격리해야 함
- 별도의 설정용 데이터베이스를 만들거나…
- REST 서비스들의 인터페이스가 서로 치환가능하지 않다는 사실을 처리하는 중요하고 복잡한 매커니즘을 추가하거나…
결론
- LSP 는 아키텍처 수준까지 확장할 수 있고, 반드시 확장해야만 함
- 치환 가능성을 조금이라도 위배하면 시스템 아키텍처가 오염되어 상당량의 별도 메커니즘을 추가해야 할 수 있기 때문