laughcryrepeat 2021. 2. 15. 23:40

7장 SRP: 단일 책임 원칙

 

함수는 반드시 하나의 일만 해야한다는 원칙.

 

하나의 모듈은 하나의 오직한의 액터에 대해서만 책임져야 한다.

 

단일 액터를 책임지는 코드를 함께 묶어주는 힘이 응집성 cohesion.

 

징후 1: 우발적 중복

단일클래스에 세 메서드가 배치되어 세 액터가 서로 결함됨.

변경이 일어날 경우 그것에 의존하는 무언가여 영향을 주게됨.

 

Shared Algorithm

 

서로 다른 액터가 의존하는 코드를 너무 가까이 배치해서 발생하는 문제.

SRP는 서로 다른 액터가 의존하는 코드를 서로 분리하라고 한다.

 

징후 2: 병합

병합은 항상 위험이 뒤따른다.

문제를 벗어나는 방법은 서로 다른 액터를 뒷받침하는 코드를 서로 분리하는 것.

해결책

메서드를 각기 다른 클래스로 이동시키는 방식.

 

아무런 메서드가 없는 간단한 데이터 구조인 EmplyeeData 클래슬르 만들엉 세개의 클래스가 공유하도록 하는 방법

세 클래스는 서로에 대해 모른다.

 

 

Facade 패턴. EmployeeFacade 클래스가 세클래스의 객체를 생성하고 

요청된 메서드를 가지는 객체로 위임하는 일을 책임지는 방법.

 

 

가장 중요한 업무규칙을 데이터와 가깝게 배치하는 방식.

중요한 메서드는 기존의 Employee 클래스에 유지하고, Employee 클래스를 덜 중요한 메서드들에 대한 퍼사드로 사용.

 

결론

단일 책임 원칙은 메서드와 클래스 수준의 원칙.

상위 수준에서도 다른 형태로 다시 등장.

 


8장 OCP: 개방-폐쇄 원칙

 

1988년 버트란트 마이어 Bertrad Meyer

소프트웨어 개체 artifact는 확장에 열려 있어야 하고, 변경에 닫혀있어야 한다.

소프트웨어 개체의 행위는 확장할 수 있어야 하지만, 개체를 변경해서는 안됨.

사고실험 thought experiment

서로 다른 목적으로 변경되는 요소를 적절하게 분리하고(SRP) 

이들 요소 사이의 의존성ㅇ르 체계화 함으로써(의존성 역전 원칙 DIP)

변경량을 최소화.

보고서 생성이 두개의 책임으로 분리.

보고서용 데이터를 계산하는 책임 과 데이터를 웹이나 종이로 출력하는 형태로 표현하는 책임.

 

책임 분리후, 두 책임중 하나가 변경되더라도 다른것이 영향받지 않게 코드 의존성 조직화.

행위가 확장될 때 변경이 발생하지 않도록 보장.

처리과정을 클래스 단위로 붆라하고, 클래스는 컴포넌트 단위로 분리

화살표는 변경으로부터 보호하려는 컴포넌트를 향하도록 그려진다.

예를 들어, A 컴포넌트에서 발생한 변경으로부터 B 컴포넌트를 보호하려면 A가 B에 의존해야한다.

 

아키텍처 수준에서 OCP가 동작하는 방식

어떠한 변경도 중요 업무규칙을 포함하는 Interactor에 영향을 주지 않는다.

Interactor는 가장 높은 수준 level 의 개념이고 최고의 보호를 받음.

view는 가장 낮은 수준의 개변이며 거의 보호받지 않음.

presenter는 view 보다 높고 controller나 interactor보다 낮은 수준에 위치.

 

분리한 긴으을 컴포넌트 계층구조로 조직화 하면

저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있다.

방향성 제어 directional control

 FinancialDataGateWay 인터페이스

FinancialReportPresenter 인터페이스와 2개의 view 인터페이스의 목적.

-->  의존성을 역전시키기 위함.

정보 은닉

FinancialReportRequester 인터페이스의 목적

--> Interactor 내부를 보호하기 위함. 또한 반대로 controller 도 보호.

 

결론

OCP의 목표는 시스템을 확장하기 쉬운 동시에 변경으로 인해 시스템이 너무 많은 영향을 받지 않도록 하려는 것.

- 시스템을 컴포넌트로 분리

- 저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있는 형태의 의존성 계층구조.


9장 리스코프 치환 원칙

 

1988년 바바라 리스코프의 하위타입 정의

 

필요한 것은 다음과 같은 치환 substitution 원칙이다. S타입의 객체 o1 각각에 대응하는 T 타입 객체 o2가 있고, 

T타입을 이용해서 정의한 모든 프로그램 P에서 o2의 자리에 o1을 치환하더라도 P의 행위가 변하지 않는다면,

S는 T의 하위타입이다.

 

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

License 클래스는 calcFee() 메서드를 가지고,

Billing 애플리케이션에서 이 멧드를 호출함.

License에는 PersonalLicense와 BusinessLicense 두가지 하위타입 존재하며 각기다른 라이선스 비용 계산.

License와 파생클래스는 LSP 준수

Billing 애플리케이션의 행위가 License 하위 타입 중 전혀 의존하지 않기 때문에

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

 

정사각형/직사각형 문제

LSP를 위반하는 전형적인 문제 

Square는 Rectangle의 하위타입으로 적합하지 않음.

Rectangle 높이와 너비는 서로 독립적이지만 Square의 높이와 너비는 함께 변경되기 때문에.

 

LSP와 아키텍처

상속을 사용하느 가이드 정도에서 인터페이스와 구현체에도 적용되는 설계원칙으로 변모됨.

잘 정의된 인터페이스와 그 인터페이스의 구현체끼리 상호치환 가능성.

 

LSP 위배 사례

택시파견 taxi dispatch 서비스 통합하는 애플리케이션 사례

REST 서비스를 통해 선택된 택시를 고객에게 파견.

 

택시기사 Bob의 택시파견 URI

puplecab.com/driver/Bob

 

시스템은 URI에 파견에 필요한 정보를 덧붙인 후 PUT 방식으로 호출.

puplecab.com/driver/Bob

/pickupAddress/24 Mple St.

/pickupTime/153

/destination/ORD

 

파견 서비스를 만들때 다양한 택시업체에서 동일한 REST 인터페이스를 반드시 준수. 필드를 동일하게 처리해야 함.

만약 서비스 사양을 준수하지 않아 필드값을 축약해서 사용하면,

서로 다른 규칙을 이용해 구성하고 예외사항을 처리하는 로직을 추가해야한다.

 

결론

LSP는 아키텍처 수준까지 확장할 수 있어야 하고,

치환가능성을 위배하면 상당한 예외처리 메커니즘을 추가하게 될수도 있음.