[클린코드] 17장 냄새와 휴리스틱

JUN·2024년 8월 19일
0

클린코드

목록 보기
14/14

17장 냄새와 휴리스틱

주석.

C1: 부적절한 정보

  • 다른 시스템에 저장할 정보는 주석으로 적절하지 않음.
  • 변경 이력 등 메타 정보는 소스 코드를 번잡하게 만듦.
  • 주석은 코드와 설계에 기술적인 설명을 부연하는 수단.

C2: 쓸모없는 주석

  • 오래된, 엉뚱한, 잘못된 주석은 쓸모없음.
  • 쓸모없어진 주석은 빨리 삭제하는 것이 좋음.
  • 쓸모없는 주석은 코드와 무관하게 따로 놀며 코드를 그릇된 방향으로 이끔.

C3: 중복된 주석

  • 코드만으로 충분한 내용을 설명하는 주석은 중복된 주석임.
  • 주석은 코드만으로 다하지 못하는 설명을 부연하는 역할을 해야 함.

C4: 성의 없는 주석

  • 작성할 가치가 있는 주석은 잘 작성할 가치도 있음.
  • 시간을 들여 간결하고 명료하게 작성해야 함.

C5: 주석 처리된 코드

  • 주석 처리된 코드는 오래되거나 불필요한 코드일 가능성이 큼.
  • 소스 코드 관리 시스템이 이전 버전을 기억하므로 주석 처리된 코드는 즉각 삭제하는 것이 좋음.

환경.

E1: 빌드 과정의 단순화

  • 빌드 과정은 단일 명령어로 완료되어야 하며, 소스 코드 관리 시스템에서 개별적으로 체크아웃할 필요 없이 전체를 한 번에 체크아웃하고 빌드할 수 있어야 함.
  • SVN을 통해 프로젝트를 체크아웃한 후, 한 명령어로 모든 것을 빌드할 수 있어야 함.

E2: 테스트 프로세스의 단순화

  • 모든 단위 테스트는 한 번에 실행할 수 있어야 하며, IDE에서도 버튼 하나로 전체 테스트를 실행할 수 있어야 함.
  • 셸에서도 단일 명령어로 모든 테스트를 실행할 수 있어야 하며, 이는 개발자에게 중요한 기능임.

함수.

F1: 함수의 인수 개수 최소화

  • 함수의 인수 개수는 작을수록 좋으며, 가능하면 인수 없이 함수를 구현하는 것이 이상적임.
  • 최대한 한 개 이내의 인수를 가진 함수를 설계하고, 네 개 이상의 인수는 사용을 피해야 함.

F2: 출력 인수의 사용 제한

  • 함수에서는 출력 인수를 사용하지 말고, 대신 함수가 속한 객체의 상태를 변경하는 방식을 사용해야 함.
  • 함수는 입력을 받아 처리한 후에 객체의 상태를 변화시키는 방식으로 설계되어야 함.

F3: 플래그 인수의 사용 제한

  • boolean 타입의 플래그 인수는 함수의 여러 기능을 명시적으로 나타내는 것이므로 혼란을 초래할 수 있으며, 가능하면 피해야 함.
  • 함수 호출 시 다양한 옵션을 플래그로 전달받는 방식은 코드의 가독성과 유지보수성을 저해할 수 있음.

F4: 죽은 함수 제거

  • 실행되지 않는 함수는 시스템에서 삭제해야 하며, 이는 코드의 불필요한 복잡성을 줄이는 데 중요함.
  • 사용되지 않는 함수는 삭제하고, 시스템에서 죽은 코드를 제거함으로써 코드 베이스를 깔끔하게 유지해야 함.

일반

G1: 소스 파일에서의 다중 언어 사용 최소화

  • 소스 파일은 하나의 언어로 작성하는 것이 이상적이지만 현실적으로 여러 언어를 사용해야 할 경우, 최대한 언어의 수와 범위를 줄이는 것이 중요함.
  • Java 파일 내에 XML, HTML, JavaScript 등의 다양한 언어를 포함하지 않도록 노력해야 함.

G2: 기대하는 동작의 구현

  • 함수나 클래스는 다른 프로그래머가 기대할 수 있는 동작을 제공해야 하며, "최소 놀람의 원칙"에 따라 일관된 동작을 구현해야 함.
  • 함수가 입력받은 문자열을 정확히 enum 값으로 변환하거나, 대소문자를 구분하지 않고 처리하는 등의 구현이 필요함.

G3: 경계 조건의 올바른 처리

  • 코드는 모든 경계 조건에서 올바로 동작해야 하며, 모든 예외 상황을 고려하여 테스트 케이스를 작성하는 것이 중요함.
  • 코드에서 예외 상황을 처리하지 않고 흘려보내지 않고, 모든 경계 조건을 명확히 처리해야 함.

G4: 안전 절차의 중요성

  • 안전 절차를 무시하면 시스템에 심각한 위험이 발생할 수 있으며, 컴파일 경고를 무시하거나 실패하는 테스트 케이스를 미루는 태도 역시 위험할 수 있음.
  • serialVersionUID의 직접 제어와 같은 절차적 결정은 신중하게 이루어져야 하며, 시스템의 안정성을 위해 필수적인 절차를 준수해야 함.

G5: 코드의 중복 최소화

  • 중복된 코드는 추상화를 통해 제거되어야 하며, 함수 내에서 반복되는 코드는 하위 루틴으로 분리하거나 다형성을 이용해 해결해야 함.
  • 코드를 추상화하여 중복을 제거하면 유지보수성과 코드의 응집력이 향상되며, 디자인 패턴을 활용해 중복을 최소화해야 함.

G6: 올바른 추상화 수준 유지

  • 추상화는 저차원 세부 사항을 고차원 개념과 분리해야 하며, 상수나 변수와 같은 세부 사항은 기초 클래스에 포함하고, 고차원 개념은 파생 클래스에 포함해야 함.
  • 추상 클래스와 인터페이스를 통해 코드를 추상화하고, 모듈이나 컴포넌트도 분리하여 정리해야 코드의 응집성을 높일 수 있음.

G7: 의존성 관리

  • 기초 클래스는 파생 클래스에 의존해서는 안 되며, 독립적인 구성 요소로 분리해야 시스템의 유연성을 유지할 수 있음.
  • 기초 클래스가 파생 클래스의 구현에 대해 직접적인 의존성을 가지면 시스템의 확장성이 제한될 수 있으므로, 이를 피해야 함.

G8: 인터페이스의 간결성 유지

  • 잘 정의된 인터페이스는 많은 함수를 제공하지 않고도 충분히 동작할 수 있어야 하며, 결합도를 낮추는 것이 중요함.
  • 인터페이스는 필요한 기능만을 제공하고, 불필요한 함수나 변수는 숨겨야 함.

G9: 죽은 코드 제거

  • 실행되지 않는 코드는 시스템에서 제거해야 하며, 이는 코드의 복잡성을 줄이고 시스템의 유지보수성을 높이는 데 도움이 됨.
  • 사용되지 않는 변수나 함수, 불가능한 조건을 확인하는 코드 등은 제거되어야 하며, 이는 시스템의 안정성과 가독성에 긍정적인 영향을 미침.

G10: 과도한 최적화 피하기

  • 최적화는 시스템이 충분히 실행되지 않을 때에만 신경쓰도록 하고, 미리 최적화하는 것은 시간 낭비일 수 있음.
  • 시스템에서 실질적으로 문제가 되는 부분만을 최적화하고, 일반적인 성능 향상을 위해 지나치게 시간을 낭비하지 않도록 주의해야 함.

G11: 코드의 단순성 강조

  • 코드는 가능한 한 단순하게 유지해야 하며, 직관적이고 명확한 구현이 필요함.
  • 코드를 간결하게 유지하면 읽기 쉽고 이해하기 쉬워지며, 디버깅이나 유지보수 과정에서의 실수를 줄일 수 있음.

G12: 프로그래머의 편리함 고려

  • 코드는 다른 개발자들도 쉽게 이해하고 수정할 수 있도록 작성해야 하며, 효율적인 작업을 가능하게 하는 도구나 기법을 적극적으로 활용해야 함.
  • 적절한 주석과 문서화, 일관된 코드 스타일 등은 코드의 가독성을 높이고, 개발자들이 협업할 때 편리함을 제공함.

G13: 인위적 결합

  • 인위적 결합은 서로 무관한 개념을 강제로 결합하는 것을 말함. 예를 들어, enum이나 범용 static 함수를 특정 클래스에 속하게 만드는 것은 이 개념에 해당함. 이는 코드를 의도치 않게 복잡하게 만들 수 있음.

G14: 기능 욕심

  • 기능 욕심은 클래스 메서드가 다른 클래스의 변수와 함수에 너무 많이 의존하는 것을 의미함. 이는 객체 지향 설계 원칙을 위배할 수 있으며, 필요 이상으로 클래스 간 결합을 높이는 결과를 초래할 수 있음.

G15: 선택자 인수

  • 선택자 인수는 함수의 동작을 선택하기 위해 넘겨주는 인수를 말함. 이는 여러 함수를 하나로 합치는 결과를 초래할 수 있으며, 코드의 가독성을 떨어뜨릴 수 있음. 함수 호출 시 목적을 명확히 드러내는 것이 중요함.

G16: 모호한 의도

  • 모호한 의도는 코드에서 의도를 명확하게 드러내지 않는 것을 말함. 이는 코드를 이해하고 유지보수하기 어렵게 만들 수 있으며, 코드 가독성을 저하시킬 수 있음. 명확하고 직관적인 변수명과 함수명을 사용하는 것이 중요함.

G17: 잘못 지운 책임

  • 잘못 지운 책임은 한 모듈이 다른 모듈에 대해 논리적인 의존성을 가지고 있지만 이를 물리적으로 드러내지 않는 경우를 의미함. 이는 코드를 예상치 못한 방향으로 복잡하게 만들 수 있음.

G18: 부적절한 static 함수

  • 부적절한 static 함수는 특정 인스턴스와 관련이 있는 기능을 static으로 정의하는 것을 말함. 이는 객체 지향 설계 원칙을 위배할 수 있으며, 코드의 유연성을 저하시킬 수 있음. 인스턴스 함수로 정의할 수 있는지 고민해야 함.

G19: 서술적 변수

  • 서술적 변수는 계산의 여러 단계에서 중간값으로 사용되는 변수명을 명확하고 서술적으로 지으면 코드의 가독성을 높일 수 있음. 코드를 이해하고 유지보수하기 쉽게 만드는 데 중요한 역할을 함.

G20: 이름과 기능이 일치하는 함수

  • 이름과 기능이 일치하지 않는 함수는 코드의 이해를 어렵게 만들 수 있음. 함수의 이름을 통해 함수가 어떤 기능을 수행하는지 명확하게 드러나야 함.

G21: 알고리즘을 이해하라

  • 코드를 작성할 때는 구현한 알고리즘을 완전히 이해하고 작성해야 함. 단순히 테스트 케이스만 통과한다고 해서 충분하지 않으며, 알고리즘이 코드의 의도를 정확하게 반영해야 함.

G22: 논리적 의존성은 물리적으로 드러내라

  • 한 모듈이 다른 모듈에 논리적으로 의존한다면 이를 코드에서 명시적으로 드러내야 함. 논리적 의존성만으로는 부족하며, 코드의 예상치 못한 동작을 방지할 수 있음.

G23: If/Else 혹은 Switch/Case 문보다 다형성을 사용하라

  • If/Else 혹은 Switch/Case 문보다 다형성을 사용하는 것이 바람직함. 이는 객체 지향 설계의 원칙을 따르며, 코드의 유연성과 확장성을 높이는 데 도움이 됨.

G24: 표준 표기법을 따르라

  • 팀 내에서 사용하는 표준 표기법을 따르는 것이 중요함. 이는 코드의 일관성을 유지하고 팀원들 간 협업을 원할하게 만드는 데 기여함.

자바.

J1: 긴 import 목록을 피하고 와일드카드를 사용하라.

  • 패키지에서 둘 이상의 클래스를 사용하면 “*” 를 사용할 것.

J2: 상수는 상속하지 않는다.

  • 상수를 사용할 때는
    private static final int TENTHS_PER_WEEK = 400;
    과 같이 private로 사용할 것.
  • 상수를 상속받고 싶을때는 static import 를 사용할 것
    import static Constants.*;

J3: 상수 vs Enum

  • 상수 상속보다는 Enum을 사용하는게 좋음
  • 메서드, 필드도 사용가능하니 참고할 것.

이름

N1: 서술적인 이름을 사용하라

  • 소프트웨어의 진화와 함께 의미가 변하는 이름을 신중하게 선택함. 이름은 코드의 가독성에 중대한 영향을 미침. 코드를 이해하는 데 있어 신중하게 선택된 서술적인 이름은 필수적임.

N2: 적절한 추상화 수준에서 이름을 선택하라

  • 구현을 드러내는 이름보다는 클래스나 함수가 위치한 추상화 수준을 반영하는 이름을 선택함. 추상화 수준을 고려하여 이름을 지으면 코드 이해가 더 쉬워짐.

N3: 가능하면 표준 명명법을 사용하라

  • 표준 명명법을 사용하면 코드를 읽고 이해하기 쉬워짐. 프로젝트에 맞는 명명 규칙을 정하고 일관성 있게 사용함.

N4: 명확한 이름을 선택하라

  • 함수나 변수의 목적이 명확히 드러나도록 이름을 선택함. 이름만으로 함수가 수행하는 작업을 명확히 이해할 수 있어야 함.

N5: 긴 범위는 긴 이름을 사용하라

  • 변수나 함수의 범위가 커질수록 이름을 길고 정확하게 짓음. 범위가 작을 때는 간결한 이름을 사용해도 되지만, 범위가 커질수록 이름을 확실하게 지어야 함.

N6: 인코딩을 피하라

  • 유형이나 범위 정보를 이름에 인코딩하지 않음. 명확하고 중복되지 않는 이름을 선택하여 코드의 가독성을 높임.

N7: 이름으로 부수 효과를 설명하라

  • 함수나 변수의 이름을 통해 부수적인 효과를 알 수 있도록 함. 이름만으로도 함수나 변수가 수행하는 작업을 이해할 수 있어야 함.

테스트

T1: 불충분한 테스트

  • 충분한 테스트 케이스 필요
  • 테스트되지 않는 조건이나 계산이 있으면 불완전

T2: 커버리지 도구를 사용하라!

  • 테스트 커버리지 도구 사용
  • 테스트가 빠진 부분을 시각적으로 확인

T3: 사소한 테스트를 건너뛰지 마라

  • 사소한 테스트도 중요
  • 문서적 가치 제공

T4: 무시한 테스트는 모호함을 뜻한다

  • 불분명한 요구사항은 주석 또는 @Ignore로 표시
  • 모호한 테스트 케이스는 컴파일 가능한지 확인

T5: 경계 조건을 테스트하라

  • 경계 조건 테스트 중요
  • 중앙 조건보다 경계 조건에서 실수 빈번

T6: 버그 주변은 철저히 테스트하라

  • 버그 주변 함수 철저히 테스트
  • 다른 버그 발견 가능성 높음

T7: 실패 패턴을 살펴라

  • 테스트 케이스 실패 패턴 분석
  • 실패 패턴으로 문제 진단
  • 합리적인 순서로 정렬된 테스트 케이스 중요
profile
순간은 기록하고 반복은 단순화하자 🚀

0개의 댓글