Clean Code 읽기(9)

17장 냄새와 휴리스틱

  • “Refactoring”에서 마틴 파울러는 다양한 ‘코드 냄새’를 한다. 거기에 추가한 ‘냄새’들과 코드를 짜면서 사용하는 기교와 휴리스틱을 소개한다.
  • 🙋‍♂️ 리팩토링 책은 클린코드를 다 읽은 후 다음에 읽을 책이다.

자바

  1. 긴 import 목록을 피하고 와일드카드를 사용하라
    • 패키지에서 클래스 둘 이상을 사용한다면 와일드카드를 사용해 패키지 전체를 가져와라.
  2. 상수는 상속하지 않는다.
    • 상수를 상속 계층 맨 위에 숨겨놓으면 안된다. 언어의 범위 규칙을 속이는 행위이다. 대신 static import를 사용해라
  3. 상수 대 Enum
    • public static final int라는 옛날 기교보다 enum을 활용해라
    • enum은 이름이 부여된 열거체기 때문에 유연하고 서술적인 강력한 도구이다.
  • 🙋‍♂️ 크게 어려움이 없는 내용이긴한데, 아직 enum에 대해 자세히 알지는 못한다. 자바역량이 떨어지기 때문인데.. 공부할게 개많다 흑흑

이름

  1. 서술적인 이름을 사용해라

    • 소프트웨어 가독성의 90%는 이름이 결정한다.
    • 신중하게 선택한 이름은 추가 설명을 포함한 코드보다 강력하다. 신중하게 선택한 이름을 보고 모듈 내 다른 함수가 하는 일을 짐작할 수 있다.
    • 🙋‍♂️ 90%라는 수치에 엄청 공감한다. 클린 코드라는 책을 보기전에 그냥 int a, int temp등 의미를 알수없는 지역변수를 많이 사용했다. 그리고 함수로 추출하는 생각을 아에 하지않았다. 그러면서 코드는 길어지게되고 읽기 힘든 코드가 된다.
    • 🙋‍♂️ 여기서 웃긴건 읽기 힘든 코드가 되는걸 파악할 수가 없었다. 왜? 내가 한번 짠 코드를 다시 안봤으니까; 이것만으로도 클린코드를 읽기전과 지금 개발 능력 갭은 많이 차이난다고 생각한다.
    • 🙋‍♂️ 이전에는 코드쓰는게 그냥 과제제출? 용도라고 생각했다면 지금은 어떻게 짜면 더 읽기 편할까? 라는 생각을 항상 하게된다. 좋은 현상인것같다.
  2. 적절한 추상화 수준에서 이름을 선택하라

    • 구현을 드러내는 이름을 피하라. 작업 대상 클래스나 함수가 위치하는 추상화 수준을 반영하는 이름을 선택하라. 안정적인 코드를 만들려면 지속적인 개선과 노력이 필요하다.

      public interface Modem {
        boolean dial(String phoneNumber);
        boolean disconnect();
        boolean send(char c);
        char recv();
        String getConnectedPhoneNumber();
      }
      
      • 모뎀에서 전화번호가 아닌 다른방법으로 통신할 수 있기때문에 전화번호라는 추상화 수준이 틀렸다.
      public interface Modem {
        boolean connect(String connectionLocator);
        boolean disconnect();
        ...
      }
      
      • 이제 더 이상 전화번호로 제한하지 않고, 다른 연결방식도 가능하다.
    • 🙋‍♂️ 추상화 개념이 너무 어렵다. 저 코드를 직접 쓰면서 추상화 수준이 어디가 다른지 파악하지 못했다.

  3. 가능하다면 표준 명명법을 사용하라

    • toString같은 패턴이나 특정 프로젝트에 유효한 의미가 담긴 이름을 많이 사용해야 코드 이해하기가 쉬워진다.
  4. 명확한 이름

    • 함수나 변수의 목적을 명확히 밝히는 이름을 선택한다.
  5. 긴 범위는 긴 이름을 사용해라

    • 이름의 길이는 범위 길이에 비례해야한다. 이름 범위가 길어질수록 정확하고 길게 짓는다.
  6. 인코딩을 피하라

    • 헝가리안 표기법같은 접두어 사용을 피해라, 독자만 혼란스럽게 만든다.
  7. 이름으로 부수 효과를 설명하라

    • 여러 작업을 수행하는 함수에 동사 하나만 달랑 사용하면 곤란하다.

      public ObjectOuputStream getOos() throws IOException {
        if (m_oos == null) {
          m_oos = new ObjectOutputStream(m_socket.getOutputStream());
        }
        return m_oos;
      }
      
      • 단순히 oos만 반환하는것이 아니다. 기존에 oos가 없다면 생성한다 따라서 createOrReturnOos라는 이름이 더 좋다.
    • 🙋‍♂️ 그런데 메서드는 한가지 일만 해야 한다고 했으니 그냥 createOos메서드랑 getOos메서드로 분리하는게 더 나을것 같다.

테스트

  1. 불충분한 테스트
    • 테스트 케이스는 잠재적으로 깨질 만한 부분을 모두 테스트해야 한다.
    • 테스트가 확인하지 않는 조건이나 검증하지 않은 계산이 있으면 불완전하다.
  2. 커버리지 도구를 사용하라
    • 커버리지 도구는 테스트가 빠뜨리는 공백을 알려준다. (테스트 성공은 녹색, 실패는 붉은색 등..)
  3. 사소한 테스트를 건너뛰지 마라
    • 사소한 테스트는 짜기 쉽다. 테스트가 제공하는 문서적 가치는 구현에 드는 비용을 넘어선다.
    • 🙋‍♂️ 테스트 케이스 자체가 문서화에 도움이 된다는 말인것같다.
  4. 무시한 테스트는 모호함을 뜻한다.
    • 불분명한 요구사항은 테스트 케이스를 주석으로 처리하거나 @Ignore를 붙여 표현한다.
  5. 경계 조건을 테스트하라
    • 경계 조건은 각별히 신경 써서 테스트한다. 알고리즘의 중앙 조건은 잘 짜놓고 경계 조건에서 실수하는 경우가 흔하다.
  6. 버그 주변은 철저히 테스트하라
    • 버그는 모이는 경향이 있다. 버그를 발견했다면 그 함수를 철저히 테스트해라
  7. 실패 패턴을 살펴라
    • 때로는 테스트 케이스가 실패하는 패턴으로 문제를 진단할 수 있다.
  8. 테스트 커버리지 패턴을 살펴라
    • 통과하는 테스트가 실행하거나 실행하지 않는 코드를 살펴보면 원인을 찾을 수 있다.
  9. 테스트는 빨라야 한다.
    • 느린 테스트 케이스는 실행하지 않게된다. 테스트 케이스가 빨리 돌아가게 최대한 노력한다.

🙋‍♂️테스트 코드라는 것 자체를 알게된게 얼마 되지 않는다. 그 전에는 Scanner로 내가 직접 입력하곤 했다. 요즘은 테스트 코드를 만들어 하나씩 검증하는것이 훨씬 편하고 빠르다는것을 느낀다.

🙋‍♂️ 한가지 문제가 있다면 스프링이나 웹에서도 테스트코드를 적용할 수 있는가이다. 또한 외부 API호출관련해서도 잘 모르겠다.

댓글남기기