- ☆ 표시가 붙은 부분은 스터디 중 나온 얘기 혹은 제 개인적인 생각이나 제가 이해한 방식을 적어놓은 것으로, 책에서 말하고자 하는 바와 다를 수 있습니다.
- 모든 이미지의 출처는 클린 코드(로버트 C. 마틴 저) 책 입니다.
5장 형식 맞추기
⚈ 술 취한 뱃사람 한 무리가 짜놓은 듯 어수선해 보인다면 독자들은 프로젝트의 다른 측면도 똑같이 무성의한 태도로 처리했으리라 생각할 것이다. -> ☆ 완전 공감되는 내용이었다. 예전에 뭔 외주줘서 진행한 프로젝트를 짬처리 받은적이 있다. 그런데 저런식이다. 코드 형식을 논하기 이전에 뭔 띄어쓰기도 제대로 안되어있고, 최대한 완벽해야 할 공통코드에서 꽤 많이 사용된 isEmpty가 == "null" 이러고 있다. 돌아가는게 신기하다 ㅋㅋ. 진짜 저런식으로 짠거면 스스로 부끄럽지 않다는건데 기가 차다. 내 경우엔 해당 프로젝트의 나머지 부분은 그냥 보지도 않고 소스 받은 후 3분정도만에 삭제하고 그냥 새로 진행하겠다고 했다. 나머지 부분도 뻔하니까!
⚈ 코드 형식은 의사소통의 일환이다. 코드 형식은 전문 개발자의 일차적인 의무다.
⚈ 원래 코드는 사라질지라도 개발자의 스타일과 규율은 사라지지 않는다. -> ☆ 엄청 깔끔하게 짜여져 있는 코드를 수정하면서 굳이 엉망으로 짜는 또라이는 잘 없다.
⚈ 적절한 행 길이를 유지하라
- 일반적으로 큰 파일보다 작은 파일이 이해하기 쉽다. 대부분 200줄 정도인 파일로도 커다란 시스템을 구축할 수 있다.
⚈ 신문 기사처럼 작성하라
- 독자는 위에서 아래로 기사를 읽는다.
- 신문기사처럼 소스 파일 첫 부분은 고차원 개념과 알고리즘을 설명하고 아래로 내려갈수록 의도를 세세하게 묘사한다. 마지막에는 가장 저차원 함수와 세부 내역이 나온다.
- ☆ 나도 그렇고 주로 C로 먼저 언어를 접한 사람들이 클린코드 책에 나온 것과 반대로 아래쪽에 중요한 개념이 나온다. C의 경우 아래쪽에 있는 함수는 사용할 수 없다. 위에 선언을 따로 적어야 하는데 보통 귀찮다보니 아래쪽에서 위로 올라가면서 코드를 짜게 된다.
⚈ 개념은 빈 행으로 분리하라
⚈ 세로 밀집도는 연관성을 의미한다.
- 서로 밀접한 코드 행은 세로로 가까이 놓여야 한다.
- ☆ 그렇다고 전역 변수 - 함수 - 전역 변수 - 함수 이런식으로 밀접하다고 해당 전역 변수를 주로 사용하는 함수랑 붙여두진 말자 ㅋㅋ
⚈ 연관성이 깊은 두 개념이 멀리 떨어져 있으면 코드를 읽는 사람이 소스 파일과 클래스를 여기저기 뒤지게 된다.
⚈ 변수는 사용하는 위치에 최대한 가까이 선언한다.
⚈ 인스턴스 변수 (전역 변수)는 클래스 맨 처음에 선언한다.
- C++에서는 모든 인스턴스 변수를 클래스 마지막에 선언한다는 소위 가위 규칙을 적용한다. -> ☆ 본적 없긴하다. 일단 내가 본 다른 사람의 C++ 코드도 전부 위에 뒀긴하다.
- 위나 아래가 중요한게 아니라, 잘 알려진 위치에 인스턴스 변수를 모은다는 사실이 중요하다.
⚈ 호출하는 함수를 호출되는 함수보다 먼저 배치한다.
⚈ 상수를 알아야 마땅한 함수에서 실제로 사용하는 함수로 상수를 넘겨주는 방법이 더 좋다.
- ☆ 객체간의 관계에서도 동일하다. 의존성 주입(DI)에 해당한다. defaultPage가 뭔지 알기 위해 코드를 뒤져봐야 하는 것 자체가 캡슐화가 무너진 것이다.
⚈ 개념적 유사성이 높을수록 코드를 가까이 배치한다.
- e.g. assertTrue(), assertFalse() 이런 것들은 비슷한 위치에 코드를 둔다.
⚈ 함수 호출 종속성은 아래 방향으로 유지한다.
⚈ 120자 정도로 행 길이를 제한한다.
- ☆ 인텔리제이의 경우 코드 쓰는 부분에 세로줄이 그어져 있는데 그게 이 용도이다. 대략 110자 정도가 기본으로 세팅되어 있다. 넘었다고 오류가 나는건 아니지만 주의하라는 의미이다.
⚈ 연산자 우선순위를 강조하기 위해서도 공백을 사용한다.
- ☆ 이건 엄청 좋은 팁인 것 같다. 백준 9206을 풀었던 코드에 수식이 많았어서 한번 시도해봤다. 결론적으로 저 아래쪽의 ans+= 부분처럼 너무 복잡한 경우엔 크게 의미가 없었지만, 중간에 f() 함수의 경우엔 확실히 보기 편해진다.
class Vase {
private double a, b, h, interval;
private int numOfInterval;
public Vase(StringTokenizer st) {
this.a = Double.parseDouble(st.nextToken());
this.b = Double.parseDouble(st.nextToken());
this.h = Double.parseDouble(st.nextToken());
this.numOfInterval = (int) Math.ceil(h/Tags.X_DIVIDE_GAP);
this.interval = h/numOfInterval;
}
private double f(double x) {
return a*Math.exp(-(x*x))+b*Math.sqrt(x);
return a*Math.exp(-x*x) + b*Math.sqrt(x);
}
private double g(double x) {
double fx = f(x);
return fx*fx*Math.PI;
}
public double getVolume() {
double ans = 0.0d;
for (int i = 0; i < numOfInterval; i++) {
double a = interval*i;
double b = interval*(i+1);
ans += interval/6*(g(a)+4*g((a+b)/2)+g(b));
ans += interval/6*(g(a) + 4*g((a+b)/2) + g(b));
}
return ans;
}
}
⚈ 가로 정렬은 별로 유용하지 못하다.
⚈ 프로그래머는 들여쓰기 체계에 크게 의존한다. 들여쓰기가 없다면 인간이 코드를 읽기란 거의 불가능하다.
- 들여쓰기한 파일은 구조가 한눈에 들어온다.
⚈ 가짜 범위
- 빈 while문이나 for문의 경우 아래와 같이 새 행에다가 세미콜론을 넣어준다.
while (dis.read(buf, 0, readBufferSize) != -1)
;
- ☆ 개인적으로는 아래와 같은 방식을 더 선호한다. 내 경우엔 책의 방식보단 아직은 내 방식이 더 눈에 잘 띄고 명확하다고 생각되서 바꾸진 않을 것 같다.
while (dis.read(buf, 0, readBufferSize) != -1) {
// do nothing
}
⚈ 팀 규칙
- 팀은 한 가지 규칙에 합의해야 한다. 그리고 모든 팀원은 그 규칙에 따라야 한다.
'Study > 클린코드' 카테고리의 다른 글
[클린코드] 7장. 오류 처리 (0) | 2023.01.02 |
---|---|
[클린코드] 6장. 객체와 자료 구조 (0) | 2023.01.02 |
[클린코드] 4장. 주석 (0) | 2022.12.21 |
[클린코드] 3장. 함수 (0) | 2022.12.20 |
[클린코드] 2장. 의미 있는 이름 (0) | 2022.12.14 |
댓글