[기술독서모임] Clean Code 8장

·2020년 9월 21일
0

기술독서

목록 보기
8/12
post-thumbnail

Clean Code 8장 경계

시스템에 들어가는 모든 소프트웨어를 직접 개발하는 경우는 드물다.
...
어떤 식으로든 이 외부 코드를 우리 코드에 깔끔하게 통합해야만 한다.

경계

  • 외부 프로그램을 가져와서 나의 프로그램에 통합할 때의 경계
  • 아는 코드와 모르는 코드를 분리하는 경계

외부 코드 사용하기❓❗

인터페이스 제공자 : 적용성을 최대한 넓히려고 함
인터페이스 사용자 : 자신의 요구에 집중하는 인터페이스를 원함

이런 서로의 초점이 다르기 때문에 시스템 경계에서 문제가 생기기도 함

ex) java.utill.Map

//Sensor라는 객체를 담는 Map을 만들 때
Map sensors = new HashMap();

//Sensor 객체가 필요한 코드를 가져올 때
Sensor s = (Sensor)sensors.get(sensorId);

이 코드에서는 Map이 반환하는 Object를 올바른 유형으로 변환할 책임은 Map을 사용하는 클라이언트에 있다.

제네릭스를 사용하면 코드 가독성이 높아진다.

Map<String, Sensor> sensors = new HashMap<Sensor>();
...
Sensor s = sensors.get(sensorId);

이 코드에서는 Map<String, Sensor> 인스턴스를 여기저기로 넘긴다면, Map 인터페이스가 변할 때, 수정할 코드가 상당히 많아진다.

경계 인터페이스인 Map을 Sensors 안으로 숨기는 방법을 사용한다.

public class Sensors {
  private Map sensors = new HashMap();
  
  public Sensor getById(String id) {
    return (Sensor) sensors.get(id);
    }
}

이렇게 할 경우 Map 인터페이스가 변하더라도 나머지 프로그램에는 영향을 미치지 않는다.

경계 인터페이스를 사용할 때

  • 경계 인터페이스를 여기저기 넘기지 않기
  • 경계 인터페이스를 이용하는 클래스나 클래스 계열 밖으로는 노출되지 않도록 주의하기

경계를 살피고 익히기🤔

외부에서 가져온 라이브러리를 사용할 때

  • 하루나 이틀(아니면 더 오랫동안) 문서를 읽으며 사용법 결정
  • 우리쪽 코드를 작성해 라이브러리가 예상대로 동작하는지 확인
  • 버그 발생 시 우리 버그인지, 라이브러리 버그인지 디버깅

외부 코드를 익히고 통합하기는 어렵기 때문에 학습 테스트 방법을 이용하면 좋다.

학습 테스트

  • 간단한 테스트 케이스를 작성해 외부 코드를 익히는 것
  • 프로그램에서 사용하려는 방식대로 외부 API를 호출하기 때문에 사용하려는 목적에 초점을 맞춤

log4j 익히기🔗

로깅 기능을 직접 구현하는 대신 아파치의 log4j 패키지를 사용한다고 했을 때 간단한 테스트 케이스들을 통해 log4j가 돌아가는 방식을 이해한다.

@Test
public void testLogCreate() {
  Logger logger = Logger.getLogger("MyLogger");
  logger.info("hello");
}

//Appender가 필요함
@Test
public void testLogAddAppender() {
  Logger logger = Logger.getLoger("MyLogger");
  ConsoleAppender appender = new ConsolAppender();
  logger.addAppender(appender);
  logger.info("hello");
}

//Appender에 출력 스트림이 없음
@Test
public void testLogAddAppender() {
  Logger logger = Logger.getLoger("MyLogger");
  logger.removeAllAppenders();
  logger.addAppender(new ConsoleAppender(new PatternLayout(
                  "%p %t %m%n"), ConsoleAppender.SYSTEM_OUT));
  logger.info("hello");
}

테스트 케이스를 통해 log4j가 어떻게 돌아가는 지를 이해하고 여기서 얻은 것들을 독자적인 로거 클래스로 캡슐화한다. 그러면 나머지 프로그램은 log4j 경계 인터페이스를 몰라도 된다.

학습 테스트는 공짜 이상이다💡

학습 테스트

  • 이해도를 높여주는 정확한 방법
  • 패키지가 예상대로 도는지 검증
  • 새로운 패키지가 나왔을 때 우리 코드와 호환되지 않으면 밝혀줌

학습 테스트를 이용한 학습이 필요하든 아니든, 실제 코드와 동일한 방식으로 인텊이스를 사용하는 테스트 케이스가 필요하다. 이런 경계 테스트가 있다면 패키지의 새 버전으로 이전하기 쉬워진다.

아직 존재하지 않는 코드를 사용하기💭

경계에는 아는 코드와 모르는 코드를 분리하는 경계의 유형이 있다. 때로는 우리 지식이 경계를 너머 미치지 못하는 코드 영역도 있다.

ex) 무선통신 시스템에 들어간느 소프트웨어 개발
소프트웨어의 하위 시스템 중에 송신기가 있는데 여기에 대한 지식이 거의 없음
송신기 API가 설계되지 않음

송신기 모듈에 원하는 기능
지정한 주파수를 이용해 이 스트림에서 들어오는 자료를 아날로그 신호로 전송

만들어지기 바라는 송신기 인터페이스를 자체적으로 정의
송신기 API가 정의된 후에 TransmitterAdapter를 구현
API 사용을 캡슐화 해 API가 바뀔 때 수정할 코드를 한곳으로 모음

깨끗한 경계✨

경계에 위치하는 코드는 깔끔히 분리한다. 기대치를 정의하는 테스트 케이스도 작성한다.

통제 불가능한 외부 패키지에 의존하는 대신 통제가 가능한 우리 코드에 의존하는 편이 훨씬 좋다.

외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하는 것이 좋다.
새로운 클래스로 경계를 감싸거나, ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환한다.


느낀점🙊

외부 패키지를 가져와서 사용을 할 때 외부 코드를 우리 코드에 깔끔하게 통합하는 방법에 대해 이야기 하고 있다. 외부 코드를 가져와서 코드를 통합하고 프로그램을 짜고 해본적이 없어서 이번 내용이 좀 어렵게 느껴졌다. 하지만 동시에 이 부분을 제대로 공부해야겠다는 필요성도 동시에 느꼈다.

이 장의 처음에서 말한 것처럼 시스템에 들어가는 모든 소프트웨어를 직접 개발하지 않고 외부 코드를 가져와서 사용한다. 그렇다면 앞으로 분명히 내가 경험을 하게 될 것이다. 외부 패키지를 이해하고 코드를 짜고 내 코드와 다시 외부 코드를 통합하고... 그리고 버그가 나면 다시 버그를 찾고 수정하고...

깃헙으로 졸작을 작업하고 있는데 각자 작업하고 푸쉬하는 과정에서 처음으로 오류가 났던 적이 있었다. 왠지 모르겠는데 각자 돌릴 때는 잘 됬고 분명 게임 오브젝트에 Rigidbody 컴포넌트를 넣어놨다. 근데 master 브랜치에 merge 하고 실행할 때는 Rigidbody 컴포넌트가 사라져있었다... 이거 하나도 오류나면 이유를 찾고 수정해야 되는 문제로 머리가 아픈데... 외부 패키지는 얼마나 힘들까.. 하는 생각을 잠시 하게 됬다. 그래서 그만큼 더 신경써서 준비를 하고 처음부터 이 책에서 말한 방법을 기억하며 습관을 잘 들여야겠다.

profile
익숙함을 향해👟

0개의 댓글