[Clean Code] 11장 | 시스템 (미완성)

PADO·2020년 12월 31일
0

Clean Code

목록 보기
12/15
post-thumbnail

🧷 11장 | 시스템

깨끗한 코드를 구현하면 낮은 추상화 수준에서 관심사를 분리하기 쉬워진다.
높은 추상화 수준, 즉 시스템 수준에서도 깨끗함을 유지하는 방법을 살펴본다.

📘 시스템 제작과 시스템 사용을 분리하라

SW 시스템은 애플리케이션 객체를 제작하고 의존성을 서로 '연결'하는 준비 과정과
준비 과정 이후에 이어지는 런타임 로직을 분리해야 한다.

  • 제작(Construction): 어플리케이션 객체를 제작하고 의존성을 서로 연결하는 과정
  • 사용(Use): 제작 과정 이후 이어지는 런타임 과정

📘 관심사 분리

애플리케이션을 서로 겹치지 않는 개별 단위로 나누는 과정
→ 한 영역이 다른 영역과 격리되기 때문에 다른 영역에 영향을 주지 않고도 변경할 수 있으며, 애플리케이션의 전체적인 유지보수가 용이해진다.

가장 흔히 쓰이는 초기화 지연(Lazy Initialization)의 한계

public Service getService() {
  if (service == null)
    service = new MyServiceImpl(...);
  return service;
}

장점

  • 실제로 필요할 때까지 객체를 생성하지 않으므로 불필요한 부하가 걸리지 않는다.
    → 애플리케이션을 시작하는 시간이 그만큼 빨라진다.
  • 어떤 경우에도 null 포인터를 반환하지 않는다.

단점

  • getService 메서드가 MyServiceImpl 과 생성자 인수에 명시적으로 의존한다.
  • MyServiceImpl이 무거운 객체라면 단위 테스트 시 적절한 테스트 전용 객체를 할당해야 한다.
  • 일반 런타임 로직에 객체 생성 로직을 섞어놓은 탓에 모든 실행 경로(service가 null이 아닌 경로)도 테스트 해야 한다.
  • 메서드가 작업을 두 가지 이상 수행한다 = 책임이 둘이다.
    → 단일 책임 원칙(SRP)을 깬다.

많은 애플리케이션이 초기화 지연 기법을 수시로 사용한다. 그래서 전반적인 설정 방식이 곳곳에 흩어져 있다.
모듈성은 저조하며 대개 중복이 심각하다.

체계적이고 탄탄한 시스템을 만들고 싶다면 모듈성을 깨서는 절대로 안 된다.
객체를 생성하거나 의존성을 연결할 때도 마찬가지다.
설정 논리는 일반 실행 논리와 분리해야 모듈성이 높아진다.

📘 Main 분리

시스템 생성과 시스템 사용을 분리하는 방법

  • 생성과 관련한 코드는 모두 main이나 main이 호출하는 모듈로 옮긴다.
  • 모든 의존성이 main에서 애플리케이션으로 향한다.
  • 애플리케이션은 main이나 객체가 생성되는 과정을 모른다.
  • 애플리케이션은 모든 객체가 생성되었고 모든 의존성이 연결되었다고 가정한다.

📘 팩토리

객체가 생성되는 시점을 애플리케이션이 결정할 때 사용하는 방법

  • ABSTRACT FACTORY 패턴 사용
  • 모든 의존성이 main에서 애플리케이션으로 향한다.
  • 애플리케이션은 main이나 객체가 생성되는 과정을 모른다.
  • 객체 생성 시점은 애플리케이션이 결정하지만, 객체 생성 코드는 애플리케이션이 모른다.
  • main 쪽에 있는 FactoryImplementation이 안다.
  • 애플리케이션은 객체 생성 시점을 완벽히 통제하며, 생성자 인수도 넘길 수 있다.

📘 의존성 주입

사용과 제작을 분리하는 강력한 메커니즘

필요한 객체를 직접 생성하는 것이 아닌, 외부로부터 필요한 객체를 받아서 사용 하는 것이다.
이를 통해 객체간의 결합도를 줄이고 코드의 재활용성을 높여준다.

의존성 주입은 제어 역전 기법을 의존성 관리에 적용한 메커니즘이다.
제어 역전에서는 한 객체가 맡은 보저 책임을 새로운 객체에게 전적으로 떠넘긴다.
새로운 객체는 넘겨받은 책임만 맡으므로 단일 책임 원칙을 지키게 된다.

  • DI 컨테이너를 통해 의존성을 관리한다.
  • setter 메소드나 생성자 인수를 통해 의존성을 주입한다.
  • DI 컨테이너는 요청이 들어올 때마다 필요한 객체의 인스턴스를 만든 후 의존성을 설정한다.

초기화 지연으로 얻은 장점을 포기?

📘 확장

'처음부터 올바르게' 시스템을 만들 수 있다는 믿음은 미신이다. 대신에 우리는 오늘 주어진 사용자 스토리에 맞춰 시스템을 구현해야 한다.

테스트 주도 개발 (Test-driven Development), 리팩터링, 그에 따라 얻은 깨끗한 코드는 코드 수준에서 시스템을 조정하고 확장하기 쉽게 만든다.

📘 횡단(cross-cutting) 관심사

로깅, 보안, 트랜잭션 등등 다수의 모듈에서 반복적으로 나타나는 부분
영속성과 같은 관심사는 애플리케이션의 자연스러운 객체 경계를 넘나드는 경향이 있다.
모든 객체가 전반적으로 동일한 방식을 이용하게 만들어야 한다.

  • AOP: Aspect-Oriented Programming

횡단 관심사에 대처해 모듈성을 확보하는 방법론

Aspect: "특정 관심사를 지원하려면 시스템에서 특정 지점들이 동작하는 방식을 일관성 있게 바꿔야 한다."

자바에서 사용하는 Aspect와 유사한 메커니즘 세 개

📘 자바 프록시

0개의 댓글