8. 코드를 모듈화하라
요구 사항이 어떻게 바뀔지 정확히 예측하는 것은 대개 시간 낭비인데, 그 이유는 정확하게 예측하는 것이 거의 불가능하기 때문이다. 하지만 보통 요구 사항이 어떤 식으로든 바뀐다는 점만은 어느 정도 확신할 수 있다.
모듈화의 주된 목적 중 하나는 코드가 향후에 어떻게 변경되거나 재구성될지 정확히 알지 못한 상태에서 변경과 재구성이 용이한 코드를 작성하는 것이다. 이를 달성하기 위한 핵심 목표는 각각의 기능(또는 요구 사항)이 코드베이스의 서로 다른 부분에서 구현되어야 한다는 것이다.
코드를 모듈화하는 것은 종종 하위 문제에 대한 해결책의 자세한 세부 사항들이 독립적이고 서로 밀접하게 연관되지 않도록 하는 것으로 귀결된다. 이렇게 하면 적응성이 뛰어난 코드가 될 뿐만 아니라 소프트웨어 시스템에 대한 추론을 쉽게 해준다.
8.1. 의존성 주입의 사용을 고려하라
8.1.1. 하드 코드화된 의존성은 문제가 될 수 있다
하드 코드화 되면 다용도로 사용 할 수 없다.
8.1.2. 해결책: 의존성 주입을 사용하라
의존성 주입을 이용하면 훨씬 더 모듈화되고 다용도로 사용 할 수 있다. 의존성 주입은 팩토리 함수를 작성하거나 의존성 주입 프레임워크를 사용하여 구현가능하다. 팩토리 함수 대신 의존성 주입 프레임워크를 사용하는 것이 개발 작업을 쉽게 만든다. 다만, 주의해서 사용하지 않을 경우 오히려 파악하기 어려운 코드가 만들어 질 수도 있다.
8.1.3. 의존성 주입을 염두에 두고 코드를 설계하라
지금 의존성 주입을 사용하지 않더라도, 나중에 의존성 주입을 사용 할 것을 염두하고 코드를 작성하는 것이 좋다. 대표적으로 정적 함수에 과도하게 의존하지 않는 것이다.
8.2. 인터페이스에 의존하라
어떤 클래스에 의존하고 있는데 그 클래스가 어떤 인터페이스를 구현하고 필요한 기능이 그 인터페이스에 모두 정의되어 있으면, 클래스에 직접 의존하기보다는 인터페이스에 의존하는 것이 일반적으로 더 바람직하다.
8.3. 클래스 상속을 주의하라
두 가지 사물이 진정한 is-a 관계를 갖는다면(예: a car is a vehicle) 상속이 적절할 수 있다.
8.3.1. 클래스 상속은 문제가 될 수 있다
상속을 조심히 사용하지 않으면, 객체 내부용 인터페이스도 같이 노출된다. 그리고 상속으로 인해 오히려 코드 중복이 늘어 날 수도 있다.
8.3.2. 해결책: 구성을 사용하라
상속의 문제를 해결하기 위해서는 구성(composition)을 이용하여 코드를 작성한다. 구성을 적절히 사용하면, 상속의 문제를 회피하는 것이 가능하다.
8.3.3. 진정한 is-a 관계는 어떤가?
진정한 is-a 관계가 있다 하더라도 상속은 여전히 문제가 될 수 있다는 점을 알아야 한다.
- 취약한 베이스 클래스 문제
- 다이아몬드 문제
- 문제가 있는 계층 구조
8.4. 클래스는 자신의 기능에만 집중해야 한다
SOLID의 단일책임원칙 내용에 대해 풀어서 간단히 설명하는 부분이라 생각한다.
8.5. 관련 있는 데이터는 함께 캡슐화하라
데이터 객체의 유용성에 대해 설명한다.
8.6. 반환 유형에 구현 세부 정보가 유출되지 않도록 주의하라
8.7. 예외 처리 시 구현 세부 사항이 유출되지 않도록 주의하라
명확안 계층 분리를 위해서는 반환값이나 예외의 내용도 호출한 계층에 의존되게 작성하지 말아야 한다는 내용이다.