Clean Code 5장 - 8장

2019-04-01

5장과 6장은 지난주 스터디 끝나고 집 들어가는 지하철에서 충분히 읽었는데, 7장과 8장은 자잘자잘하게 걸리는 구석이 많아서 여러번 읽고 찾아봤음에도 명쾌하게 해결이 안되어서 힘들었다.

5장 형식 맞추기

p. 101 수직거리

타당한 근거가 없다면 서로 밀접한 개념은 한 파일에 속해야 마땅하다. 이게 바로 protected 변수를 피해야 하는 이유 중 하나다.는 이해했다.
부적절하게 protected 남발한 예시와 그걸 개선한걸 보고싶은데, 어디서 찾아야 할 지 모르겠다.

p. 105 수직거리

[G35] getPageNameOrDefault 함수 안에서 "FrontPage" 상수를 사용하는 방법도 있다.

이거 첨에 볼 때 이해를 못했는데, 앞에 나온 추상화 수준 관련이다. 함수안에서 상수를 쓰면 읽는 사람 입장에서는 ‘왜 여기서 String이 바로 나오지?’ 싶을 것이다. 인자로 넘기는 것이 깔끔하다.

p. 113 가짜 범위

아래와 예제 코드와 같이 세미콜론은 새 행에다 제대로 들여써서 넣어준다. 실수로 세미콜론을 찍지 않았고, 세미콜론이 찍히지 않은 while문 아래에 if문이 있다고 가정해보자. while 조건 안에서 if가 돌게 되므로 의도와 다르게 동작하게된다. 이건 컴파일러가 제대로 잡아주지 않을것이다.

근데 세미콜론을 그냥 아래 라인에 따로 쓰라는것인지, 들여쓰기까지 해야되는진 모르겠다. 밥 아저씨가 짜놓은거 보면 들여쓰기 하라는거 같은데..

별로 중요한건 아닌것 같고 이것이 중요하다면 팀 규칙을 만들테니 그냥 넘어가기로 했다.

while(dis.rad(buf, 0, readBufferSize) != -1)
    ;

6장 객체와 자료 구조

p. 122

분별 있는 프로그래머는 모든 것이 객체라는 생각이 미신임을 잘 안다. 때로는 단순한 자료 구조와 절차적인 코드가 가장 적합한 상황도 있다.

p. 123 디미터 법칙

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

p. 123 기차 충돌

아래와 같은 코드를 기차 충돌이라고 부른다. 일반적으로 조잡하다 여겨지는 방식이므로 피하는 편이 좋다. 자료구조라면 당연히 내부 구조를 노출 하므로 디미터 법칙이 적용되지 않는다.

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

위가 객체라면 아래와 같이 나누는 편이 좋다.

Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();

반면 자료구조라면 아래와 같이 개선하는 것이 좋다. 이유는 get이 붙은 조회함수 때문에 헷갈리기 때문이다.

final String outputDir = ctxt.options.scratchDir.absolutePath;

이 기차 충돌을 보면서 메서드 체이닝이 생각났다. ‘왜 저렇게 해야되는진 알겠는데 저렇게 쓰는 경우가 많지않나?’라는 생각역시 들었다. JAVA Stream 쓰는 것만 봐도 계속 길게 늘어진다.

'메서드 체이닝'과 '기차 충돌'은 확실하게 다르다. 또한 JAVA Stream의 경우는 길게 이어져도 이 책에 나와있는 예제와 다르게 한 개념으로 볼 수 있다.

p. 127 활성 레코드

내가 아는 활성 레코드는 컴파일러 시간에 들은 그것인데, ‘활성 레코드는 DTO의 특수한 형태다’에서 엥?했다. 아니나 다를까 Active Record라고 검색하니까 원하는 내용들이 나왔다.

Active Record라는 디자인 패턴이 있었다. 이 패턴은 ORM에 자주 쓰인다는 글을 보고 이해가 갔다.

7장 오류 처리

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

‘얼마 전까지만 해도 예외를 지원하지 않는 프로그래밍 언어가 많았다.’를 읽고 무슨 언어가 있는지 생각해보았다. C언어 말곤 생각이 안난다. C에서는 exception 처리를 위한 표준문법이 없는 것으로 알고있다.
아마 쓰는걸 봤다면 그건 c++의 try-catch를 썼다거나 윈도우에서 제공하는 __try-__except 일 것이다. 아마 그것도 아니면 <setjmp.h>로 꼼수를 쓴거거나..

p. 133 미확인 예외를 사용하라

여기서 말하는 미확인은 unchecked이다. Unchecked Exception… 책에 영어로 표기가 되어있었는데, 그게 눈에 안들어와서 한참을 생각했다. ‘음 예외인데 미확인이라고? catch(Exception e) {} 이런거 쓰라는건가?’ 이러면서..

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

‘한 예외는 잡아내고 다른 예외는 무시해도 괜찮은 경우라면 여러 예외 클래스를 사용한다.’ 이 말이 이해가 안갔는데, ‘예외 처리 로직이 다르면 예외처리 클래스를 여러개 사용하는 것이 옳다’로 이해했다.

p. 140 null을 전달하지 마라

‘정상적인 인수로 null을 기대하는 API가 아니라면 메서드로 null을 전달하는 코드는 최대한 피한다.’ 에서 정상인수로 null을 기대하는 API는 어떤 경우가 있는지 의문이 들었다.

‘방어적인 코드를 작성 할 때 그렇게 하지 않을까?’라는 답변을 받고 이해했다.

p. 142 null을 전달하지 마라

‘대다수 프로그래밍 언어는 호출자가 실수로 넘기는 null을 적절히 처리하는 방법이 없다. 그렇다면 애초에 null을 넘기지 못하도록 금지하는 정책이 합리적이다.’

이걸 읽고 실수로 넘어오는 null을 적절히 처리하는 프로그래밍 언어가 뭔지 궁금했다. Kotlin은 기본적으로 null을 허용하지 않기 때문에 null을 써도 비교적 안전하게 쓸 수 있다.

8장 경계

이 장은 쭉 읽으면서 “음.. 그렇지”하고 받아들이기는 했으나, 이걸 제대로 해본 경험이 없어서 구체적인 사례들이 떠오르지 않았다.

p.147 log4j 익히기

학습테스트라는 용어자체를 처음 들어봤으나 이렇게 테스트 짜는 것은 들어봤다. 학습테스트라는 용어는 많이 쓰이는 용어라고 한다.

어찌되었건 API를 익혀야 하므로 이런저런 테스트 코드를 짜 본다. 이것은 그저 외부 코드를 익히기 위해서 짜는 것만은 아니며 그 이상의 가치가 있다.

이 책에 있는 log4j와 같이 프로젝트에 쓰고있는 외부 코드들이 버전업이 될 것이다. 그 때 과거에 짜 놓은 학습테스트를 돌려본다. Deprecated 되거나 변경이 되었거나 등의 이유로 깨지는 부분들이 있을 것이다. 이 학습테스트 짜놓은 것 덕분에 변경점을 쉽게 파악하고 고칠 수 있다.

그래서 p.149에 학습 테스트는 공짜 이상이다라고 하는 것이다.

현실적으로는 제대로 하기 어렵다고 들었다.

p.151 깨끗한 경계

  • 경계에 위치한 코드는 깔끔히 분리한다.
  • 외부 패키지를 직접적으로 호출하는 코드는 가능한 줄이자.