[Clean code] chapter 11. 시스템

3 minute read

Overview

복잡성은 개발자들에게 어려움만을 제공한다.

깨끗한 코드는 낮은 추상화 수준에서 관심사 분리가 쉬워진다. 그러기 때문에 높은 추상화 수준, 시스템 수준에서 깨끗함을 유지하는 것이 중요하다.

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

제작과 사용은 아주 다르다.

소프트웨어 시스템은 (애프릴케이션 객체를 제작하고 의존성을 서로 ‘연결’하는) 준비과정과 (준비 과정 이후에 이어지는) 런타임 로직을 분리해야 한다.

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

위에 설명한 방법은 초기화 지연 기법이다. 해당 기법의 장점은 필요할 때 만든다는 장점이 있지만 해당 초기화 코드에 매우 의존적이다. 그러다보니 테스트도 어렵다.

가장 중요한 것은 해당 초기화가 어떤 것을 의미하는지 알기 어렵다. 그러기 때문에 실행하면서도 해당 코드를 봐야된다는 문제가 있다. (어떻게 초기화 되는지 알아야되기 때문에)

Main 분리

생상과 관련된 코드는 모두 main이나 main이 호출하는 모듈로 옮기고, 나머지 시스테믄 모든 객체가 생성되었고 모든 의존성이 연결되었다고 가정한다.

이런 방식으로 모든 애플리케이션은 객체 생성에 대해서 전혀 알지 못한다.

팩토리

객체 생성되는 시점을 애플리케이션이 결정할 때가 있다. 그런 경우 Abstract factory 패턴을 사용한다.

객체 생성에 대해서 내부 로직을 추상화하고 그것에 대해서 애플리케이션은 호출만 하기 때문에 실제 구현을 알지 못하고 생성 시점만 결정한다.

의존성 주입

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

의존성 관리는 맥락에서 객체는 의존성 자체를 인스턴스로 만드는 책임을 지지 않는다. main 루틴이나 컨테이너를 사용한다.

Service service = (Service) jndicContext.lookup("NameOfMyService");

스프링에서는 자바 DI 컨테이너를 제공한다. 객체 사이 의존성을 XML 파일에 정의하고 자바 코드에서는 이름으로 특정 객체를 요구할 수 있다.

확장

도시가 마을, 도시로 점점 성장하듯이 소프트웨어도 점점 성장한다.

도시가 성장하면서 처음 지은 도로가 좁은 것처럼 소프트웨어 확장을 지속적으로 생각하고 설계하지 않고 개발을 진행하면 지속적인 확장이 힘들 수 있다.

EJB (Enterprise JavaBeans)2를 기반으로 설명해보겠다.

Code~~~

비즈니스 논리는 EJB2 어플리케이션 ‘컨테이너’에 강하게 의존되어 있다. 클래스를 생성할 때 컨테이너에서 파생해야 하며 컨테이너가 요구하는 생명주기 메서드도 제공해야 한다. (class, interface 상속 때문인가?)

그러기 때문에 테스트도 어려워 지게 된다. 요구사항도 맞춰야되며 그것을 하기도 어렵다.

횡단 관심사

EJB2 아키텍처는 거의 모든 영역에서 관심사를 분리했지만 애플리케이션이 경계를 넘나드는 경우가 있다. 그런 경우 해당 영역에서 끝이 아니라 지속적으로 퍼져나가게 된다.

자바 프록시

복잡함. 깨끗한 코드를 만들기 어렵다.

순수 자바 AOP 프레임워크

POJO 기반으로 프레임워크에 대한 종속성이 전혀 없는 상태로 진행이 가능하다. 그러기 때문에 테스트 작성하는 부분해서 유리하면 확장도 쉬워진다.

XML를 이용해서 관계를 정의할 수 있고 지속적으로 프록시를 통해서 해당 객체를 얻을 수 있다. 그 과정에서 당연히 중간에 트랜잭션과 캐쉬를 추가할 수도 있다.

XmlBeanFactory bf = ...
Bank bank = (Bank) bf.getBean("bank");

위에 코드는 스프링과 관련이 없는 코드이기 때문에 프레임워크와는 독립적이다. EJB2와는 다르게 강한 결합이 없어지므로 강한 결헙 문제가 사라진다.

AspectJ 관점

스프링 AOP, JBoss AOP가 제공하는 순수 자바 박신은 과점이 필요한 중 80~90%를 커버할 수 있다. AspectJ는 다양한 기능을 제공해주지만 새로운 언어 문법과 사용법을 익히는데 비용이 많이 든다.

테스트 주도 시스템 아키텍처 구축

AOP 관점에서 설계를 하여서 관심사를 분리한다면 굉장히 큰 임팩트를 줄 수 있따. 논리를 POJO로 작성할 수 있으며, 즉 코드 수준에서 아키텍처 관심사를 분리할 수 있으며 (?), 진정한 테스트 주도 아키텍처 구축이 가능해진다.

처음부터 큰 그림을 생각해서 그것을 가지고 디자인, 설계, 개발, 테스트 진행한다면 중간에 큰 문제가 발생했을 떄 고치는 것에 대한 심리적인 압박감을 느낀다. 그러기 때문에 단순하게 만들어진 아키텍처를 가지고 지속적으로 확장이 가능하도록 하는 것이다.

의사 결정을 최적화하라

모듈을 나누고 관심사를 분리하면 지엽적인 관리와 결정이 가능해진다.

결정에 대해 가장 적합한사람이 책임을 담당하는게 좋지만 해당 결정은 최대한 미루는 것이 좋다. 많은 정보를 얻고 최선의 선택을 할 수 있기 때문이다.

시스템은 도메인 특화 언어가 필요하다.

대다수 도메인, 건축 분야역시 필수적인 정보를 명료하고 정확하게 전달하는 어휘, 관용구, 패턴이 풍바하다.

소프트웨어는 이런 언어를 DSL이라고 하는데 좋은 DSL은 도메인 개념과 그 개념을 구현한 코드 사이에 존재하는 의사소통 간극을 줄여준다. 그 뿐만 아니라 도메인 논리를 구현하면 도메인을 잘 못 구현할 가능성이 줄어든다.

결론

시스템 역시 깨끗해야 한다. 깨끗하지 못한 아키텍처는 도메인 논리를 흐리며 기민성을 떨어뜨린다.

모든 추상화 단계에서 의도는 명확히 표현해야 한다. 그러려면 POJO를 작성하고 관점 혹은 유사한 메커니즘을 사용해 각 구현 관심사를 분리해야 한다.

돌아가는 가장 단순한 수단을 사용해햐 한다는 사실을 명심해라.

key point

  • 제작과 사용은 아주 다르다. 제작과 사용을 동시에 하게 되면 해당 코드를 재분석해야될 수도 있으면 테스트 작성에 어려움이 존재할 수 있다.
  • 확장
    • 관심사 분리를 제대로 하지 못한 경우 혹은 애플리케이션과 프레임워크 사이에 존재하는 경우 확장에 어려움이 있다.

마무리

솔직히 글이 너무 어렵고 너무 특화된 정보라는 생각이 들었다. AOP 같은 경우 개념이 전혀 없고 자바를 모르는 경우 이해하기 너무 어려운 내용이라는 생각이 든다.

코드 영역이 아닌 아키텍처적인 큰 느낌을 설명한다는 생각은 들었지만 설명에 대한 큰 핵심이 무엇인지 잘 모르겠다.

Leave a comment