본문 바로가기
Study/Java

[Clean-Code] Chapter. 15-17(~G23)

by novxerim 2023. 7. 12.

Clean-Code_week6_yerimi11 (~p.285)

15. JUnit 들여다보기

image

  • 의도를 명확히 표현하려면 조건문을 캡슐화해야 한다. 즉, 조건문을 메서드로 뽑아내 적절한 이름을 붙인다.

image

  • if문은 긍정으로 만들어 조건문을 반전한다.
  • 불필요한 if문을 제거한다.
  • 코드를 리팩터링 하다보면 원래 했던 변경을 되돌리는 경우가 흔하다. 리팩터링은 코드가 어느 수준에 이를 때까지 수많은 시행착오를 반복하는 작업이기 때문이다.

=> 리팩토링 시 위의 내용들을 기억하면 좋을 것 같다. 또한 현재 업무 중 내가 개발한 코드를 리팩토링하는 과정에 있는데, 이전으로 돌아가는 경우가 잘못된 과정이 아님을 알고 여러 시도를 해봐야 겠는 생각이 든다.


16. SerialDAte 리팩터링

  • 코드를 고칠 때마다 단위 테스트를 실행했다.
  • 변수명은 늘 명확하게. getYYY -> getYear
  • 테스트케이스 외에 호출되지 않는 메서드라면 해당 메서드와 관련 테스트 케이스는 전부 삭제하자.

=> 리팩토링하는 과정이군..!


17. 냄새와 휴리스틱 (~G23)

전부 지양해야 할 사항들

[주석]

  • C1: 부적절한 정보
  • C2: 쓸모 없는 주석
  • C3: 중복된 주석
    • 코드만으로 충분한데 구구절절 설명하는 중복이 중복된 주석이다.
    • 함수 서명만 달랑 기술하는 Javadoc의 케이스도 중복된 주석이다.
  • C4: 성의없는 주석
  • C5: 주석 처리된 코드
    • github을 믿고 즉각 지워라.

[환경]

  • E1: 여러 단계로 빌드
  • E2: 여러 단계로 테스트

[함수]

  • F1: 너무 많은 인수
    • 함수에서 인수 개수는 작을수록 좋다. 넷 이상은 최대한 피한다.
  • F2: 출력 인수
  • F3: 플래그 인수
    • boolean 인수는 함수가 여러 기능을 수행한다는 먕백한 증거다. 플래그 인수는 흔란을 초래하므로 피해야 마땅하다.
  • F4: 죽은 함수
    • 아무도 호출하지 않는 함수는 삭제한다.

[일반]

  • G1: 한 소스 파일에 여러 언어를 사용한다
  • G2: 당연한 동작을 구현하지 않는다
    • 함수나 클래스는 읽었을 때 당연하게 여길만한 동작과 기능을 제공해야 한다.
  • G3: 경계를 올바로 처리하지 않는다
    • 흔히 개발자들은 머릿속에서 코드를 돌려보고 끝낸다.
    • 부지런함을 대신할 지름길은 없다.
    • 스스로의 직관에 의존하지 마라. 모든 경계 조건을 찾아내고, 모든 경계 조건을 테스트 하는 테스트 케이스를 작성하라.
  • G4: 안전 절차 무시
  • G5: 중복
    • 중복된 코드를 하위 루틴이나 다른 클래스로 분리하라.
    • 여러 모듈에서 일련의 switch/case나 if/else 문으로 똑같은 조건을 거듭 확인하는 중복 -> 다형성(polymorphism)으로 대체해야한다.
    • 알고리즘이 유사하나 코드가 서로 다른 중복 -> TEMPLATE METHOD 패턴이나 STRATEGY 패턴으로 제거한다.
  • G6: 추상화 수준이 올바르지 못하다
    • 세부 구현과 관련한 상수, 변수, 유틸리티 함수는 기초 클래스에 넣으면 안된다.
  • G7: 기초 클래스가 파생 클래스에 의존한다
  • G8: 과도한 정보
    • 클래스가 제공하는 메서드 수는 작을수록 좋다. 함수가 아는 변수 수도 작을수록 좋다. 클래스에 들어있는 인스턴스 변수 수도 작을수록 좋다.
    • 자료를 숨겨라. 유틸리티 함수를 숨겨라. 상수와 임시 변수를 숨겨라 메서드나 인스턴스 변수가 넘쳐나는 클래스는 피하라.
    • 하위 클래스에서 필요하다는 이유로 protected 변수나 함수를 마구 생성하지 마라. 인터페이스를 매우 작게 그리고 매우 깐깐하게 만들어라. 정보를 제한해 결합도를 낮춰라.
  • G9: 죽은 코드
    • 죽은 코드란 실행 되지 않는 코드
    • 불가능한 조건을 확인하는 if 문과 throw 문이 없는 try 문에서의 catch 블록
    • 아무도 호출하지 않는 유틸리티 함수와 switch/case문에서 불가능한 case 조건
  • G10: 수직 분리
    • 지역변수는 처음으로 사용하기 직전에 선언하며 수직으로 가까운 곳에 위치해야 한다
    • 비공개 함수는 처음으로 호출한 직후에 정의
    • 정의하는 위치와 호출하는 위치를 가깝게 유지
  • G11: 일관성 부족
    • 다른 함수에서도 일관성 있게 동일한 변수 이름을 사용한다.
  • G13: 인위적 결합
    • 서로 무관한 개념을 인위적으로 결합하지 않는다.
  • G18: 부적절한 static 함수
    • 일반적으로 static 함수보다 인스턴스 함수가 더 좋다. 조금이라도 의심스럽다면 인스턴스 함수로 정의한다.
  • G21: 알고리즘을 이해하라
    • 잠시 멈추고 실제 알고리즘을 고민해라
    • 알고리즘을 안다고 생각하지만 실제는 코드가 ‘돌아갈’ 때까지 이리저리 찔러보고 굴려본다. ‘돌아간다’는 사실은 어떻게 아느냐고? 생각할 수 있는 테스트 케이스를 모두 통과하니까.
    • 구현이 끝났다고 선언하기 전에 함수가 돌아가는 방식을 확실히 이해히는지 확인하라. 테스트 케이스를 모두 통과한다는 사실만으로 부족하다. 작성자가 알고리즘이 올바르다는 사실을 알아야 한다.
    • 코드가 돌아간다는 사실을 아는 것과 돌아가기 위한 알고리즘이 올바르다는 사실을 아는 것은 다르다. 흔히 개발 자들은 알고리즘이 올바르다고 확산하지 못한다. 게으름의 소치라 하겠다.
  • G22: 논리적 의존성은 물리적으로 드러내라
    • 의존하는 모든 정보를 명시적으로 요청하는 편이 좋다.
      image
    • PAGE_SIZE를 HourlyReporter 클래스에 선언한 실수는 잘못 지운 책임(G17)에 해당한다.
      HourlyRepoter 클래스는 HourlyReportFormatter가 페이지 크기를 알거라고 가정한다. 바로 이 가정이 논리적 의존성이다.
      HourlyRepoter 클래스는 HourlyReportFormatter 클래스가 페이지 크기 55를 처리할 줄 안다는 사실에 의존한다.
      만약 HourlyReportFormatter 구현 중 하나가 페이지 크기 55를 제대로 처리하지 못한다면 오류가 생긴다.
      HourlyReportFormatter에 getMaxPageSize()라는 메서드를 추가하면 논리적인 의존성이 물리적인 의존성으로 변한다.
      HourlyRepoter 클래스는 PAGE_ SIZE 상수를 사용하는 대신 getMaxPageSize() 함수를 호출하면 된다.
  • G23: If/Else 혹은 Switch/Case 문보다 다형성을 사용하라
    • ‘switch 문 하나’ 규칙을 따른다. 즉, 선택 유형 하나에는 switch 문을 한 번만 사용한다.

'Study > Java' 카테고리의 다른 글

[Clean-Code] Chapter. 17(G24~)~부록:동시성  (0) 2023.07.20
[Clean-Code] Chapter. 14  (1) 2023.07.11
[Clean-Code] Chapter. 11-13  (0) 2023.06.23
[Clean-Code] Chapter. 7-10  (0) 2023.06.22
[Clean-Code] Chapter. 4-6  (0) 2023.06.21

댓글