[클린 아키텍처] 9. LSP: 리스코프 치환 원칙

햄도·2022년 2월 20일
0

Clean Architecture

목록 보기
9/11

출처

클린 아키텍처를 읽으며 정리한 내용입니다.

9. LSP: 리스코프 치환 원칙

바바라 리스코프가 정의한 하위 타입이란 다음과 같다.

  • S 타입의 객체 o1 각각에 대응하는 T 타입 객체 o2가 있고, T 타입을 이용해서 정의한 모든 프로그램 P에서 o2의 자리에 o1을 치환하더라도 P의 행위가 변하지 않는다면, S는 T의 하위 타입이다. → 리스코프 치환 원칙

예시를 통해 리스코프 치환 원칙을 알아보자.

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

License 클래스는 calcFee() 라는 메서드를 가지며, Billing 애플리케이션에서 이 메서드를 호출한다고 가정해보자. License를 구현한 하위 타입 PersonalLicenseBusinessLicense 는 서로 다른 알고리즘을 이용해 라이선스 비용을 계산한다.

이러한 상황에서 Billing 애플리케이션의 행위는 License 하위 타입 중 무엇을 사용하는지에 의존하지 않기 때문에, 이 하위 타입은 모두 License 타입을 치환할 수 있다. 따라서 이 설계는 LSP를 준수한다.

정사각형/직사각형 문제

LSP를 위반하는 전형적인 문제로 정사각형/직사각형 문제가 있다.

Rectangle 클래스는 가로, 세로 길이를 변경하는 setH, setW 메서드를 가지고 있다. 이 클래스의 하위 타입으로 Square를 구현했다고 가정해보자. 이 예제에서 Square 의 높이와 너비는 반드시 함께 변경되어야 하기 때문에, Rectangle 의 하위 타입으로 적합하지 않다.

RectangleSquare인지 검사하는 매커니즘을 추가하는 등의 방법으로 해결할 수는 있겠지만, 이렇게 하면 user의 행위가 사용하는 타입에 의존하게 된다.

LSP와 아키텍처

LSP가 나타난 초반에는 상속을 사용하도록 가이드하는 방법 정도로 간주되었지만, 시간이 지나며 인터페이스와 구현체에도 적용 가능한 원칙이 되었다.

여기에서 말하는 인터페이스란 다양한 형태로 나타날 수 있다.

  • 자바류: 인터페이스 하나와 이를 구현하는 여러 클래스
  • 루비류: 동일한 메서드 시그니처를 공유하는 여러 개의 클래스
    • 파이썬에서는 덕타이핑같은 모양이 아닐까?
  • 동일한 REST 인터페이스에 응답하는 서비스 집단일 수도

아키텍처 관점에서 LSP를 이해하기 위해 이 원칙을 어기면 무슨 일이 일어나는지 알아보자.

LSP 위배 사례

다양한 택시 파견 서비스를 통합하는 애플리케이션의 예시를 보자.

택시 파견 REST 서비스의 URI가 운전기사 DB에 저장되어 있고, 시스템이 알맞은 기사를 선택해 URI로 다음과 같이 요청을 보낸다고 생각해보자.

purplecab.com/driver/Bob
		/pickupAddress/24 Maple St.
		/pickupTime/153
		/destination/ORD

이 예시에서는 다양한 택시 파견 서비스가 동일한 REST 인터페이스를 준수하도록 만들어야 한다. 즉 다른 택시업체도 pickupAddress, pickupTime, destination 필드를 동일하게 처리해야 한다.

하지만 일부 택시업체에서 다르게 처리한다면, if문을 처리하는 등의 방법으로 해결해야 한다. 이런 예외상황은 끝없이 발생할 수 있다.

아키텍트는 이러한 버그로부터 시스템을 보호해야 한다. 파견 URI를 키로 사용해 파견 요청 포맷을 관리하거나, 각 REST 서비스의 인터페이스가 치환 가능하지 않다는 사실을 처리하는 복잡한 매커니즘을 추가해야 할 수도 있다.

결론

LSP는 아키텍처 수준까지 확장할 수 있고, 위에서 본 문제를 막으려면 반드시 확장해야 한다.

profile
developer hamdoe

0개의 댓글