Hayden's Archive

클린코드(Clean Code) 7, 8장 - 로버트 C. 마틴 본문

Book

클린코드(Clean Code) 7, 8장 - 로버트 C. 마틴

_hayden 2021. 5. 31. 16:50

book.naver.com/bookdb/book_detail.nhn?bid=7390287

 

Clean Code

『CLEAN CODE(클린 코드)』은 오브젝트 멘토(OBJECT MENTOR)의 동료들과 힘을 모아 ‘개발하며’ 클린 코드를 만드는 최상의 애자일 기법을 소개하고 있다. 소프트웨어 장인 정신의 가치를 심어 주며

book.naver.com

 


7. 오류 처리

  • 오류 처리 코드로 인해 프로그램 논리를 이해하기 어려워진다면 깨끗한 코드라 부르기 어려움
  • 오류 코드보다 예외를 사용하라
    • 오류 플래그를 설정하거나 호출자에게 오류 코드를 반환하는 방법을 사용하면 호출자 코드가 복잡해짐
    • 오류가 발생하면 예외를 던지는 편이 낫다
  • Try-Catch-Finally 문부터 작성하라
    • try 블록은 트랜잭션과 비슷함
      • try 블록에서 무슨 일이 생기든지 catch 블록은 프로그램 상태를 일관성 있게 유지해야 함
    • 먼저 강제로 예외를 일으키는 테스트 케이스를 작성한 후 테스트를 통과하게 코드를 작성하는 방법을 권장함
      • 그러면 자연스럽게 try 블록의 트랜잭션 범위부터 구현하게 되므로 범위 내에서 트랜잭션 본질을 유지하기 쉬워짐
  • 미확인 예외를 사용하라
    • 지금은 안정적인 소프트웨어를 제작하는 요소로 확인된 예외가 반드시 필요하지는 않음
    • 확인된 예외는 OCP(Open Closed Principle)를 위반함
      • 하위 단계에서 코드를 변경하면 상위 단계 메서드 선언부를 전부 고쳐야 함
      • 모듈과 관련된 코드가 전혀 바뀌지 않았더라도 (선언부가 바뀌었으므로) 모듈을 다시 빌드한 다음에 배포해야
    • 대규모 시스템에서 최상위 함수가 아래 함수를 호출하고, 아래 함수는 그 아래 함수를 호출하고, 단계를 내려갈수록 호출하는 함수 수가 증가함
      • 최상위 함수를 변경해서 새로운 오류를 던진다고 가정
        • 확인된 오류를 던진다면 함수는 선언부에 throws 절을 추가해야 함
        • 변경한 함수를 호출하는 함수 모두가 1) catch 블록에서 새로운 예외를 처리하거나 2) 선언부에 throw 절을 추가해야 함
        • 결과적으로 최하위 단계에서 최상위 단계까지 연쇄적인 수정이 일어남
          • thorws 경로에 위치하는 모든 함수가 최하위 함수에서 던지는 예외를 알아야 하므로 캡슐화가 깨짐
    • 아주 중요한 라이브러리를 작성할 경우 모든 예외를 잡아야 하지만, 일반적인 애플리케이션은 확인된 예외에서 의존성이라는 비용이 이익보다 큼
  • 예외에 의미를 제공하라
    • 예외를 던질 때는 전후 상황을 충분히 덧붙여서 오류가 발생한 원인과 위치를 찾기 쉽게 함
    • 오류 메시지에 정보를 담아 예외와 함께 던짐(실패한 연산 이름과 실패 유형도 언급)
    • 애플리케이션이 로깅 기능을 사용한다면 catch 블록에서 오류를 기록하도록 충분한 정보를 넘김
  • 호출자를 고려해 예외 클래스를 정의하라
    • 외부 API를 사용할 때는 감싸기 기법이 최선
      • 외부 API를 감싸면 외부 라이브러리와 프로그램 사이에서 의존성이 크게 줄어듦
      • 또한 감싸기 클래스에서 외부 API를 호출하는 대신 테스트 코드를 넣어주는 방법으로 프로그램을 테스트하기도 쉬워짐
      • 특정 업체가 API를 설계한 방식에 발목을 잡히지 않음
        • 프로그램이 사용하기 편리한 API를 정의하면 그만
      • 예외 클래스에 포함된 정보로 오류를 구분해도 괜찮은 경우, 예외 클래스가 하나만 있어도 충분함
      • 한 예외는 잡아내고 다른 예외는 무시해도 괜찮은 경우라면 여러 예외 클래스 사용

 


8. 경계

  • 모든 소프트웨어를 직접 개발하는 경우는 드물다
    • 그렇다면 어떻게 외부 코드를 우리 코드에 깔끔하게 통합할 것인가?
    • 소프트웨어 경계를 깔끔하게 처리하는 기법과 기교

 

  • 외부 코드 사용하기
    • 경계 인터페이스인 Map을 Sensors 안으로 숨기기
      • Map 인터페이스가 변하더라도 나머지 프로그램에는 영향을 미치지 않음
      • Sensors 클래스 안에서 객체 유형을 관리하고 변환하므로 제네릭스를 사용하든 하지 않든 더 이상 문제가 되지 않음
      • Sensor 클래스는 프로그램에 필요한 인터페이스만 제공
        • 코드 이해는 쉽고 오용은 어려움
        • 설계 규칙과 비즈니스 규칙을 따르도록 강제
    • 경계 인터페이스를 사용할 때 유의할 점
      • 이를 이용하는 클래스나 클래스 계열 밖으로 노출되지 않도록 주의
      • Map 인스턴스를 공개 API의 인수로 넘기거나 반환값으로 사용하지 않음

 

  • 경계 살피고 익히기
    • 학습 테스트
      • 우리쪽 코드를 작성해 외부 코드를 호출하는 대신 먼저 간단한 테스트 케이스를 작성해 외부 코드를 익힘
      • 프로그램에서 사용하려는 방식대로 외부 API 호출
      • API를 사용하려년 목적에 초점

 

  • log4j 익히기
    • 간단한 콘솔 로거를 초기화한 방법을 익힌 후 모든 지식을 독자적인 로거 클래스로 캡슐화
      • 나머지 프로그램은 log4j 경계 인터페이스를 몰라도 됨

 

  • 학습 테스트는 공짜 이상이다
    • 학습 테스트는 이해도를 높여주는 정확한 실험
    • 패키지 새 버전이 나온다면 학습 테스트를 돌려 차이가 있는 확인
      • 새 버전이 우리 코드와 호환되지 않으면 학습 테스트가 이 사실을 곧바로 밝혀냄
    • 어차피 실제 코드와 동일한 방식으로 인터페이스를 사용하는 테스트 케이스가 필요
      • 이런 경계 테스트가 있다면 패키지의 새 버전으로 이전하기 쉬워짐경계 테스트가 있다면 패키지의 새 버전으로 이전하기 쉬워짐

 

  • 아직 존재하지 않는 코드를 사용하기
    • 아는 코드와 모르는 코드를 분리하는 경계
    • 우리가 바라는 인터페이스를 구현하면 우리가 인터페이스를 전적으로 통제할 수 있고, 코드 가독성이 높아지며, 코드 의도도 분명해짐

 

  • 깨끗한 경계
    • 경계에 위치하는 코드는 깔끔히 분리함
    • 기대치를 정의하는 테스트 케이스도 작성
    • 통제 불가능한 외부 패키지에 의존하는 대신 통제가 가능한 우리 코드에 의존하는 편이 훨씬 좋음
    • 외부 패키지를 호출하는 코드를 가능한 줄여 경계 관리하기
      • 새로운 클래스로 경계를 감싸기
      • ADAPTER 패턴을 사용해서 우리가 원하는 인터페이스를 경계가 감싸기
      • ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환
    • 코드 가독성이 높아지며, 경계 인터페이스를 사용하는 일관성도 높아지고, 외부 패키지가 변경했을 때 변경할 코드가 줄어듦