namkyujin.com

2016-05-06
#book

읽기 좋은 코드가 좋은 코드다 (원제 The Art of Readable Code), 더스틴보즈웰, 트레버파우커 저

추천하고 싶은 책이다. 예전부터 잘 작동하는 깔끔한 코드 (Clean code that works) 에 관심이 많았기 때문에 관련 된 책을 몇 권 읽기도 했었고, 프로그래밍과 관련된 대부분의 책에서는 좋은 코드에 대해 꼭 언급한다. 코드 작성에 대해 가장 자세한 조언을 해준 책은 Code Complete2, 스티브맥코넬 저 (현재 절판) 이긴 하지만 책이 너무 두껍고 잘 읽히지도 않는다. 그에 반해 이 책은 좋은 코드에 관한 거의 모든 내용을 쉽게 담았다. 게다가 얇다!

쉬운 코드

코드는 다른 사람이 그것을 이해하는 데 들이는 시간을 최소화 하는 방식으로 작성되어야 한다.

더스틴보즈웰, 트레버파우커 저. 읽기 좋은 코드가 좋은 코드다. 임백준 역. 한빛미디어. 2012. 23페이지

코드를 완전히 이해 한다면 코드를 좀 더 자유롭게 변경 할 수 있다.

가장 읽기 쉬운 코드는 아무 것도 없는 코드다.

더스틴보즈웰, 트레버파우커 저. 읽기 좋은 코드가 좋은 코드다. 임백준 역. 한빛미디어. 2012. 192페이지

뭔가 멋지거나 대단한 기능을 구현하려고 하는 것 보다 이게 정말 필요한 기능인지 요구 사항을 잘 분석해야 한다. 불필요한 기능이 많아진다는 것은 불필요한 코드가 많아진다는 것이다.

변수명

변수의 이름은 작은 설명문이다. 충분한 공간은 아니지만, 이름 안에 끼워 넣은 추가 정보는 변수가 눈에 보일 때마다 전달된다.

더스틴보즈웰, 트레버파우커 저. 읽기 좋은 코드가 좋은 코드다. 임백준 역. 한빛미디어. 2012. 40페이지

책에서 가장 먼저 언급하는 것은 변수명에 관한 것이다. 변수, 함수, 혹은 클래스 등의 이름은 변수의 값을 설명하는 구체적인 정보가 포함되어야 한다. 본인이 지은 이름을 “다른 사람은 어떻게 해석할 수 있을까?” 라는 질문을 던져보며 고민해야 한다.

1// 좋지 않은 예
2public String get() {
3	//...
4}
5
6pubic void stop() {
7	//...
8}

위는 안 좋은 예이다. 어디서 뭘 가져온다는(get)것 인지 메소드명만으로는 전혀 유추가 불가능하다. 만약 인터넷에서 페이지를 가져오는 메소드라면 fetchPage() 또는 downloadPage() 등의 이름이 더 적절하다.

1// 좋지 않은 예
2for (int i=0; i<size; i++) {
3	for(int j=0; j<i; j++) {
4		//...
5	}
6}

특히, 루프안에서 사용하는 인덱스 변수는 간단히 작성하는 경우가 많다. 가능하면 의미를 담는 것이 좋다. 중첩 된 반복문의 경우 (애초에 중첩을 안하는게 좋겠지만!) 굉장히 도움이 된다.

일관성

얼마 전 자주 가는 개발 관련 커뮤니티에서 재밌는 글을 봤다. 자주 있는 논란이다.

 1// 보기 (1)
 2if(true) {
 3  //...
 4}
 5
 6// 보기 (2)
 7if(true)
 8{
 9  //...
10}

위 두 가지 스타일 중 어떤 스타일을 선호하냐는 글이 있었는데 댓글에 의견이 분분했다. 사실 정답은 없다고 생각한다. 각 언어 마다 전통적으로 권장 되는 스타일이 있고, 또 본인이 현재 속한 팀 안의 코드 컨벤션이 있을 것이고 말 그대로 Case by Case 이다. 중요한 것은 일관성 이다. 코드를 작성할 때 각종 스타일 (줄바꿈, 정렬 등)은 전체에 일관성 있게 유지하는 것이 중요하다.

일관성 있는 스타일은 ‘올바른’ 스타일보다 더 중요하다.

더스틴보즈웰, 트레버파우커 저. 읽기 좋은 코드가 좋은 코드다. 임백준 역. 한빛미디어. 2012. 73페이지

주석

주석의 목적은 코드를 읽는 사람이 코드를 작성한 사람만큼 코드를 잘 이해하게 돕는 데 있다.

더스틴보즈웰, 트레버파우커 저. 읽기 좋은 코드가 좋은 코드다. 임백준 역. 한빛미디어. 2012. 76페이지

주석을 다는 것보다 코드 스스로 설명하도록 하는 것이 좋다. 스스로 설명한다는 것은 변수나 메소드에 좋은 이름을 사용하는 것이다. 좋은 이름은 좋은 주석보다 더 낫다. 메소드를 설명할 때는 수행하는 동작을 설명하지 말고 의도를 명시하는 것이 좋다. 언어 자체가 야기하는 혼란을 제거하고 설명을 더 명확하고 자세하게 한다.

 1// (1) 단순히 수행하는 동작을 설명
 2// 리스트를  반복한다
 3for(String product Info : productList) {
 4  //...
 5}
 6
 7// (2) 의도를 명시
 8// 각 가격을 낮은 값에서 높은 값으로 하나씩 꺼내온다.
 9for(String product Info : productList) {
10  //...
11}

코드는 지속적으로 진화하며, 그러는 과정 중에 버그를 갖게 될 수 밖에 없다. 이러한 결함을 설명하는 것을 부끄러워 할 필요는 없다.

더스틴보즈웰, 트레버파우커 저. 읽기 좋은 코드가 좋은 코드다. 임백준 역. 한빛미디어. 2012. 81페이지

이 부분은 맘에 들었던 부분인데, 주석을 통해 코드에 있는 결함을 설명하라고 한다. 내가 사용하고 있는 IntelliJ 의 경우 TODO 주석을 작성 하면 별도의 메뉴에서 TODO 리스트들을 확인 할 수 있기 때문에 언제든지 리스트를 빠르게 체크할 수 있다. 가능하면 최선의 코드를 짜는 것이 좋지만 어떠한 이유로 결점이나 부족한 점이 있는 코드를 짰을 때, 이렇게 주석으로 남겨 두면 나중에 나 뿐만 아니라 다른 사람이 내 코드를 볼 때도 많은 도움이 될 것이다.

1// TODO: OOO점이 개선되어야 함.
2public void EnforceLimitsFromRequest(Request request, Reply reply) {
3  //...
4}

읽기 쉬운 흐름 제어

  • 아래 코드와 같이 부정보다 긍정이 먼저 등장하는 것이 좋다.
1// 좋지 않은 예
2// 부정보다는 긍정이 조건절에 등장하는 것이 좋다.
3if(!url.hasQueryParameter) {
4  //...
5} else {
6  //...
7}
  • 라인 수를 최소화 하는 일보다 다른 사람이 코드를 읽고 이해하는 데 걸리는 시간을 최소화하는 일이 더 중요하다.
 1// 삼항 연산자를 이용하면 코드를 한 줄에 나타낼 수 있다.
 2// 하지만 한 줄에 쓰기 그 이상도 그 이하도 아니다.
 3return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / 1
 4
 5// 라인 수는 늘어났지만 읽기가 좀 더 낫다.
 6if (exponent >= 0) {
 7  //...
 8} else {
 9  //...
10}
  • 조건문에서 인수의 순서는 왼쪽에 더 유동적인 ‘질문을 받는 표현'을, 오른쪽에 더 고정적인 값 즉, 비교 대상으로 사용되는 표현을 쓴다.
1if (10 <= length) {}
2while (bytes_expected > bytes_received) {}
3
4// 위보다 아래가 읽기 쉽다.
5if (length >= 10) {}
6while (bytes_received < bytes_expected) {}

이미 있는 코드를 읽어라

프로그래머는 이미 존재하는 라이브러리로 문제를 풀 수 있는 상황이 많다는 걸 모르고 있다. 아니면 라이브러리가 할 수 있는 일을 잊어버린다.

더스틴보즈웰, 트레버파우커 저. 읽기 좋은 코드가 좋은 코드다. 임백준 역. 한빛미디어. 2012. 196페이지

내가 처음 수행했던 프로젝트에서도 선배 개발자가 정의한 유용한 함수들이 꽤 많이 포함 되어 있었다. 하지만 그게 있는 줄 모르고 그 기능을 구현하기 위해 많은 시간을 허비한 경험이 있다. 꼭 새롭게 구현하는 것만 중요한 것이 아니라 필요할 때 어떤 걸 가져다 써야 하는지 아는 것도 중요하다.

* 2017-06-24 일부 내용 및 오타 수정.