클린코드
book, review · 2017-12-1
← 리스트로1. 깨끗한코드
A. 초반 일정의 압박은 -> 나쁜코드를 양산.
B. 나쁜코드는 생상성을 저하시킨다.
C. 코드를 리팩토링 할 나중은 오지 않는다.
D. 관리자는 일정을 압박하지만 좋은 코드를 사수하는일은 프로그래머의 책임
- 급하니 수술전에 손을 씻지 말라는 환자의 요구는 당연히 거부되어야 한다.
- 관리자의 말을 무조건 따르는 행위는 전문가답지 못하다.
E. 깨끗한 코드를 만드려면 청결 이라는 감각이 필요하다.
F. 좋은 코드란?
- 논리가 간단해야한다.
- 의존성을 줄여야 유지보수가 쉽다.
- 한가지 일만 잘하는 함수
- 세세한 사항까지 꼼꼼히 처리
- 가독성 (깨끗한 코드는 단순하고 직접적인 표현을 한다.)
- 다른 사람이 고치기쉬어야한다.
- 테스트케이스가 있어야 한다.
- 코드는 작을수록 좋다.
- 문학적이어야 한다 (신문 읽듯이 읽기가 쉬어야 한다.)
- 중복이 없다.
- 주의를 기울인 코드.
G. 코드의 작성과정은 기존코드를 읽는 과정이 크다.
H. 프리퀄의 원칙
- SRP (단일 책임의 원칙)
- OCP (확장에 열려있고 변경에 닫혀있는 구조)
- DIP (의존관계 역전)
2. 의미있는 이름
A. 의도를 분명히 밝혀라
B. 그릇된 정보를 피하라.
C. 의미있게 구분하라.
D. 발음하기 쉬운이름을 사용하라.
E. 인코딩정보가 포함된 이름을 피하라.
- 어쩔수 없이 인코딩네이밍이 필요한 경우도 있다.
F. 기억력을 자랑하지마라.
- 똑똑한 프로그래머와 전문가 프로그래머는 틀리다.
G. 클래스 이름은 명사. 메서드 이름은 동사로 사용하라.
H. 기발한 이름은 사용하지 말라.
I. 전체 코드에서 한 개념에는 한 단어만 일관성 있게 사용하라.
J. 말장난을 하지 말아라.
K. 해법영역 (전산용어, 알고리즘용어)을 사용하라.
L. 문제영역에 관련된 코드라면 문제영역의 이름을 사용하라.
M. 의미있는 맥락을 유지해라.
- 연관된 큰 맥락은 클래스로 나눠라.
- 연관된 변수에는 접두어를 사용하는것도 도움이 된다.
N. 불필요한 맥락을 없애라.
- M과 같은 의미에서 큰 맥락은 클래스를 나눠라.
3. 함수
A. 작게 만들어라.
- 들여쓰기가 2단을 넘으면 안된다.
- 한가지일만 잘하는 함수를 만들어라.
- 한가지로 정의할수 있어야한다.
- 의미있는 이름으로 다른 함수로 추출 불가능 해야한다.
- 함수 단계마다 추상화 수준을 일정하게 유지하라.
B. switch 문은 작게 만들기 어렵다.
C. 서술적인 이름을 사용하라.
- 차라리 긴 이름이 짧고 이해가 어려운 이름보다 100배 좋다.
D. 인수는 없을수록 좋다.
- 2항을 초과하는 인수는 피하자. (인수가 많으면 코드 이해가 어렵다.)
- 1항 - 질문이나 요청 (boolean은 안됨 ㅋ)
- 좌표값과 같은 어쩔수 없는 2항 인수를 제외하고는 최대한 피함.
- 3항 인수는 이해하기가 너무 어렵다. 가변인수같은 경우를 제외하고는.
- 객체를 사용해 인수를 줄여라 - 자연스럽게 자료구조가 정리됨.
E. 부수효과를 일으키지 마라.
F. 명령과 조회를 분리하라.
- 함수의 목적을 구분해서 명확하게 사용하라 - 처리하거나 조회하거나.
G. 오류코드 대신 예외를 사용하라.
H. 예외도 한가지 작업임으로 다른 함수로 분리.
I. 반복하지 마라.
J. 구조적 프로그래밍과 작은 함수.
- 함수가 작다면 함수내에 return문이 2개여도 괜찮다.
K. 처음에는 서툴게 짜고 리펙토링하라.
4. 주석
A. 주석은 최대한으로 줄여야한다.
B. 주석 대신에 코드를 의도로 표현하자.
C. 좋은주석
- 법적인 주석
- 정보를 제공
- 결과를 경고하는 주석
- 의도를 설명하는 주석
D. 나쁜주석
- 주절거리는 주석
- 같은 이야기를 중복하는 주석
- 오해의 여지를 주는 주석
- 의무적인 주석
- 너무 많은 정보
- html이 포함된 주석
- 주석으로 처리한 코드
- 저자정보 주석
- 이력을 기록한 주석
- 있으나 마나한 주석
- 닫는 괄호 표시 주석
5. 형식맞추기
- 코드란 의사소통임으로 코드규칙을 정하고 착실히 따라야 한다.
- 일단 돌아가기만 하는 코드는 다음 버전을 만들때 생산성을 떨어뜨린다.
A. 적절한 행 길이를 유지하라.
B. 신문기사처럼 작성하라.
C. 개념은 빈 행으로 분리하라.
D. 세로 밀집도가 커야 읽기가 편하다.
E. 수직거리
F. 변수선언
- 사용하는 위치에 최대한 가까이 선언
- 인스턴스 변수는 한 부분에 모은다.
G. 종속함수는 세로 가까이에 붙여서 선언
H. 개념적 유사성이 있는 것들은 새로로 붙여서 선언
I. 가로 형식 맞추기
- 길이가 짧을 수록 좋고 최대 120자 정도가 좋음
- 할당 연산자는 앞뒤로 공백
- 인수 쉼표 다음은 한칸 공백
- 변수들의 가로정렬은 피하는게 좋음 (선언부가 길다면 클래스를 쪼개는게 좋음)
J. 들여쓰기 무시하기
- 들여쓰기가 귀찮아서 한 행에 몰아 넣지 말것.
K. 팀규칙
- 한 소스에서 봤던 형식이 다른 소스에서도 그러해야 한다.
- 코드 자체가 최고의 문서다.
6. 객체와 자료구조 (객체가 항상 만능은 아니다.)
A. 자료 추상화
- 아무 생각없이 조회/설정(getter, setter) 를 만드는 것 보다 자료를 표현하는 가장 좋은 수단을 찾아야 한다.
- 객체의 구현은 최대한 숨기는 편이 좋다.
B. 자료 / 객체 비대칭
- 객체지향이 만능은 아니며 절차지향이 더 좋을때도 있다.
C. 디미터 법칙
- 객체를 인자로 받거나, 생성하거나, 소속한 클래스에 인스턴스로 가지고 있는 객체만 조작해야 한다.
- 객체는 자료 구조를 숨기고 최소한의 함수를 공개해야 한다.
- 탐색 메소드(getter)를 만드는것보다 임무를 가진 메서드를 만들자.
D. 자료전달객체
- 자료전달객체(구조체 객체)는 자료구조임으로 비지니스 로직을 담으려면 따로 객체를 생성하는게 좋다.
7. 오류처리
- 오류처리 코드로 인해 프로그램의 논리를 이해하기 어려워서는 안된다.
A. 오류코드 보다는 예외를 사용하라.
B. 오류코드의 여지가 생기면 try / catch / finally 문 부터 작성하라.
C. 미확인 예외를 사용하라.
- 확인 예외는 예외처리를 안하면 컴파일 에러가 난다.
D. 예외에 의미를 제공하라
- 오류 메세지에 충분한 정보가 담겨 있어야 한다.
E. 호출자를 고려해 예외 클래스를 정의하라.
- 오류를 잡아내는 방법을 고려해야 한다.
- 외부 API를 사용할때는 감싸기 기법을 사용하라.
F. 정상흐름을 제어하라 (try / catch의 남용은 안된다.)
G. null을 반환하거나 전달하지 말라.
- null을 반환하는 코드는 일거리를 만들어 코드가 지저분해진다.
- null 대신 특수사례 객체를 사용하라 (empty.list 와 같은)
8. 경계
A. 외부코드 사용하기
- map과 같은 경계인터페이스는 공개 api의 인수로 넘기거나 반환값으로 사용하지 않는다.
B. 경계 살피고 익히기
- 외부 코드를 사용하려면 외부코드의 사용법에 대해 잘 알아야 함으로
간단한 학습 테스트케이스를 만드는 것이 좋다.
C. 학습 테스트는 공짜가 아니다.
- 외부 라이브러리 업데이트시 버전업 하기가 쉬어진다.
D. 아직 존재하지 않는 코드 사용하기
- 우리가 원하는 형태로 기능을 정의하여 사용
- 추후 코드가 존재하게 되면 Adapter패턴으로 초기 정의와 실제 코드와의 간극을 줄인다.
E. 깨끗한 경계
- 외부코드를 사용하는 포인트를 최대한 줄여서 경계를 관리한다.
9. 단위테스트
A. TDD의 세가지 법칙
- 실패케이스의 단위테스트를 작성하기 전까지는 실제 코드를 작성하지 않는다.
- 컴파일을 실패하지 않을 정도로만 실패를 작성
- 현재 실패할 테스트를 통과하는 정도로만 실제코드를 작성
B. 깨끗한 코드 유지하기
- 테스트 코드는 실제 코드만큼이나 깨끗하게 짜야한다.
C. 테스트당 Assert는 하나가 좋다.
D. F.I.R.S.T 테스트 코드의 5가지 법칙
- 빠르게
- 독립적으로 (의존없이)
- 반복 가능하게 (어떠한 환경에서도)
- 자가 검증 가능하게 (결과를 true / false 로만 리턴)
- 적시에 (실제코드보다 먼저 작성)
10. 클래스
A. 클래스 체계
- 정적공개, 정적비공개, 비공개, 공개함수, 비공개함수 순서로 작성한다.
- 비공개를 풀어주는 것은 최후의 수단이다.
B. 단일책임 클래스 (클래스는 작아야 한다)
- 클래스의 이름은 클래스의 책임을 기술.
- if 나 and, but의 의미가 있으면 안된다.
- 클래스의 책임이 하나이면 관리가 쉬워진다.
- 거대한 다목적 클래스는 어떠한 문제를 해결할때 자잘한 부분까지 파악해야 한다.
- 인스턴스 변수가 많아지면 새로운 클래스로 쪼개는게 좋다.
- 높은 응집력이 유지된다 (구조가 명확해짐)
C. 변경하기 쉬운 클래스
- 응집력이 강한 클래스
- 확장에 열려있고 수정에 패쇄적이어야한다 (OCP)
- 다형성을 이용하여 결합도를 낮추면 변경하기 쉽다.
11. 시스템
A. 깨끗한 코드를 유지하면 낮은 추상화 수준에서 관심사 분리가 가능
B. 시스템 제작과 시스템 사용을 분리하라. (의존성 주입)
- 시스템 생성과 관련된 코드는 메인 함수로 옮긴다.
- 시스템 생성을 책임질 메커니즘으로 main이나 또다른 컨테이너를 사용한다.
C. 확장
- 생성과 사용을 분리하면 시스템의 확장이 쉬워진다.
12. 창발성
A. 창발성 설계로 깔끔한 코드를 구현하자.
- 모든 테스트 코드를 만들어 실행한다.
- 중복을 없앤다.
- 프로그래머의 의도를 표현하라.
- 클래스나 메서드의 수를 최소화 하라.
B. 테스트 코드가 있음으로 마음것 리팩토링이 가능하다.
C. 중복코드를 뽑아내는 패턴을 이용한다. (Template Method패턴)
D. 좋은이름, 클래스와 함수의 크기, 테스트 코드
E. 가장 중요한것은 청결함을 유지하기 위한 프로그래머의 노력
13. 동시성
A. 동시성이란
- 객체 -> 처리의 추상화
- 스레드 -> 일정의 추상화
B. 동시성의 특징
- 동시성은 때때로 성능향상을 불러온다.
- 대기시간이 크거나 독립적으로 처리하는 계산이 많을 경우
- 동시성을 사용하면 설계가 바뀐다.
- 동시성은 다소 부하를 유발한다.
- 동시성은 복잡하다.
- 동시성 버그는 재현이 힘들다.
- 동시성을 사용하려면 메모리 모델을 이해해야 한다.
C. 동시성 방어원칙
- SRP (단일 책임)
- 동시성 코드는 다른 코드와 분리
- 자료의 범위를 제한
- 공유데이터를 캡슐화 원자화 하고 제한한다.
- 자료사본을 이용한다.
- 스레드는 되도록이면 독립적으로 구현하라.
- 다른 스레드와 동기화를 피하라.
14. 점진적인 개선
- 먼저 지저분하게 짠뒤 정리하는 방법이 좋다.
- 일단 돌아가는 프로그램을 그대로 놓아두는것은 자살행위다.
A. 점진적으로 개선하라.
- 리펙토링의 전과 후과 똑같이 동작하려면 테스트 코드가 필요하다.
17. 냄새와 휴리스틱
- 많은 코딩경험은 나쁜코드의 냄새를 맡는 기준의 잣대가 생기게 한다.