본문 바로가기
개발/기타

클린 코드(Clean Code)

by 궁즉변 변즉통 통즉구 2023. 8. 26.
반응형

깨끗한 코드를 작성하는 방법은 배우기 어렵다. 단순히 원칙과 패턴을 안다고 깨끗한 코드가 나오지 않는다. 

고생을 해야한다. 연습하고 실패하고 다시 일어서야 한다.
결정을 내리느라 고민하는 모습, 잘못된 결정으로 대가를 치르는 모습도 봐야한다.
보이스카우트 규칙: "처음 왔을 때보다 더 깨끗하게 해놓고 떠나라.”

 

단순한 설계 규칙 4가지(중요도 순서)

1. 모든 테스트를 실행한다.
    - 리팩토링 쉽게 가능
 
2. 중복을 없앤다.
 
3. 프로그래머의 의도를 표현한다.
    - 좋은 이름선택, 함수,클래스 크리 줄이기, 표준명칭 사용, 단위 테스트 작성
 
4. 클래스와 메소드의 수를 최소로 줄인다.
 

 

냄새와 휴리스틱

1. 주석

   C1 부적절한 정보 - 코드,설계의 기술적인 설명이외의 변경이력 등은 주석으로 적절하지 못함.
   C2 쓸모없는 주석 - 오랜된, 엉뚱한, 잘못된 주석은 삭제. 코드와 따로 노는  주석은 필요없음.
   C3 중복된 주석 - 코드만으로 충분한데 구구절절 설명하는 주석 필요없음.
   C4 성의없는 주석 - 간단, 명료, 신중하게 주석을 작성하라.
   C5 주석처리된 코드 - 주석처리된 코드는 과감히 삭제하라. 소스코드 관리시스템으로 복구가능 
 * 좋은 주석 - 법적인 주석(저작권,소유권), 정보/의도를 명확히 하는 주석, 결과를 경고하는 주석, 중요성을 강조하는 주석
 

2. 환경

   E1 여러 단계의 빌드 - 빌드는 간단히 한 단계로 끝나야 한다.
   E2 여러 단계의 테스트 - 모든 단위 테스트는 한 명령으로 실행가능 해야함.
  

3. 함수

   F1 너무 많은 변수 - 함수에는 변수는 작을수록 좋음(없거나 1~3정도, 4이상은 최대한 피하는것이 좋음)
   F2 출력 변수 - 출력인수는 피해야함. 함수에서 상태를 변경한다면 훔수가 속한 객체 상태를 변경하는 방식이 맞음. 
                          ex> public void appendFooter(StringBuffer report)  ==>  report.appendFooter();
   F3 플래그 변수 - boolean 플래그 변수는 함수가 여러기능을 수행한다는 증거, 제거 필요
   F4 죽은 함수 - 아무도 호출하지 않은 함수는 무조건 삭제
 

4. 일반

  G1 한 소스파일에 여러 언어 - 한소스 파일에 사용하는 언어 수와 범위를 최대한 축소(ex. HTML, XML, Java 등 한 파일에 사용)
  G2 당연한 동작 구현 - 함수, 클래스는 이름이 제공하는 의미에서 당연히 여길 만한 기능과 동작을 제공해야 함(저자의 신뢰성)
  G3 경계 조건 - 모든 경계조건, 예외 상황을 테스트하라
  G4 안전 절차 무시 - 컴파일러 경고, 실패하는 테스트케이스를 무시하거나 미루지 마라
  G5 중복(DRY:Dont Repeat Yourself) - 중복을 발견하면 추상화 할 기회로 생각하고 중복을 제거하라.
  G6 추상화 수준 - 함수, 클래스에 고차원 개념과 저차원 개념이 섞여서는 안된다.
  G7 기초클래스가 파생클래스에 의존 - 기초클래스는 파생클래스를 몰라야 한다.
  G8 과도한 정보 - 상수,변수,함수가 많은 클래스는 피하라, 인터페이스는 작고 간결하게 작성해서 결합도를 줄여라
  G9 죽은코드 - 실행되지 않는 코드는 삭제하라(ex. 불가능한 조건체크if문, throw문이 없는 try문에서 catch블럭 등)
  G10 수직 분리 - 변수와 함수는 사용되는 위치에 가깝게 정의, 정의하는 위치와 호출하는 위치를 가깝게 유지
  G11 일관성 부족 - 코드에서의 명명 및 구현 방법에 일관성을 지켜라
  G12 잡동사니(쓸데없는 코드) - 빈 생성자, 호출되지 않는 함수, 의미없는 주석 등 삭제
  G13 인위적 결합 - 직접적인 상호작용, 명확한 목적없이 변수,상수,함수를 당장 편한 위치에(잘못된 위치) 놓지 마라.
  G14 기능욕심 - 다른 클래스의 변수,함수를 과도하게 사용해 내용을 조작하면 그 클래스는 범위를 욕심내는 것이다.
  G15 선택 변수 - boolean, int등 변수를 사용해서 함수의 동작을 선택하는 것은 함수를 분리하지 않으려는 게으름이다.
  G16 모호한 의도 - 코드 작성 시 의도를 최대한 분명하게 밝힌다(적절한 행 바꿈, 매직 번호, 헝가리 표기법 등)
  G17 잘못 지운(맡긴) 책임 - 코드 배치하는 위치를 신중하게 선택
  G18 부적절한 static 함수 - 일반적으로 static함수보다 인스턴스함수가 더 좋다. 의심스러우면 인스턴스함수로 작성하라.
  G19 서술적 표현 - 프로그램 가독성 높이기 위해서는 계산을 여러단계로 나누고 중간값에 서술적인 변수명을 사용하라.
  G20 이름과 기능이 일치하는 함수 - 명확하게 알수있는 함수명을 사용하라
  G21 알고리즘을 이해하라 - 알고리즘을 확인하고 이해하는 방법은 함수를 깔끔하고 명확하게 재구성하는 방법이 최고다
  G22 논리적인 의존성을 물리적으로 드러내라 - 상대 모듈에 뭔가를 가정하지 말고 명시적으로 요청(함수호출 등)하라
  G23 if/Else, Switch/Case 보다 다형성을 사용하라 - 다형성 객체를 생성하는 곳 외에는 switch문을 의심하라.
  G24 표준 표기법을 따르라 - 클래스,함수,변수의 명명규칙, 선언위치 등 규칙을 따르라(규칙 자체보다 모두가 동의하고 따르는것이 중요)
  G25 매직 숫자는 상수로 교체 - 숫자는 명명된 상수 뒤로 숨겨라
  G26 정확하라 - 코드의 모호성과 부정확성은 의견차나 게이름의 결과.
  G27 관례보다는 구조를 사용하라 - switch문을 매번 같은 형식으로 구현을 강제하는것은 어렵지만 추상메소드는 반드시 구현해야한다.
  G28 조건을 캡슐화 하라 - if,while문의 조건을 분명히 밝히는 함수로 표현하라(ex. if(shouldBeDeleted(timer)) )
  G29 부정 조건은 피하라 - 부정조건은 긍정조건보다 이해하기 어렵다(ex, if(!buffer.shouldNotCompact()) 어려움 )
  G30 함수는 한가지만 하라 - 함수는 한가지만 수행하는 작은 함수로 나눠야 한다.
  G31 숨겨진 시간적 결합 - 여러개 함수 호출 시 순서가 필요한 경우 적절한 변수사용으로 함수 호출 순서를 명확하게 드러내야 한다.
  G32 일관성을 유지하라 - 코드 구조에 일관성을 유지하라.
  G33 경계조건을 캡슐화 하라 - 코드 여기저기에 +1, -1(ex. level +1)을 흩어놓지 않는다. 변수 선언등으로 캡슐화
  G34 함수의 추상화 수준 분리 - 한 함수에 여러 추상화 수준을 단계별로 분리하라
  G35 설정정보는 최상위 단계에 둬라 - 기본값, 설정값 등은 고차원 함수에 선언하고 저차원 함수로 전달하라.
  G36 추이적 탐색을 피하라 - 내가 사용하는 모듈이 내게 필요한 서비스를 모두 제공해야한다. 원하는 메소드를 위해 객체 탐색할 필요 없어야함(ex. a.getB().getC()… : 중간에 다른 모듈 끼우기 어려움, 많은 모듈이 아키텍처를 너무 많이 알게 됨)
 
  개념은 행으로 구분하라 - 함수에서 개념구분은 빈행으로 구분하라
  소스는 신문기사처럼 작성하라 - 전체 내용부터 아래로 갈수록 세세한 내용을 작성(고차원->저차원)
  오류코드 보다는 예외를 리턴하라 - 상수 등으로 정의한 오류코드보다 예외를 리턴
  Null을 리턴, 변수로 전달하지 마라
  

5. 자바

  J1 긴 import 목록을 피하고 *를 사용하라 - 요즘 IDE는 자동숨김 등 기능 잘 지원해 줌
  J2 상수는 상속하지 않는다 - 상수를 인터페이스 등에 넣고 상속해서 사용하지 않는다.
  J3 상수 대신 Enum - enum을 적극 활용하라. static final int라는 옛날 기교를 버려라
  

6. 이름

  N1 서술적인 이름을 사용하라 - 신중하고 명확한 이름은 추가설명 주석보다 강력하다.
  N2 적절한 추상화 수준에서 이름을 선택하라 - 구현을 드러내는 이름은 피하라(ex. Modem클래스 connectPhoneNum()는 전화번호 구현을 드러냄, connect()로 변경하는 것이 좋음)
  N3 표준 명명법을 사용하라 - 프로젝트에서 유요한 의미가 담긴 이름을 많이 사용하면 이해가 쉬워짐(DSL)
  N4 명확한 이름 - 변수,함수 명은 길어도 좋다, 명확하게 의미를 표현하라.
  N5 긴 범위는 긴 이름을 사용하라 - 사용되는 범위가 긴 변수는 서술적인 긴 이름을 사용하라
  N6 인코딩을 피하라 - m_, f_ 등의 접두하는 제거하라
  N7 이름으로 부수효과를 설명하라 - 함수,변수,클래스가 하는 일 모두를 설명하는 이름을 사용하라(단순 get() -> createOrGet() 등)
  

7. 테스트

  T1 불충분한 테스트 - 테스트케이스가 확인하지 않는 조건, 계산이 있다면 불완전한 테스트.
  T2 커버리지 도구를 사용하라 - 테스트 커버리지 도구를 사용하라
  T3 사소한 테스트를 건너뛰지 마라 
  T4 무시한 테스트는 모호함을 뜻한다 - 요구사항 등이 명확하지 않으면 테스트케이스를 주석,@Ignore로 무시하게 된다.
  T5 경계조건을 테스트하라
  T6 버그 주변은 철저히 테스트하라 - 버그는 서로 모이는 경향이 있다
  T7 실패 패턴을 살펴라 - 합리적인 순서로 꼼꼼한 테스트케이스는 실패 패턴을 드러내고 쉽게 확인가능하다.
  T8 테스트 커버리지 패턴을 살펴라 - 통과하는 테스트가 실행or실행하지 않는 코드를 살피면 테스트 실패원인이 드러난다.
  T9 테스트는 빨라야 한다 - 테스트케이스는 최대한 빨리 돌아가게 한다.
  테스트 당 개념 하나만 테스트 하라
 

 

반응형

댓글