License라는 클래스가 있다고 해보자. 

이 클래스는 calcFee()라는 메서드를 가지며, Billing 애플리케이션에서 이 메서드를 호출한다

License에는 PersonalLicense와 BusinessLicense라는 두가지 '하위 타입'이 존재한다

이들 두 하위 타입은 서로 다른 알고리즘을 이용해서 라이선스 비용을 계산한다


이 설계는 LSP를 준수하는데, Billing 애플리케이션의 행위가 License 하위 타입 중 무엇을 사용하는지에 전혀 의존하지 않기 때문이다

이들 하위 타입은 모두 License 타입을 치환할 수 있다


LSP 위반사례

다양한 택시 파견 서비스를 통합하는 애플리케이션을 만들고 있다


...


이 예제에서 분명한 점은 파견 서비스를 만들 때 다양한 택시업체에서 동일한 REST 인터페이스를 반드시 준수하도록 한다는 사실이다

서로 다른 택시 업체가 pickupAddress, pickupTime, destination 필드를 모두 동일한 방식으로 처리해야 한다


이제 택시 업체 애크미에서 프로그래머를 몇 명 고용했는데, 이 들이 서비스 사양서를 그다지 신중하게 읽지 않았다고 해보자

그래서 destination 필드를 dest로 축약해서 사용했다고 치자

그런데 애크미는 이지역에서 가장 큰 택시업체일 뿐만 아니라, 애크미 대표의 전처는 우리 회사 대표의 아내가 되었다

무슨일이 벌어질지 충분히 짐작 가능하지않나?

우리 회사의 시스템 아키텍처에는 무슨일이 벌어질까?


뻔한 일이지만, 우리는 이 예외 사항을 처리하는 로직을 추가해야만 할 것이다

애크미 소속 기사를 파견하는 요청은 나머지 업체의 기사를 파견할 때와는 다른 규칙을 이용하여 구성해야만 한다

이를 위한 가장 간단한 방법은 파견 명령어를 구성하는 모듈에 if 문을 추가하는 것이다


if (driver.getDispatchUri().startsWith("acme.com")): ...


하지만 실력있는 아키텍트라면 당연히 시스템을 이런식으로 구성하는 것을 용납하지 않는다

"acme"라는 단어를 코드 자체에 추가하면, 끔직할 뿐만 아니라 이해할 수도 없는 온갖 종류의 에러가 발생할 여지를 만들게 된다

보안이 침해되는 것은 말할 것도 없다


예를 들어 애크미가 지금보다 더 성장해서 다른 택시업체인 퍼플을 인수한다면 어떻게 될까?

합병된 퍼플이 브랜드와 웹 사이트는 애크미와는 독립적으로 유지하되, 회사 시스템은 모두 통합한다면?

퍼플위해 "purple"을 처리하는 또다른 if문을 추가해야만 하나?


...


LSP는 아키텍처 수준까지 확장 할 수 있고, 반드시 확장해야만 한다

치환 가능성을 조금이라도 위배하면 시스템 아키텍처가 오염되어 상당량의 별도 메커니즘을 추가해야 할 수 있기 때문이다