Clean Code

(로버트 마틴 저자의 클린코드에서 거의 제목만 뽑아 놓은 것임. 자세한 내용은 책을 보자)

2장 의미 있는 이름

의도를 분명히 밝혀라

함수/변수 명을 작명할때 길어도 좋으니 분명히 의미 있는 이름으로 지어라.
단순한 숫자를 직접 사용하기 보다 enum 등으로 정의하여 사용해라

그릇된 정보를 피하라

list type도 아닌데 accountList 형태로 짓지 말자.
차라리 accountGroup 이라고 하자.
헷깔리는 이름으로 이름 짓지말자.

의미 있게 구분하라

ex) int a1, a2, a3 이런식은 피하자.

getActiveAccount()
getActiveAccountInfo()

발음하기 쉬운 이름을 사용하

    • [X] Date genymdhms;
    • [O] Date generationTimeStamp;

인코딩을 피하라

헝가리식 표기법

인터페이스 클래스와 구현 클래스

    • [X] IShapeFactory / CShapeFactory
    • [O] ShapeFactory / ShapeFactoryImpl

자신의 기억력을 자랑하지 마라

i,j,k까지는 괜찮다.

클래스 이름

    명사구

메서드 이름

    동사구
    get, set, is

기발한 이름은 피하라


한 개념에 한 단어를 사용해라

    fetch, retrieve, get 제각각 사용하지 마라
    DeviceManager와 DeviceController 뭐가 다른가? 일관성 있는 이름으로.

말장난을 하지마라

    a+b 의미로 add 함수를 작성했다면, item 추가하는 함수로 add 이름을 사용하지 마라.
    => append, insert로 사용한다.

해법 영역에서 가져온 이름을 사용하라

    전산용어, 알고리즘 이름, 패턴이름, 수학용어 등을 사용해도 좋다.
    VISTOR패턴에 친숙하면 AccountVisitor 이름을 금방 이해할 수 있다.

문제 영역에서 가져온 이름을 사용하라

    마땅한 해법영역의 이름이 없다면 문제 영역에서 가져온 이름을 사용해라.

의미 있는 맥락을 추가하라


불필요한 맥락을 없애라

    GSDAccountAddress

3장 함수

작게 만들어라

    첫번째 규칙 작게 만들어라
    두번째 규칙: 더 작게 만들어라

한 가지만 해라

함수 당 추상화 수준은 하나로

위에서 아래로 코드 읽기: 내려가기 규칙

Switch문

switch문을 완전히 피할 방법은 없지만 저차원 클래스에 숨기고 절대로 비슷한 switch문이 반복되지 않도록 한다.

서술적인 이름을 사용하라

함수 인수

무항이 가장 좋고 그 다음에 단항, 그 다음에는 이항까지는 괜찮다.

단항함수

이항함수

삼항함수

인수객체

    인수가 2~3개 필요하다면 일부를 독자적인 클래스 변수로 선언할 가능성을 짚어본다.
동사와 키워드
    단항 함수 이름은  동사/명 쌍을 이뤄야 한다.
    writeField(name)

부수효과를 일으키지 마라

    • 클래스 변수 수정
    • 함수로 넘어온 인수나 시스템 전역 변수를 수정
=> 시간적인 결합(temporal coupling)이나 순서 종속성(order dependency)을 초래한다.

출력인수

일반적으로 인수는 함수 입력으로 해석한다.

명령과 조회를 분리하라

if (set("username", "freehuni") ...
=>
if(attributeExists("username"))
{
    setAttribute("username", "freehuni");
}

오류코드보다 예외를 사용하라

try/catch 블록은 지저분하기에 코드 구조에 혼란을 일으킨다.
허니생각: 저수준 함수에서는 throw, 고수준 함수에서 try/catch로 잡는다.

4장 주석

주석은 나쁜 코드를 보완하지 못한다

코드로 의도를 표현하라

좋은 주석

    • 법적인 주석
    • 정보를 제공하는 줏헉
    • 의도를 설명하는 주석
    • 의도를 명료하게 설명하는 주석
    • 결과를 경고하는 주석
    • todo 주석
    • 중요성을 강조하는 주석
    • 공개API의 doxygen 주석

나쁜주석

    • 주절거리는 주석
    • 같은 이야기를 중복하는 주석
    • 오해할 여자기 있는 주석
    • 의무적으로 다는 주석
    • 이력을 기록하는 주석
    • 있으나 마나 한 주석
    • 무서운 잡음
      • 무조건적인 doxygen 주석을 다는 것은 잡음이다.
      • 필요없는 주석은 없는 것이 낫다.
    • 위치를 표현하는 주석
      • // Actions //////////////////
    • 닫는 괄호에 다는 주석
      • } // while(isRunning)
    • 공로를 돌리거나 자저를  표시하는 주석
    • 주석으로 처리한 코드
    • HTML주석
    • 전역정보
      • 주석을 달아야한다면 근처에 있는 코드만 기술하라
    • 너무 많은 정보
      • RFC번호만으로도 충분하다.
    • 모호한 관계
    • 함수 헤더
    • 비공개 코드에서 doxygen
      • 공개API는 doxygen이 유용하지만 비공개 코드는 불필요하다.
    • 예제

5장 형식 맞추기

형식을 맞추는 목적

    융통성 없이 맹목적으로 따르면 안된다.
    코드 형식은 의사소통의 일환이다.
    오랜 시간이 지나면 원래 코드의 흔적을 더 이상 찾아보기 어렵지만 맨 처음 잡아놓은 형식을 따르면 유지보수 용이성과 확장성에 계속 영향을 미친다.

적절한 행 길이를 유지하라

신문 기사처럼 작성하라

개념은 빈 행으로 분리하라

세로 밀집도

수직 거리

    • 변수선언
      • 변수는 사용하는 위치에 최대한 가까이 선언한다.
    • 인스턴스 변수
      • 인스턴스 변수는 클래스 맨 처음에 선언한다.
      • 변수간에 세로로 거리를 두지 않는다.
      • C++ 에서 클래스 마지막 선언을 많이 한다
      • Java에서는 클래스 클래스 맨 처음에 선언한다.
    • 종속함수
      • 한 함수가 다른 함수를 호출한다면 두 함수는 세로로 가까이 배친한다.
      • 가능하면 호출하는 함수를 호출되는 함수보다 먼저 배치한다.
    • 개념유사성
      • 친화도가 높은 코드를 가까이 배치한다.

세로순서

    일반적으로 함수 호출 종속성은 아래 방향으로 유지한다.

가로형식 맞추기

    가로 공백과 밀집도

    가로정렬 

   들여쓰기

팀 규칙 


6장 객체와 자료구조

자료추상화

자료/객체 비대칭

객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다.
자료구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.

디미터 법칙

모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙.

객체는 자료를 숨기고 함수를 공개한다. 

기차충돌

 String out=ctx.getOptions().getScratchDir().getAbsolutePath();

위와 같은 코드는 여러 줄로 풀어쓰자. 

잡종구조

구조체감추기

자료전달객체

결론

객체는 동작을 공개하고 자료를 숨긴다
    => 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기는 쉬운 반면,
    => 기존 객체에 새 동작을 추가하기는 어렵다.

7장 오류처리

오류코드보다 예외를 사용하라

try/catch 문부터 작성하라

미확인(unchecked)예외를 사용하라

예외에 의미를 제공하라

호출자를 고려해 예외 클래스를 정의하라

정상 흐름을 정의하라

null을 반환하지 마라

null 반환대신에 예외를 던지거나  특수 객체를 반환해라.
외부 API가 null를 반환하는 경우 감싸기 메서드를 구현하여 예외를 던져라.

null을 전달하지마라

차라리 assert 처리하는 것이 좋다.

 

8장 경계

외부코드 사용하기

Wrapper 작성 

경계 살피고 익히기

대게 타사 라이브러리 문서를 리뷰하고 우리쪽 코드를 작성하여 라이브러리가 예상대로 동작하는지 확인한다. 때로는 우리 버그인지 라이브러리 버그인지 찾아내느라 고생한다.

차라리, 테스트코드를 작성하여 라이브러리 사용법을 익히자.

log4j 익히기 

학습 테스트는 공짜 이상이다 

아직 존재하지 않는 코드를 사용하기

경계 인터페이스가 뭔지 안다면 타사 라이브러리의 API가 작성되지 않았더라도 경계 인터페이스를 통하여 필요한 로직을 구현할 수 있다. 

깨끗한 경계


9장 단위테스트

TDD법칙 세가지

    • 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않느다.
    • 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
    • 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.
실제 코드와 맞먹을 정도로 방대한 테스트 코드는 심각한 관리 문제를 유발하기도 한다.

깨끗한 테스트 코드 유지하기

실제 코드가 변경되면 테스트 코드도 변경해야한다. 그런데 테스트 코드가 지저분할 수록 변경하기 어렵다.
깨끗한 테스트 코드를 작성하려면 3가지가 필요하다. 첫번째 가독성, 두번째도 가독성, 세번째도 가독성이다.
최소의 표현으로 많은 것을 나타내야 한다.

테스트당 assert 하나

F.I.R.S.T

빠르게(Fast)

테스트는 빨리 돌아야 한다. 

독립적으로(Inpendent)

각 테스트는 서로 의존하면 안된다. 

반복가능하게(Repeatable)

 어떤 환경에서도 반복 가능해야 한다.

자가 검증하는(Self-Validating)

 테스트는 bool값으로 결과를 내야 한다. 로그 내용으로 판단하게 하지 마라.

적시에(Timely)

 실제 코드를 구현한 다음에 테스트 코드를 만들면 실제 코드가 테스트하기 어렵다는 사실을 발견할 지 모른다. 반드시 실제 코드가 작성되기 전에 테스트코드가 작성되어야 한다.



10장 클래스


11장 시스템


12장 창발성

  • 모든 테스트를 실행한다.
  • 중복을 없앤다.
  • 프로그래머 의도를 표현한다.
  • 클래스와 메서드 수를 최소로 줄인다. 

13장 동시성

동시성이 필요한 이유?

동시성은 coupling을 없애는 전략이다. 무엇what과 언제when을 분리하는 전략이다.

난관

동시성 방어 원칙

  • 자료범위를 제한하라

    •  critical section

  • 자료 사본을 사용하라
    •  공유 자료9를 줄이려면 처음부터 공유하지 않는 방법이 제일 좋다.

  • 스레드는 가능한 독립적으로 구현하라
    • 다른 스레드와 자료를 공유하지 않는다.
    • 모든 정보는 비공유 출처에서 가져오며 로컬 변수에 저장한다.  

라이브러리를 이해하라

실행모델을 이해해라

  • 한정된 자원(Bound Resource)

  •  상호배제(Mutal Exclusion)
  • 기아(Starvation)
  • 데드락(DeadLock)
  • 라이브락(LiveLock)

Producer-Consumer

Reader-Writer

Dining Philosphers

동기화하는 메서드 사이에 존재하는 의존성을 이해하라

공유 클래스 하나에 동기화된 메서드가 여럿이라면 구현이 올바른지 다시 한번 확인한다. 

동기화하는 부분을 작게 만들어라

올바른 종료 코드는 구현하기 어렵다

스레드 코드 테스트하기 


 

14장 점진적인 개선

15장 JUnit 들여다보기

16장 SerialDate 리팩토링

17장 냄새와 휴리스틱

주석

    • 부적절한 정보
    • 쓸모없는 주석
    • 중복된 주석
    • 성의없는 주석
    • 주석 처리된 코드

환경

    • 여러단계로 빌드
    • 여러단계로 테스트

함수

    • 너무 많은 인수
    • 출력 인수
    • 플래그 인수
    • 죽은 함수

일반

    • 한 소스파일에 여러 언어 사용
    • 당연한 동작을 구현하지 않음
    • 경계를 올바로 처리하지 않음
    • 안전 절차 무시
    • 중복
    • 추상화 수준이 올바르지 못함
    • 기초 클래스가 파생 클래스에 의존
    • 과도한 정보
    • 죽은 코드
    • 수직 분리
    • 일관성 부족
    • 잡동사니
    • 인위적 결합
    • 기능욕심
    • 선택자 인수
    • 모호한 의도
    • 잘못 지운 책임
    • 부적절한 static함수
    • 서술적 변수
    • 이름과 기능이 일치하는 함수
    • 알고리즘을 이해하라
    • 논리적 의존성은 물리적으로 드러내라
    • 표준 표기법을 따르라
    • 매직 숫자는 명명된 상수로 교체
    • 정확하라
    • 관례보다 구조를 사용하라
    • 조건을 캡슐화하라
    • 부정 조건을 피하라
    • 함수는 한 가지만 해야한다.
    • 숨겨진 시간적인 결합
    • 일관성을 유지하라
    • 경계 조건을 캡슐화하라
    • 함수는 추상화 수준을 한 단계만 내려가야 한다
    • 설정 정보는 최상위 단계에 둬라
    • 추이적 탐색을 피하라

자바

    • 긴 import 목록을 피하고 와이들카드를 사용하라
      • import package.*;
    • 상수는 상속하지 않는다
    • 상수 vs enum
      • enum을 사용하라

이름

    • 서술적인 이름을 사용하라
    • 적절한 추상화 ㅅ후준에서 이름을 선택하라
    • 가능하면 표준 명명법을 사용하라
    • 명확한 이름
    • 긴 범위는 긴 이름을 사용하라
    • 인코딩을 피하라
      • m_ 이나 f와 같은 접두어는 불필요하다.
      • 헝가리안 표기법 X

테스트

    • 불충분한 테스트
    • 커버리지 도구를 이용하라
    • 사소한 테스트를 건너뛰지 마라
    • 무시한 테스트는 모호함을 뜻한다
    • 경계 조건을 테스트하라
    • 버그 주변은 철저히 테스트하라
    • 실패 패턴을 살펴라
    • 테스트 커버리지 패턴을 살펴라
    • 테스트는 빨라야 한다.

댓글