The Art Of Readable Code.

24
The Art of Readable Code 세세 세세 The Art of Readable Code..................................................1 Chapter 1. Code Should Be Easy to Understand..............................2 Part I. Surface-Level Improvements........................................4 Chapter 2. Packing Information into Names.................................4 Chapter 3. Names That Can’t Be Misconstrued...............................9 Chapter 4. Aesthetics (아아아아아 아아아)........................................12 Chapter 5. Knowing What to Comment.......................................19 Chapter 6. Making Comments Precise and Compact...........................26

description

The Art Of Readable Code 라는 책의 Part One 부분을 책을 읽으면서 알게된 내용을 정리하고, 내가 겪은 사례들을 첨가해서 정리한 자료입니다. 상업적 목적이 아닌 내부 세미나용으로 자료를 정리했습니다.

Transcript of The Art Of Readable Code.

Page 1: The Art Of Readable Code.

The Art of Readable Code

세부 내용The Art of Readable Code..................................................................................................1

Chapter 1. Code Should Be Easy to Understand.................................................................2

Part I. Surface-Level Improvements...................................................................................4

Chapter 2. Packing Information into Names.......................................................................4

Chapter 3. Names That Can’t Be Misconstrued..................................................................9

Chapter 4. Aesthetics (아름다움에 대하여).........................................................................12

Chapter 5. Knowing What to Comment............................................................................19

Chapter 6. Making Comments Precise and Compact........................................................26

Page 2: The Art Of Readable Code.

Chapter 1. Code Should Be Easy to Understand

위 두 코드는 장단이 있다. 어떤 것은 compact 해서 좋고, 어떤 건 친숙해서 좋고. 우리는 어떤 코드를 짜야 할까? 이런 생각을 하게 된다. 그런데 이 근간에는 하나의 기본 철학을 둘 수 있다.

Code should be written to minimize the time it would take for someone else to understand it.

물론 좋은 코드는 어떤 측면에서 좋으냐에 따라서 판단이 달라질 수 있다. 그렇지만 위에서 이야기 한 것처럼 코드를 읽고 이해하는 데는 시간이 적게 걸릴 수록 좋지 않겠는가? 물론 수정할 일이 없을 정도로 아주 완벽한 코드를 짠다거나, 평생 내가 해당 코드를 짊어지고 간다면야 다른 이야기이다. 그러면야 남이 읽기 좋건 말건, 내 맘대로 짜고 성능도 좋고 정확히 동작하면 되겠지. 그렇지만, 우리는 그렇지 않은 상황에 처해 있다.

항상 다른 이가 작업한 코드를 읽고 사용하고, 수정을 해가야만 하는 상황에 처해 있는 것이다. 이런 상황에서 내가 타인이 읽기 힘든 코드를 작성하면서, 다른 이들이 읽기 편한 코드를 짜주기를 바라는 것은 말이 되지 않는다.

그리고 여기서 읽을 수 있었다는 것은 기본적으로 이해를 전제로 한다. 이해를 했다 함은 얼마든지 코드에서 결점을 찾아서 수정을 할 수 있어야 함을 이야기 하기도 한다.

이러한 측면에서 다음 코드를 봐봅시다.

assert((!(bucket = FindBucket(key))) || !bucket->IsOccupied());

이 코드가 읽기 쉬운가요? 이해하기 쉬운가요? 이보다는 아래 코드가 좋지 않은가요?

bucket = FindBucket(key);if (bucket != NULL) assert(!bucket->IsOccupied());

흔히 적은 코드를 작성하라고 합니다. 분명 동일한 동작을 하는 코드가 3 만 라인으로 구성된 것보다는 3 천 라인으로 구성된 내용이 더 좋기 때문입니다. 그렇지만, 이해가 더 중요합니다. 그래서 아래와 같이 이야기 할 수 있습니다.

"So even though having fewer lines of code is a good goal, minimizing the time-till-understanding is an even better goal."

앞서 언급한 예 외에도 여러 가지 요소들이 혹시나 readable 한 코드와 상충되는 것이 아닌가라는 생각을 하는 사람들이 있습니다. 실제로는 그러한 경우는 거의 없다고 할 수 있습니다. 간단히 생각해서 어떤 성능 좋은 코드가 있는데, 읽기가 어렵습니다. 이러한 코드가 읽기가 어려워야만 성능이 좋게 나올 수 있을까요? 오히려 읽기 좋게 만드는 작업은 코드를 더욱 멋진 구조로 만들기도 합니다.

Page 3: The Art Of Readable Code.

그럼 지금까지 이야기한 읽고 이해하기 좋은 코드를 만들기 위한 가장 좋은 방법은 뭘까요? 몇 가지 기술보다도 내가 작성한 코드를 타인의 입장에서 읽어보는 것입니다. 물론 이렇게 할 수는 쉽지 않습니다. 이미 나는 내가 작성한 코드를 알기 때문입니다. 그러나 이렇게 다른 이 입장에서 코드를 읽어보려는 마음 자세를 가지는 것 만으로도, 아무 생각 없이 프로그램을 작성할 때보다 더 나은 결과를 줄 것 입니다. 그리고 한 가지 팁으로 코드 리뷰 시간에 내 코드에 대해서 아무런 언급도 하지 않고 다른 이에게 읽게 해보세요. 그러면, 더욱 명확히 읽기 좋은 코드인가를 알 수 있답니다.

Page 4: The Art Of Readable Code.

Part I. Surface-Level Improvements가장 쉽게 적용할 수 있는 좋은 이름 쓰기, 커멘트 잘 달기, 코드를 적절한 포맷으로 맞춰서 만들기와 같은 단순한 또는 표면적인 부분부터 어떻게 하면 좋은지를 알아가 봅시다. 이러한 작업들은 refactoring 이나 프로그램 구동 방식을 바꾸지 않고도 할 수 있는 것들이라서, 심적인 부담도 많이 없습니다. 또한 시간도 많이 들지 않는 그런 작업들인 만큼 쉽게 해 나갈 수 있습니다. 쉽게 해 나갈 수 있다고 효과가 없는 것 절대 아닙니다. 이것만 해도 어마어마한 효과가 있으니, 의욕을 가지고 알아가 봅시다.

Chapter 2. Packing Information into Names

변수 이름은 어찌 보면 가장 짧은 comment 입니다. 즉, 이름들만 명확히 명명을 하더라도, 그 자체로 추가적인 comment 가 필요 없는 경우가 많습니다. 그럼 어떻게 할 수 있을까요?

가이드 1. Choosing Specific Words.

가능하면, 너무 많은 의미를 다음 단어보다, 구체적인 단어를 사용하도록 노력합니다. 물론 우리가 영어가 짧아서 이게 쉽지는 않지만, 그래도 해야겠다고 마음을 잡으면 더 나아질 수 있을 것입니다. 너무 많은 의미를 담아서 애매한 경우를 살펴 보면 아래와 같은 경우가 있을 것입니다.

BinaryTree.Size();

여기서 Size 라고 하는 함수가 뭘 줄까요? 이거 애매합니다. 왠지 사이즈에는 많은 것들이 있기 때문입니다. 예를 들어, tree 의 depth 를 줄 수도 있고, node 개수를 줄 수도 있고, 메모리 크기를 줄 수도 있구요. 이렇기 때문에 우리는 추가적인 주석을 달지 않으면, 적절한 의미를 실제 코드 안을 봐야 알 수 있는 것입니다.

이를 구체적인 단어인 BinaryTree.getHeigh() 라고 하거나, BinaryTree.getNumNodes()라고 명시하면 코드를 보지 않고 해당 함수에 대해서 좀더 명료하게 읽을 수 있습니다.

가이드 2. Finding More “Colorful” Words.

일상 생활에서 사용되는 수 많은 단어들이 있습니다. 그러한 단어들을 정확히 해당 상황에 맞는 단어가 있으면 그러한 단어를 사용하도록 노력합니다. 가령 make 라는 단어로 모두 상징해서 쓸 수 있는 상황에 대해서 아래와 같은 다양한 단어들 사용이 가능합니다.

create, set up, build, generate, compose, add, new

이렇게 상황에 따른 좀 더 명료한 단어가 있다면, 해당 단어를 쓰는 것을 주저하지 마세요. 이러한 각자 자기만 색깔이 있는 단어는 좀 더 정확한 의사 전달에 필수입니다.

가이드 3. Avoid Generic Names Like tmp and retval

일반적으로 아무 의미가 없이 임시로 사용되는 변수 명들이 있습니다. 예를 들어서 tmp, retval 과 같은. 물론 그 자체로 의미가 있는 경우가 있는 경우가 있습니다. 아래와 같이 값을 교환하는데 임시저장소 공간으로 의미가 있는 경우가 바로 그 경우이죠.

if (right < left) { tmp = right; right = left; left = tmp;}

이러한 경우 외에 아래 경우는 어떠한가요?

Page 5: The Art Of Readable Code.

String tmp = user.name();

tmp += " " + user.phone_number();

tmp += " " + user.email();

...

template.set("user_info", tmp);

위 경우에는 tmp 가 임시용이 아닌 user_info 데이터를 만들기 위한 것이기에 tmp 대신 userInfo 라는 변수명을 사용하는 것이 더 나았을 것입니다. 이는 더 명료하게 표현을 해주는 것과 함께, 있을 수 있는 실수를 방지하게 해 주기 때문입니다. tmp 라고 하면, 별도로 말 그대로 임시 변수라고 이야기 하는 것이기 때문에, 다른 사람들이 임의로 해당 변수에 값을 지정할 수 있습니다. 그런데, 만약 변수가 앞의 경우와 같이 특정 목적을 가진 항목 useInfo 라고 명명하면, 어떤 누가 userInfo 에 사용자 정보 아닌 다른 값을 설정하겠습니까.

이러한 측면에서 우리는 보통 loop 에 쓰는 위치 표시용 변수들을 다시 바라볼 필요가 있습니다.

for (int i = 0; i < clubs.size(); i++)

for (int j = 0; j < clubs[i].members.size(); j++)

for (int k = 0; k < users.size(); k++)

if (clubs[i].members[k] == users[j])

cout << "user[" << j << "] is in club[" << i << "]" << endl;

위와 같은 코드 어떠하신가요? 변수명 i, j, k 별 문제 없이 무난하게 보이시죠? 그런데, 프로그램 작성해 본 사람들은 대부분 이 i, j, k 가 혼돈을 가져다 주어 j 대신 i 를 깜빡하고 쓰는 경우가 있었을 것입니다. 이러한 경우에도 위치 지시자라 간단하게 임시 변수명을 쓰더라도, 아래와 같이 조금 의미를 더 해볼 수 있습니다.

club_i, member_j, user_k

이렇게 하면, 좀 길어지기는 했지만, 적절한 변수를 적절히 위치에 사용될 수 있게 해주어 버그 유발자를 제거하는 효과를 가져다 주기도 합니다.

이처럼, 어떤 값에 대해서 의미가 있다면, 의미를 구분 지을 수 있는 이름으로 바꿔줄 생각을 한 번 해보세요.

그렇게 한 번 하는 생각이 코드를 이해하기 좋게, 그러면서도 버그를 방지할 수 있게 해 줍니다.

가이드 4. Prefer Concrete Names over Abstract Names

유사한 흐름이지만, 이름에는 구체적인 동작이 명시가 되어야 합니다. 가령 A 라고 이야기를 할 때 코드를 읽는 사람은 여러 상황을 생각하게 되는데, 실제 코드는 한 가지 상황만을 이야기 한다면, 이는 이름이 abstract 한 경우입니다. 예를 들어서, DISALLOW_EVIL_CONSTRUCTOR 라는 이름이 있다고 생각해 봅시다. 이게 의미하는 것이 뭘까요? 뭔가 evil 한 생성자일까요? 결국에는 이게 뭘 방지하고 싶은 것일까요? 이를 DISALLOW_COPY_AND_ASSIGN 이라고 변경하면 어떤가요? 아까 보다 구체적으로 의미가 전달되는 것을 알 수 있습니다. 이처럼 모든 이름은 abstract 하면 바로 concrete 하게 바꾸도록 합시다.

이러한 명명은 옵션 설정에서도 적용이 됩니다. –run_locally 라는 옵션이 있습니다. 이걸 첨 보는 사람은 로컬 환경으로 돌리는가 보다라는 생각을 할 것입니다. 그런데 내부적으로는 로컬 환경에서 구동을 시키면서,

추가적인 debugging 메시지를 남기도록 하는 명령이고, 이로 인해서 속도가 느려지는 현상이 있습니다. 즉 로컬에서 돌리면서도 위 옵션을 주지 않고 돌릴 수도 있고, 더 빠르게 돌게 되는 것입니다. 이를 알고 있는 처음 옵션 생성자는 성능 테스트를 할 때에는 이 옵션을 사용하지 않았습니다. 그런데, 다른 사람들은 어떨까요?

이러한 배경 상황을 모르기 떄문에, 로컬 환경에서는 죽으나 사나 위 옵션으로 돌리겠죠. 이러한 부작용을 방지하기 위해서 좀 더 구체적인 상황을 담아서 명명해봅시다. –run_locally 옵션 이름을 –extra_logging 이라고

Page 6: The Art Of Readable Code.

바꾸면 어떤가요? 좀 더 명료해지고, 추가적인 배경 설명 없이 옵션을 적절히 사용할 수 있을 것을 기대할 수 있습니다.

이 때, 어떤 이는 말 그대로 로컬 환경에 맞춰서 구동하는, DB 를 local DB 를 사용해서 구동하게 해야 하는 옵션이면 어떻게 할지 의문을 가질 수도 있습니다. 이런 경우 우리가 지금까지 알아온 것과 같이 상황을 구체적으로 명시하는 옵션을 사용하면 됩니다. –user_local_database 라는 옵션 이름을 사용할 수 있겠죠.

찾으려 하면 구체적인 이름을 얼마든지 찾을 수 있습니다. 중요한 것은 모호함을 주는 이름은 사용하지 않도록 하는 인식인 것입니다.

가이드 5. Attaching Extra Information to a Name

변수 이름은 어떤 주석보다 효과적인 주석이며, 그렇기에 최대한 효율적으로 사용해야 합니다. 즉 우리는 최대한 압축을 해서 구체적인 정보를 변수에 넣을 수 있도록 합니다. 예를 들어서 생각해 봅시다.

private String id; // hexadecimal format. For example, “af84ef845cd8”

id 라는 변수가 있는데, 이게 hexa 형 값인게 무척 중요한가 봅니다. 주석을 마구마구 써 놓은 걸 보니. 곰곰히 생각하니 일반적인 id 가 아닌데, 이를 사용하는 입장에서는 주석을 보지 않으면 이게 hexa형 값인지 전혀 모르겠군요. 그럼 우리 이걸 아래와 같이 말 그대로 변수 이름으로 주석을 달아봅시다.

private String hex_id;

이렇게 하면 이 자체로 명료해집니다. 그리고 이 변수가 어디에서 사용이 되더라도, 모두들 이게 hex형 값이구나라고 바로 알 수 있을 것입니다. 이런 유사한 사례들이 많이 있습니다. 가령 시간 데이터 경우와 같이 단위들이 있는 경우들이 있죠. 이러한 경우에도 sec 기준인지 ms 기준인지를 변수에 추가해두면 명료해진 경우가 많습니다. 사실 이렇게 안 되어 있어서, 코드를 다시 거꾸로 올라가면서 변수 단위를 찾았던 경험들이 있지 않나요? 이러한 동작 자체가 이해하기 어려운 코드, 읽기 어려운 코드임을 나타냅니다. 이런 유사한 사례로서 여러 가지가 많습니다. 어떤 String 이 인코딩 타입이 있는 경우에, 이런 정보도 변수에 녹일 수 있는 것이죠. 이렇게 명명한 것들에 대한 예는 다음과 같습니다.

delay delay_secs, size size_mb, password plaintext_password, html html_utf8, data data_urlenc

골자는 이겁니다. 변수명에 코멘트를 녹여버려라!

가이드 6. How Long Should a Name Be?

앞서 우리는 변수명에 코멘트를 녹이는 것을 이야기 했다. 그러다가 보면, 엄청 길어지는 변수명도 태어날 수 있다. 예를 들어서 newNavigationControllerWrappingViewControllerForDataSourceOfClass 라는 이름과 같이. 이건 누가 봐도 과하지 않는가? 그렇다고 해서 짧게 m 이라고 표현되는 것은 이해를 하게 힘들게 한다.

그럼 어쩌란 말인가? 답은 적당히 라고 말할 수 있다.

그래도 가이드는 있으면, 적용하기 편할 터이니, 간단한 가이드를 정해봅니다. 사용되는 변수나 함수가 사용되는 범위의 크기와 변수 길이는 비례하면 좋습니다. 이게 무슨 말인가 하면, 바로 이해가 되는 그 기원을 알아내는 것이 바로 가능한 정도 수준이면, 변수 명을 짧게 해도 좋다는 것이죠. 예를 들어 아래와 같은 경우가 있습니다.

if (debug) {Map<String, int> m;lookUpNamesNumbers(&m);print(m);

}

위와 같은 경우에 m 이라고 표기해도 짧은 범위에서 이해되고 사용되니깐 문제가 되지 않습니다. 그런데 만약

Page 7: The Art Of Readable Code.

LookUpManager.m; 이러한 코드가 있다고 생각해 봅니다. 이거 이해가 되시나요? 이해하기 위해서는 LookUpManager 클래스에서 m 이라는 변수에 대한 주석을 찾아야 겠지요. 이런 측면에서 가이드라고 생각할 수 있습니다.

이 외에 흔히 나오는 이슈 중 하나가 약어입니다. BEPManager 라는 클래스 이름이 있습니다. 이해가 가시나요?

이해가 되지 않으시죠. BackEndProcessManager 라고 하면 어떤가요? 이해가 되시죠. 이게 바로 핵심입니다.

다른 이가 봐서 이해가 힘들 정도의 약어는 사용을 피하세요. 여기서 다른 이라고 하면 외부 개발팀에서 신규로 이동해 온 개발자를 기준으로 생각하시면 될 것 입니다. 물론 이런 관점에서 보면, 오히려, readDocument 라고 적는 것보다는 readDoc 라고 사용하는 것이 더 나을 것입니다.

이처럼, 길이에 대한 제약은 비상식적으로 길어지는 것은 경계하면서도, 다른 사람이 봐서 혼돈이 되지 않을 수준에서는 짧게 작성하도록 하는 것이 읽기 좋은 코드를 만드는 길이 될 것입니다.

가이드 7. Use Name Formatting to Convey Meaning

이름은 하나의 코멘트라는 관점에 포맷을 활용해서 추가적인 정보를 전달할 수 있습니다. 예를 들어서 클래스 멤버 변수에 대해서 m_pageHeight 와 같이 ‘m_’를 앞에 붙인다고 하면, 이 자체로 추가적인 정보를 전달하게 됩니다. 또한 이러한 일환으로 상수 값에 대해서는 모든 값을 대문자로 쓰게 하는 것도 활용의 한 예입니다.

언더스코어(_), 대소문자 및 기타 기호들을 활용해서 추가적인 정보 전달이 가능합니다. 그런데 이렇게 포맷을 통해서 정보 전달하는데 있어서 중요한 점이 있습니다.

“어떠한 포맷을 사용해서 정보 전달하는 것은 결정해야 할 사항입니다만, 결정을 했다면 전체 프로젝트에 대해서 일관성 있게 적용이 되어야 합니다.”

Page 8: The Art Of Readable Code.

Chapter 3. Names That Can’t Be Misconstrued

앞선 장에서 이름들에 의미를 부여하는 방향으로 이야기를 했다면, 이제는 오해가 있지 않을 수 있도록 이름을 사용하자는 관점에서 이야기를 풀어봅니다. 이렇게 하는 가장 중요한 길은 자신이 만든 이름에 대해서 “어떻게 오해할 수 있을까?”로 자문을 해보는 것 입니다. 그러나 이렇게 하는 것이 아직은 익숙하지 않기 때문에 구체적인 예를 통해서 하나 하나 오해를 할 여지가 어디에 있는지 알아보고, 이를 통해서 우리가 만드는 이름에도 오해 여지를 없앨 수 있도록 조심합니다.

예. Filter 라는 이름의 함수.

Results = Database.all_objects.filter(“year <= 2011”);

위와 같은 문장이 있을 때, Results 는 어떤 값일까요? 2011 이하는 대상들 모임일까요? 아니면 2011 이하 대상은 제거하고 나머지들 모임일까요? 이게 바로 오해 여지입니다.

이렇게 이중적 해석이 될 수 있는 함수 이름 보다는 select 또는 exclude 와 같이 오해 여지가 적은 이름을 사용할 수 있을 것입니다.

Prefer min and max for (Inclusive) Limits

이번에는 흔히 접하는 한계값에 대한 오해 여지 있는 부분들에 대해서, 알아봅시다. 예를 들어서 우리는 사람이 쇼핑을 할 때, 한 번에 10 개 까지만 살 수 있도록 프로그램을 작성한다고 해봅시다. 이러한 것을 코드를 짜면 이렇게 짜는 사람이 있겠지요.

CART_TOO_BIG_LIMIT = 10if shopping_cart.num_items() >= CART_TOO_BIG_LIMIT: Error(“Too many items in cart”)

이러한 코드 어떠한가요? 앞서 어떤 상황에 대한 코드라는 설명이 없었다라고 생각하고, 코드를 찬찬히 봐보면 어떤가요? 이게 10 을 포함하는게 맞는 것인가 아닌가 혼돈스럽지 않은가요? 스펙이 뭔지 다시 한 번 스펙을 찾아볼 것 같지 않은가요? 이러한 혼란의 원인에는 CART_TOO_BIG_LIMIT 라는 변수명에 있습니다. 이 변수 명만 보면 이 값에 지정된 값이 포함될 수 있는 최대 값인지 아니면, 포함되지 않는 경우인지 명확하지 않기 때문입니다. 이런 면에서 보면, 왠지 코드만 보면 맞는 것 같지만, 스펙과는 다른 코드인 것이죠. 이를 아래와 같이 고치면 이해가 좀 더 명료해 질 수 있을 것 같습니다.

MAX_ITEMS_IN_CART = 10if shopping_cart.num_items() > MAX_ITEMS_IN_CART: Error(“Too many items in cart”)

이처럼 한계값이 불명확한 경우에는 MAX 나 MIN 이라는 값을 사용해서 포함하는 것을 명료하게 할 수 있습니다.

물론 혹자는 주석을 잘 달면 되지 않겠냐라고 할 수 있습니다. 그런데, 우선 명료하게 이름을 지어두면 구지 주석까지 안 찾아봐도 이해가 될 수 있다면, 그 것으로 족하지 않나요. 이런 용도로 쓰이는 좋은 단어들로서 first,

last 와 같은 것이 있습니다.

여기서 이야기하고자 하는 것은 어떤 단어를 꼬옥 쓰라는 이야기가 아닌, 혼돈을 줄 수 있는 부분에 대해서는 이를 명료하게 이름 지어 주자는 것입니다. 아 그리고 관례적으로 쓰는 것이 있는데, begin/end 쌍입니다. 여기서 end

는 프로그램 세계에서는 관행적으로 exclusive 즉 포함하지 않습니다. 이런 측면에서 아래와 같은 메소드 명을 정의하고 있는 경우들이 있습니다.

substring(int beginIndex, int endIndex)

위 함수에서도 end 는 관례에 맞춰서 해당 index 에 있는 항목은 포함하지 않는답니다.

Naming Booleans

Page 9: The Art Of Readable Code.

우리가 흔히 사용하면서, 대표적으로 애매하게 작성하는 변수명 중 하나는 바로 Boolean 값에 대한 변수입니다.

예를 들어서 boolean read_password = true; 라는 문장이 있을 때, 이게 무슨 뜻일까요?

구지 해석을 한다면, 우리는 암호를 읽을 필요하다라고 해석을 할 수도, 이미 암호는 읽혔다고 해석을 할 수도 있습니다. 이런 게 바로 애매함입니다. 우리는 이 변수의 진실을 찾기 위해서 코드를 쭈욱 보고 다니겠죠.

그러다가 아 이런 뜻이구나 라고 이해를 할 것입니다. 그리고 나 뿐만 아니라 모든 코드를 보고 이 변수를 만나는 사람들은 모두 한 번씩 그러겠죠. 이게 바로 우리가 코드를 읽기 좋게 짜야 하는 이유입니다.

위 변수를 만약 need_password 또는 user_is_authenticated 라고 사용을 한면 어떤가요? 아까보다 좀 더 명료하게 보이지요? 이렇게 명료하게 하는 것이 중요합니다. 이렇게 하는 데 몇가지 팁을 드리면, is, has, can

또는 should 와 같은 단어를 써서 표현하면 좀 더 명료한 변수 정의가 가능합니다. 그리고 또 하나 아주 중요한 것이 있는데, 가능한 not 의미를 담은 변수보다는 그렇지 않은 변수 명을 사용할 것을 권장 드립니다. 이렇게 하는 것은 not 이 들어가면 지정된 변수 값에 대해서 not 이란 의미를 더해서 해석하게 되는데, 이게 혼돈을 가져다 주기 때문입니다. 말로만 이야기 하니 혼돈스럽죠? 예로 갑니다.

Diable_ssl = false; use_ssl = true;

위 2 개 변수는 ssl 을 사용한다는 의미인데, 어느 게 더 읽기 좋고 혼돈이 적은가요? Not 의미가 안 담긴 변수명 쪽이지 않은가요? 이렇게 작은 노력 하나가 코드를 읽기 좋게 해 줍니다.

Matching Expectations of Users

의외로 잠시 이야기 나온 관습적인 용어들이 있습니다. 금방 이야기한 begin, end 가 그러하지요. 이러한 관습적인 의미에 대해서는 그 의미를 지켜주어야 합니다. 만약 다른 상황이 있다면 다른 이름을 취해주는 것을 적극 추천합니다.

예 들어갑니다. ㅎㅎ. 바로 get 으로 시작되는 함수명을 생각할 수 있습니다. 일반적으로 get 으로 시작하는 함수는 변수에 대한 단순 추가/삭제로 인식하고는 하며, 그렇기에 함수 수행 비용에 대해서 가볍게 생각하고 수행을 합니다. 이런 관습적인 생각을 고려하지 않고 getMean 이라는 함수를 만들고, 그 안에 수 많은 복잡한 계산을 하는 로직을 작성해서 한 번 수행에 10 분이 걸리는 경우가 있었습니다. 그런데, 이 함수가 이렇게 도는 것인지 모르고(?) getMean 을 수시로 호출했고, 결국 서비스 장애로 이어진 경우가 있습니다. 이러한 경우 처럼 관행적인 개념은 어느 정도 지켜주어야 합니다.

이와 유사한 사례로, size 함수가 있습니다. 대부분 데이터구조체는 size 를 가지고 있습니다. 그리고 그 계산해 내는 속도는 O(1)로 생각하고는 합니다. 그런데, 만약 O(n2) 속도로 계산이 된다면. 이 이름만으로 해당 함수가 그럴 것이라고 상상이라도 할 수 있을까요? 바로 이런 부분이 미묘하지만, 관행적인 의미를 넘는 경우임에도 이를 동일 이름을 사용해서 오해를 가져오는 경우들입니다.

이러한 경우 외에도 많은 경우들이 우리는 쉽게 이름을 짓지만, 다시 보면 명확히 전달이 안 되는 경우가 많습니다. 특히나 우리는 미국 사람이 아니니, 더욱 그런 경우들이 있겠죠. 그러니 우리 좀 더 신경을 써서 이름을 오해 또는 혼돈이 없을 수 있는 이름을 선택하도록 노력해야 할 것입니다. 그리고 이런 면에서 볼 때 방향성을 주의해서 보면 좀 더 명료한지 확인 가능합니다. 어떤 이름이 한 방향으로 해석이 되는지 아니면 다른 방향으로도 해석이 되는지, 원하는 방향을 가리키고 있는지를 고민하는 것이지요.

마지막으로 다시 한 번 생각하는 면에서 실례를 하나 더 소개하겠습니다. Is_overwrite 라는 Boolean 값이 있습니다. Is_overwrite = true; 라면 이게 무슨 이야기일까요? 이해가 되시나요? 참고로 overwrite 라는 것을 덮었는 동작을 표현하는 면에서 overwrite 입니다. 그래도 이해가 되시나요? 만약 can_overwrite = false; 라면 이해가 되시나요? 두번째 것은 덧글 방지되어다는 의미로 이해가 될 것입니다. 문제는 is_overwrite 가 덧글 방지 상태인가라는 것을 번역하면서, 사용한 변수이고, 그 의미가 엉뚱하게 혼돈을 주고 있다는 현상입니다. 이것은 하나의 예일 뿐, 우리는 오늘도 많은 이름들을 짓고 있습니다. 이럴 수 있다는 점을 느끼고 다시 한 번 보는 것이 좋을 것 같습니다.

Page 10: The Art Of Readable Code.
Page 11: The Art Of Readable Code.

Chapter 4. Aesthetics (아름다움에 대하여)

책을 생각해 봅시다. 책은 동일한 내용임에도 문단을 어떻게 표시를 하고, 그림 배열을 어떻게 하고 폰트를 어떤 크기로 하는가와 같은 점에 따라서 독자에게 다가오는 정도가 많이 다릅니다. 그런 면에서 좋은 책은 동일한 내용이라도 술술 넘어가게 구성이 되어 있는 경우가 많지요. 우리가 이번에 생각하는 부분이 바로 이 부분입니다.

이런 게 코드에선 어떻게 보일까요? 아래 예를 통해서 느껴 봅시다.

어떤가요? 보기 좋은가요? 이와 동일한 내용인데, 아래와 같을 수도 있습니다.

이게 바로 어찌 보면 코드에 있어서 본질은 같지만 다른 외형으로 코드를 읽는 이들이 편하게 코드를 읽을 수 있는가를 알려줍니다. 우리는 이제 이러한 관점에서 보기 좋게 하는 부분에 대한 가이드가 될 수 있는 내용들을 살펴 보고자 합니다.

Rearrange Line Breaks to Be Consistent and Compact

보통 우리는 80 자 길이로 코드를 작성하면서, 줄넘김을 무심코 사용하고는 합니다. 그런데 이 부분에 대해서 좀 더 신경을 쓰면 좀 더 효과적인 정보 전달이 가능합니다. 예를 보면서 생각해보죠.

Page 12: The Art Of Readable Code.

위 코드 어떤가요? 왠지 두 번째 생성자가 맘에 걸리지 않나요? 바로 이런 걸림은 뭔가 술술 넘어가지 않는 코드라는 것을 의미합니다. 이 부분을 사소하지만 아래와 같이 바꿔봅니다.

이렇게 만들 때 나름 “유사한 기능을 가진 이들은 유사한 모습을 가지도록 한다.”라는 원칙을 하나 가지고 모양을 바꾸어 본 것입니다. 별 차이 없는데, 좀 더 나은가요? 여기다가 뭔가 많은 반복되는 것이 눈에 거슬리면 이렇게 까지 만들어볼 수 있습니다. 조금 생각하면 많은 변화를 가져올 수 있지요.

Page 13: The Art Of Readable Code.

동일한 주석을 한 곳으로 모으고, 탭을 활용해서 동일한 데이터는 동일한 컬럼에 보이듯이 조정을 했습니다. 처음 접했던 코드보다 좀 더 잘 넘어가지 않나요? 이렇게 하기 위해서 탭까지 쓰면서 해야 하는가? 이런 질문을 하실 분들이 당연히 있습니다. 판단은 당신의 코드가 어떻게 읽혀지길 바라는가 수준에 달려 있다고 이야기 드리겠습니다.

Use Methods to Clean Up Irregularity

지금부터 이야기할 부분은 방법적인 면입니다. 지저분해 보이는 코드를 어떻게 하면 정리를 할지에 대한 이야기 중 하나로서 새로운 함수를 통해서 정리하는 방법을 알아보겠습니다. 바로 코드 들어갑니다. ^^

위 코드는 ExpandFullName 에 대해서 검증을 하는 코드이지요. 근데 뭔가가 복잡하다고 생각이 들고 왠지 반복되는 내용이 많이 보이시죠. ExpandFullName(database_connection, …) 이런 형태가 반복이 됩니다.

그렇다면 이런 부분에 대해서 반복되는 내용에 대해서 의미를 간명하게 하면서 모습도 정리를 해보고자 합니다.

이 과정에 새로운 함수를 선언하게 되는 것이죠. 우선 위 코드를 의미만 살려서 아래와 같이 정리합니다.

읽고 이해하는데 편해졌죠? 물론 CheckFullName 이 내부적으로 어떻게 구현이 되어있는 지는 현재로서는 잘 모르겠지만, 원래 코드가 의도하는 바는 위와 같이 정리함으로 인해서 명료해짐을 경험할 수 있습니다. 이는 흔히 refactoring 에서 나오는 기법 중 하나이기도 하지요. 다시 돌아가서 새로 만들어진 함수는 어떻게 정리가 되었는지 확인하도록 합시다. 세부 구현은 아래와 같습니다.

Page 14: The Art Of Readable Code.

이렇게 정리를 하면서, 우리는 코드를 보기 좋게 만드는 것이 단순히 시각적인 뿐만 아니라, 기능적인 면 구조적인 면에서도 좋은 영향을 준다는 사실을 알 수 있습니다. 이는 앞으로 보는 대부분 사례에서도 볼 수 있는 긍정적인 추가적 효과라고 할 수 있습니다.

Use Column Alignment When Helpful

지금 볼 내용은 앞에서 서론적인 내용으로 언급이 된 내용인데, 다시 한 번 보겠습니다. 이거 싫어할 개발자 참 많을 것이라 생각이 됩니다만, column 정렬을 보기 좋게 하자는 시도입니다. 우선 간단히 앞서 예제에서 본 내용을 생각합시다.

왠지 산만하지 않나요? 뭐 이것까지 산만하냐라고 이야기 하시는 분 많을 것입니다. 그래도 우리는 코드를 읽는 분이 정말 맘에 드는 모습으로 만들어보는 것을 목표로 하기 때문에 정리를 해 보겠습니다.

어떤가요? 더 낫지 않은가요? 반복되는 구문에서 각각 어떤 인자에 어떤 값이 들어가는지 한 분에 확 들어오시죠?

그런데 여기서 강조하고 싶은 부분이 있습니다. 눈에 확 들어온다는 이야기는 그만큼 실수도 눈에 잘 보인다는 이야기 입니다. 아래 예를 보도록 하지요.

위 코드 어떤가요? 우리 흔히 보는 코드이죠? 볼 때 마다 드는 생각인데 참 지전분하죠. 게다가 위 코드는 버그도 있습니다. 물론 이런 버그는 요즘 개발도구가 다 잡아주지만, 예로서 본다 생각해 주세요. 위 코드가 가진 버그가 뭘까요? 찾으셨나요? 아직 못 찾은 분들을 위해서 단순히 코드 칼럼을 맞춰줘 보겠습니다.

Page 15: The Art Of Readable Code.

이제 보이시나요? Phone 에 대한 선언부에서 request 가 r 이 빠진 상태로 정의가 되었죠? 이렇게 모양을 보기 좋게 하는 것은 한 눈에 코드가 보이게 해주고, 이에 따른 좋은 효과를 가져다 줍니다.

이 정도 하면 대부분 개발자가 이런 이야기 할 거에요. 이렇게 하다보면, diff 인식 처리에서 많은 문제가 올 때가 있어요. 그리고 이렇게 하는 것 번거러워요. 이거 맞는 이야기 입니다. 그렇지만, diff 인식이야 조정이 가능하고 생각 외로 번거롭지 않습니다. 오히려 예뻐진 코드를 보면 더욱 해보고 싶어질 것입니다. 한 번 해보실 것을 권장 드립니다. 해보고 아니면 안 하면 되시잖아요.

Pick a Meaningful Order, and Use It Consistently

이해하기 좋은 코드는 흐름이 크게 변하지 않는 코드입니다. 이러한 흐름 속에는 반복되는 순서도 포함되어 있습니다. 앞서 우리는 request.POST.get 에 의해서 변수 설정하는 코드를 보았습니다. 이 부분을 기준으로 더 들어가 보겠습니다.

위 문장에 이어서 아래와 같은 문장이 오는 경우를 생각해봅니다.

이야기 하려고 하는 부분이 어떤 부분인지 아시겠죠? 바로 단순하지만 순서입니다. 사람들은 하나의 동일한 모습들은 동일하게 유지되기를 바랍니다. 그런데, 위와 같이 작지만 순서를 바꾸어 두면, 무의식 중에 찾는 동작을 더 하게 됩니다. 그리고 이는 코드를 읽는데 걸림돌이 됩니다. 작은 만큼 작성자가 조금만 더 신경을 쓰면 훨씬 읽기 좋은 코드를 만들 수 있습니다.

Organize Declarations into Blocks

지금 이야기 드릴 내용은 프로그램 짤 때부터 암묵적으로 맨날 들었던 이야기지만, 확인 차원에서 한 번 보고 넘어갑니다. 우선 코드를 봅니다.

Page 16: The Art Of Readable Code.

위 내용을 보면 산만하죠? 이는 선언 시점에도 유사한 속성들로 분리해서 정리를 할 수 있는데, 하지 않았기 때문입니다. 좀 더 정리를 해보겠습니다. 이 때 의미가 유사한 것들을 덩어리로 만들어 둔다는 느낌으로 정리하면 아래와 같습니다.

주석까지 해서 구분되는 영역에 대한 설명을 넣어주니 보기 좋죠? 이해하기 편하다를 떠나서, 보기 좋으면 보고 싶은 마음이 더욱 들게 되어 있습니다. 누군가 선언을 처음에 본 예와 같이 해 준 코드를 본다면, 보자마자 더 이상 보고 싶지 않을 것입니다. 그렇지만 아래와 같이 정리된 코드를 접한다면, 왠지 볼만하겠죠? 우리가 만드는 코드가 이렇게 인식되기 위해서라면 매번 이야기 하지만, 조그만 읽는 이를 배려해서 코드를 작성하면 됩니다.

Break Code into “Paragraphs”

이 내용은 앞선 내용과 중복되는 감이 있는 내용인데, 선언부 외에 실제 구현하는 코드에 있어서도 의미 단위로 묶을 수 있다면, 묶어 주도록 합니다. 이에 대해서는 추가 설명 없이 나쁜 예와 좋은 예를 바로 보도록 합시다.

Page 17: The Art Of Readable Code.

좀 정리해야겠죠! 우리는 아래와 같이 정리할 수 있습니다.

다시 이야기 드리지만, 남의 이야기가 아닙니다. 다른 사람들이 내 코드를 보면서 우리가 방금 봐온 것 같이 ‘뭐야 이거~’ 아니면 ‘음 깔끔한데.’ 이렇게 이야기합니다.

Summary

지금까지 본 내용은 코드 모양새에 대한 이야기 입니다. 우리가 여기서 이야기 드린 내용은 coding convention

에 의해서 기술이 되기도 하지만, 그렇게 까지 하기는 너무 제약적이라 이야기 하지 않은 부분들도 있습니다.

그런데 이 모든 내용에는 다음 생각이 가장 기본입니다.

유사한 의미를 가진 것들은 뽑아주고, 모아줍시다. 그리고 더 나아가 유사한 코드는 유사한 모습을 취하도록 합니다. 보기 좋은 코드가 읽기도 좋습니다.

Page 18: The Art Of Readable Code.

Chapter 5. Knowing What to Comment

우리는 주석을 코드 상에 적습니다. 그런데, “왜 주석을 달아야 할까?”에 대해서 생각을 한 번 해볼 필요가 있습니다. 간혹 필요 없는 주석 또는 이상한 주석은 코드를 읽는 것을 더 힘들게 하기 때문입니다. 또는 꼬옥 필요한 부분인데, 해당 부분은 주석은 없는 경우가 있는 경우가 있기 때문입니다.

주석을 작성하는 목적은 아무래도 코드를 작성하는 당시에 코드 작성자가 아는 것들을 코드를 읽는 이에게 전달하기 위함입니다. 여기서 코드를 읽는 이는 본인이 될 수도 있습니다. 여기서 코드 작성자가 아는 것들이라는 것 중에는 어떤 것은 코드에 묻어날 수도 있고, 어떤 것은 자신은 당연하다라고 느끼면서 적어야 할 것이 무엇인지를 모르는 경우도 있습니다. 이러한 부분들에 대해서 하나하나 사례를 보면서 정리를 해보고자 합니다.

Knowing what not to comment

주석 역시도 코드를 읽는 때 읽는 부분입니다. 그리고 주석이 들어가는 만큼 코드 줄 수는 늘어납니다.

그렇기에 주석도 정말 필요한 항목들이 아닌 이상은 코드를 읽는데 방해만 될 뿐 입니다. 이런 측면에서 아래 코드를 봅시다.

위 코드에 있는 주석은 어떠합니까? 필요할까요? 필요하지 않습니다. 주석 자체가 코드에서 주지 않는 정보 이상을 주지 않기 때문입니다. 여기서 우리는 다음과 같은 규칙을 하나 가져봅니다.

코드 자체에서 바로 알 수 있는 사실에 대해서는 주석을 달지 맙시다.

여기서 “바로 알 수 있는” 사실은 어떤 정도일까요? 이에 대해서 다시 생각하는 측면에서 아래 코드를 봅시다.

위 주석은 어떤가요? 위 주석은 코드에 있는 내용 외에 다른 추가적인 정보가 없습니다. 그렇지만,

코드를 읽어서 이해하는 것보다 주석을 보고 이해하는 것이 더 빠릅니다. 이런 면에서 “바로 알 수 있는”이라는 측면에서 위 주석은 의미가 있는 것입니다. 즉 주석은 코드 자체에서 알 수 있는 것은 작성하지 않더라도, 코드를 이해하는데, 시간이 걸리면 이에 대한 직관적인 설명은 필요한 주석이라 할 것 입니다.

앞 서 언급한 내용과 관련된 부분인데, 우리는 아무런 생각 없이 또는 교육을 주석을 무조건 작성하도록 길들여져 있어서, 그 폐단으로 아래와 같이 주석을 다는 경우가 있습니다.

Page 19: The Art Of Readable Code.

이거야 말로 정말 의미 없는 주석입니다. 말 그대로 함수 이름을 풀어서 주석을 달았을 뿐인 것이죠.

이러한 주석은 자동화된 주석으로 많이 생성되고는 합니다. 정말 수 많은 getter/setter 에 대한 의미 없는 주석들이 가득하지요. 이런 주석에 대해서 항상 유의미한가를 생각해서 필요가 없다면, 제거를 하고 필요하다면 아래와 같이 정말 필요하게 추가적인 정보를 전달하도록 주석을 달도록 합시다.

앞서 본 주석과 위 주석은 다르죠. 바로 코드 자체에서 읽을 수 있는 내용이 아닌 추가적인 중요한 정보를 전달해 주기 때문입니다. 바로 이런 주석이 필요한 것이죠.

주석들 중에는 아래와 같은 주석도 있습니다.

어떤가요? 뭔가 개선할 부분이 있어 보이나요? 멋진 주석인가요? 흔히 좋은 코드는 주석 없이도 코드 자체로 정확히 의미 전달이 되는 코드라고 하지요. 그런 측면에서 보면 위 코드는 어떠합니까? 이 코드를 아래와 같이 바꾸어 보겠습니다.

뭐가 달라졌나요? 함수 이름 자체가 잘 못 되어서, 우리는 추가적인 정보를 마구마구 주석으로 감당했던 것입니다. 그것을 위와 같이 함수 이름을 정확히 고침으로 인해서, 필요 없는 주석들을 지울 수 있었습니다. 이 부분 굉장히 중요합니다.

함수를 호출하는 입장에서는 주석까지 포함해서 호출하지 않습니다. 즉 본 함수를 호출하는 모든 위치들을 찾아가면서, 주석을 달아주지 않을 것이면 위와 같이 모호한 이름에 대해서는 주석이 아닌 이름 자체를 고치는 방향으로 접근해야 하는 것입니다. 이렇게 하는 행동이 다른 함수에서 잘못된 함수 호출을 방지하는 길입니다. 사고가 터진 뒤에 “이런 함수인지 몰랐어요.”라고 하는 동료에게 “주석에 다 써 두었는데, 왜 안 봤어!”라고 화를 내는 것이야 말로 정말 수준 낮은 프로그래머입니다.

다시 한 번 생각합니다. 코드 이름 자체가 모호한 경우에는 이름 자체를 명확하게 수정을 하도록 해야지, 주석으로 감당하려 하지 말도록 합시다.

즉. Self-documenting 하는 코드가 주석보다 우선하는 것입니다. 항상 좋은 이름은 좋은 주석보다 우선함을 명심하도록 합시다. 이런 측면에서 아래 코드 한 번 봅시다.

위 코드 자체는 굉장히 위험해 보입니다. 레지스트리를 지운다니. 그런데 자세히 보면 주석으로 실제 레지스트리는 지우지 않고 키에 대한 handle 만 풀어준다고 합니다. 멋진 주석인가요? 위 코드는

Page 20: The Art Of Readable Code.

차라리 아래와 같이 고치는 것이 어떨까요?

어떤가요? 주석 하나도 없이 원하는 바가 잘 전달되고 있습니다. 바로 이렇게 self-documenting 하는 코드를 작성해야 합니다.

Recording your thoughts

지금까지 주석을 달지 말아야 하는 부분에 대해서 이야기를 했습니다. 이제는 반드시 주석으로 기술되어야 하는 것에 대해서 알아보겠습니다.

좋은 주석들을 자세히 보면, 코드 작성할 당시에 코드 작성자가 가지고 있던 중요한 정보들을 담고 있는 주석입니다. 이른바 프로그래머의 생각을 전달하기 위한 주석들인 것이죠. 이러한 생각은 마치 해당 부분에 대한 insight 나 숨은 이야기들을 담고 있습니다. 모호하군요. 구체적으로 아래 예를 보도록 합시다.

위 주석은 해당 코드를 작성했던 이가 이러한 코드가 나오게 된 insight 나 배경 정보를 제공함으로 코드를 읽는 이들이 추가적인 고생을 하지 않도록 함과 동시에 왜 이런 코드가 나오게 되었나를 알려주고 있습니다. 이런 내용이 바로 코드에 대한 insight 또는 배경 지식입니다. 또 다른 예를 봅시다.

위 주석은 어떠한가요? 만약 위 주석이 없다면, 해당 코드를 보는 사람은 몇몇 단어가 놓쳐지는 것을 발견하고 버그라 생각할 것입니다. 그리고는 본 프로그램을 작성했던 이가 고생해서 내린 100%는 힘들다는 사실을 다시 발견하게 되겠죠. 어마어마한 시간을 허비해서. 그러나 위와 같이 주석을 처리함으로 인해서, 해당 코드에 담긴 생각을 전달이 되고, 이로 인해서 비효율적인 동일 작업 반복을 막을 수 있게 됩니다. 이러한 좋은 주석(담을 것을 담은 주석)의 다른 예를 봅시다.

위 주석은 마치 유서와 같지요. 문제가 되는 부분과 이에 대해서 어떻게 하면 좋겠다는 가이드까지 주고 있습니다. 즉 후임자에게 코드로 못 다한 이야기를 전달하고 있는 것입니다. 이러한 주석이 있음으로 인해서 코드를 유지보수를 수행하는 이는 용감하게 작업을 시작할 수 있겠지요. 이러한 측면으로서 후속 작업을 위한 주석들을 잠시 보겠습니다.

위 주석들은 자신이 못 한 부분에 대해서 이야기를 해주면서, 고쳐야 할 부분에 대해서 이야기를 전달해 주고 있습니다. 이렇게 주석을 남기는 것에 대해서 부끄러워 하지 말고 과감히 적으세요. 이것은 절대 창피한 행동이 아닙니다. 우리 모두는 주어진 상황에서 최선을 다하는 사람들이잖아요. 그런데, 주어진 상황은 항상 제약이 있습니다. 그렇기에 미진한 부분이 당연히 있습니다. 중요한 것을 이를 감추지 아니하고, 다른 프로그래머 혹은 시간이 지난 뒤 자신에게 해당 부분에 대해서 가이드를 전달해 주는 것입니다. 이런 주석 많이 많이 달아둘수록 프로그램은 견고해져 가는 것 입니다.

이처럼 코드 작성자의 생각을 담는 행동 중에서 아예 따로 분류되어서 이야기 될 수 있는 부분이 있습니다. 바로

Page 21: The Art Of Readable Code.

상수에 대한 주석입니다. 아래 예를 봅시다. 흔히 쓰이는 상수이죠.

위 코드를 보면 어떤 생각이 드나요? 만약 해당 코드 값을 수정해야 하는 상황이 발생되면, 어떤 생각이 머리 속에 들까요? 바로 왜 8 일까 입니다. 대부분 상수들은 재미나게도 각자 값이 정해진 배경이 있는 경우들이 많습니다.

이 코드가 아래와 같이 되어 있다면, 어떨지 봐봅시다.

위와 같이 주석이 되어 있으면, NUM_THREADS 라는 상수 값을 조정할 때, 어떻게 나온 값을 알게 되니, 불안감 또는 고민 없이 작업을 할 수 있겠지요. 이러한 예에 대해서 추가적으로 더 봅시다.

위 예를 보면 알겠지만, 위와 같은 주석이 달아짐으로 인해서 후속자들은 엄청난 시간을 절약을 할 수 있습니다.

더 나아가서는 잘 못 된 값으로 값을 변경함으로 인해서 발생될 수 있는 장애도 방지가 가능합니다. 물론 모든 상수가 주석 처리될 필요가 있지는 않습니다. 예를 들어서 SECONDS_PER_DAY 라는 상수가 있다면, 이 값에 대해서 주석을 다는 것은 의미가 전혀 없을 것입니다.

중요한 것은 전달되어야 할 이야기들을 주석으로 쓰는 것입니다. 그 외에는 쓰지 마세요. ^^

Put Yourself in the Reader’s Shoes

주석을 작성하는 가장 기본 자세는 바로, 해당 코드에 대해서 처음 접할 사람들이 코드를 읽으면서 뭔가를 생각하게 될 부분을 찾는 것입니다. 바로 해당 부분들이 주석이 필요한 곳들 입니다. 바로 예를 보면서 생각해 봅시다.

위 코드에서 볼드 처리된 부분을 보면 의문이 들지 않나요? 왜 clear 인데 swap 을 할까? 이런 의문이 드는 바로 그 부분이 주석이 필요한 부분입니다. 이 부분에 바로 아래와 같이 주석을 해 두면 코드 읽는 이는 바로 주석을 보면서, 자연스럽게 의문 없이 코드를 읽게 되겠지요.

이렇게 어떤 의문이 들만한 부분에 대해서 주석을 달았다 하면, 이번에는 뭔가 일상적이지 않은 부분에 대해서 생각을 해봅시다. 이야기를 해주지 않으면 뭔가 잘 못 쓰일 수 있는 부분에 대해서 주석을 하는 것이지요. 아래 함수를 예로 생각합시다.

위 함수만 딱 봐서는 아무런 생각 없이 이메일 보내는데 해당 함수를 쓰겠지요. 근데 만약 일반적은 이메일 보내는

Page 22: The Art Of Readable Code.

함수와 달리 위 함수는 내부 이메일 서버가 아닌 외부 이메일 서버와 연계가 되어서, 경우에 따라서 메일 보내는데, 몇 분이 걸릴 수도 또는 그 이상이 걸릴 수도 있을 수 있고, 이를 방지하기 위해서 1 분 지나면 timeout

처리 한다고 생각해봅시다. 이러한 경우에 반드시 주석을 써 주어야 합니다.

주석이 없다면, 해당 함수에 대해서 다량 호출했는데, 지연이 된다면 치명적인 결과를 초래할 수 있겠죠. 이를 방지하기 위해서 이상적으로는 함수 이름에 그 내용을 포함시키면 좋겠는데, 그건 함수 이름에 포함시키기는 부수적인 내용이니 아래와 같이 주석을 달아봅시다.

이렇게 주석이 달아져 있으면, 해당 코드를 보는 사람은 주의해서 혹시나 빠질 수 있는 위험 상황을 대처하거나 위 코드를 개선하겠지요. 이러한 이상 상황에 대한 주석의 또 다른 예로 아래와 같이 주석을 달아두는 것도 좋은 주석이라 할 것입니다.

지금까지는 함수 레벨 측면에서 주석에 대해서, 많이 생각해 보았습니다. 그런데 어떤 코드를 이해할 때에는 전체적인 그림 이른바 big picture 에 대한 묘사가 필요한 경우가 많습니다. 어떠한 내용이 그런 내용일지에 대해서는 현재까지 작성된 코드를 신규 사원에게 이야기를 할 때, 전달하는 내용들이라고 생각하시면 됩니다.

예를 들어서 “이 클래스는 어떤 클래스와 같이 동작을 하고, 이 코드들은 비즈니스 로직과 데이터베이스를 연계하는 코드로서 절대 다른 곳에서는 직접적으로 본 코드가 사용되면 안되고…” 이러한 이야기들이 바로 big

picture 에 대한 이야기 이며, 우리는 이 내용을 반드시 주석으로 코드에 적어두어야 합니다. 이러한 예로 아래와 같은 주석이 있을 수 있습니다.

물론 이렇게 작성할 때, 너무 잘 쓰려고 부담은 가지지 마세요. 큰 그림에 대해서 이야기 해주는 것 자체가 훨씬 중요하니깐요.

그리고 이게 클래스나 파일 단위에 대해서 국한된 이야기는 아닙니다. 큰 그림에 대해서, 이야기가 필요한 경우에는 언제나 가볍게 큰 그림을 설명해서 아래 내용 이해를 쉽게 해주자는 것이 핵심입니다. 이러한 예로 아래 코드 같은 경우를 생각할 수 있습니다.

루프 내부 내용을 다 보면 알겠지요. 그렇지만, 위에 떡하니 큰 그림에 대해서 주석을 달아주니 세부적인 코드 내용을 보지 않고도 이해하기가 참 좋겠지요. 이런 게 바로 큰 그림을 보여주는 주석입니다. 이런 유사한 주석으로는 전체적인 논리 묶음에 대한 주석입니다. 이 부분은 메소드로 분리 처리하는 방법도 하나이지만,

그렇지 못 한 경우에도 아래와 같이 주석을 써주면 읽는 이는 읽기 편하겠지요. 이게 바로 좋은 주석입니다.

Page 23: The Art Of Readable Code.

지금까지 주석을 작성하는 부분에 대해서 알아보았습니다. 그런데 무엇보다 중요한 것은 코드 주석 쓰는 것을 두려워하지 않는 것입니다. 예쁘게 주석을 쓰는 것이 아니니, 내가 코드를 작성하면서 생각한 내용을 코드와 함께 적어둔다는 마음으로 우선 적으세요. 그리고 마무리를 하면서 과한지 정리가 필요한지를 확인하고 적절히 지우거나 고치도록 합니다. 주석 자체에 대한 부담감으로 주석을 두려워하지는 말아야 함을 다시 이야기 드립니다. 그리고 언제나 그렇듯 코드를 읽는 입장에서 읽으면서, 읽기 좋게 만들도록 다듬는 마음이 제일 중요하죠 ^^

Summary

주석을 쓰는 것은 내가 프로그램을 짜면서, 알고 있는 내용인데, 코드로 표현되지 않는 내용을 적어서 코드를 읽는 이에게 전달될 내용을 전달하거나 이해하기 편하게 해주는 것입니다. 이를 위해서 간단한 가이드를 정리하면 다음과 같습니다.

주석 달지 말아야 할 것

코드 자체에서 바로 읽히는 내용 나열

잘못된 코드 이름을 보충하기 위한 주석. 주석 대신 이름을 수정

주석으로 표출되어야 할 것

코드가 이렇게 작성이 되게 된 insight 나 배경

코드에 대해서 수정되어야 할 부분이나 향후 진행될 부분

상수들은 해당 값들을 가지게 된 배경

읽는 이 입장에서 도움을 주기 위해서 추가해야 할 주석

코드 읽을 때, 뭔가 생각하게 될 부분에 대한 설명

일상적이지 않은 부분에 대한 주지를 위한 내용

전체적인 그림을 알려주어 이해를 편하게 해 줄 수 있는 내용

세부 내용을 아우르는 기능 묶음에 대한 요약 주석

이러한 주석에 선행하는 기본 원칙은 good code > bad code + good comments. 입니다. Good code 를 작성하고 코드에는 나타나지 않는 중요한 이야기들 또는 코드를 읽기 좋게 만들어주는 내용을 주석으로 보강해서 읽기 좋은 코드를 만들어 봅시다.

Page 24: The Art Of Readable Code.

Chapter 6. Making Comments Precise and Compact

앞서서는 어떤 항목을 주석을 달아야 하는가에 대해서 알아보았습니다. 이제는 어떤 내용을 주석으로 써야 하는 지를 넘어서, 어떻게 쓰면 좀 더 읽기 좋을까라는 생각을 해봅니다.

우선 기본은 주석도 읽어야 하는 내용 중 하나이기 때문에 정보를 최소화를 해서 표시하도록 해야 합니다. 그리고 최소화를 하면서도, 사용자가 바로 이해하기 좋도록 해주면 좋겠지요. 이러한 측면을 예제를 통해서 보여주는 것이 더 나을 것입니다. 간단한 예를 생각해 보면 아래와 같습니다.

// int 는 CategoryType 이다.

// 내부 pair 의 첫번째 float 는 score 이다. 그리고 두 번째는 Weight 이다.Typedef hash_map<int, pair<float, float>> ScoreMap;

일상적인 주석이지 않는가? 그런데 나름 예를 활용하면, 다음과 같이 작성할 수도 있다.

// 항목: CategoryType, <score, weight>Typedef hash_map<int, pair<float, float>> ScoreMap;

경우에 따라서는 아래 항목이 더 이해하기 힘들 수도 있다. 그렇다면, 오히려 위의 주석을 써야 할 것이다. 우리가 주석을 쓰는 이유는 좀 더 쉽게 코드를 읽을 수 있도록 하기 위함이기 때문입니다. 그런데 여기서 이야기 하고자 했던 것은 바로 예제를 적절히 활용하면 백마디 말보다 명확히 의미 전달을 할 수 있다는 사실입니다.

주석을 어떻게 쓰는가에 대해서 보고 있지만, 주석은 말 그대로 이해를 돕기 위한 첨언이기 때문에, 글을 잘 써야 한다는 기본 전제에서 벗어나지 않습니다. 잘 쓴 글은 간략하면서도 명쾌하게 의미를 전달하는 것입니다. 이런 측면에서 다음과 같은 문장들을 보고, 이를 이렇게 쓰면 더 낫지 않을까라는 의미에서 몇몇 경우를 살펴 보도록 합니다.

모호한 지칭은 피하자

나쁜 예: 데이터를 캐쉬에 넣기 전에, 그것이 크기가 적당한 먼저 확인합니다.

좋은 예: 데티터를 캐쉬에 넣기 전에, 데이터가 캐쉬 크기보다 작은지 확인합니다.

이해하기 어렵다면, 쉽게 써라.

나쁜 예: 이 URL 을 이미 방문했는지에 따라서 다른 우선 순위를 부여한다.

좋은 예: 전에 방문하지 않은 URL 에 우선순위를 부여합니다.

불확실한 부분은 구체적으로 작성하자.

나쁜 예: 이 파일에 담긴 줄 수를 반환합니다.

좋은 예: 파일 안에 새 줄을 나타내는 \n 개수를 세어서 반환합니다.

이렇게 주석은 작성한 뒤에 읽어보고, 명확하게 그리고 이해하기 좋은 문장을 노력하는 것이 가장 중요합니다.

나쁜 문장 하나하나를 모두 보여줄 수는 없기 때문입니다. 그래도, 간단한 팁을 드리면 현실적이 도움이 될 수 있을 것 같아서 팁을 알려드립니다.

코드 자체에 대한 설명이 아닌 의도를 설명합니다.

producst.sort(CompareProductByPrice);for(list<Product>::reverse_iterator it = products.rbegin(); it != products.rend(); ++it)

Page 25: The Art Of Readable Code.

{ DisplayPrice(it -> Price); ……}

위 코드에 대해서, “가격으로 정리된 리스트를 역순으로 돌면서 가격을 표시합니다.”와 같이 코드를 읽어서 주석을 달기 보다는, “가격을 높은 값에서 낮은 값 순으로 표시를 합니다.”라고 코드에 대한 의도를 설명하는 것이 좋습니다.

경우 따라서는 파라미터에 주석을 해주는 것도 바람직하다.

Connect(10, false, 5);

위 함수에 대해서 primitive 유형이 너무 많은 경우에 전달하는 파라미터 값이 어떤 의미인지 코드를 읽을 때 알아내야 하는 경우가 있습니다. 이 때 다음과 같이 주석을 활용하면 좀 더 이해하기 좋습니다. 물론 프로그램 언어 자체에서 변수 이름을 지정해서, 호출도 가능합니다.

그렇지 않은 경우 아래와 같이 해보는 것을 팁으로 드립니다.

Connect( /* timeout_ms= */ 10, /* use_encryption= */ false, /* max_retry_times= */ 5);

도메인에 대한 정보를 아는 경우에는 도메인 용어를 사용하는 것도 좋다.

프로그램 개발을 하는 경우에 캐시라는 개념을 대부분이 알고 있다고 가정을 할 수 있습니다.

그렇다면, 만약 캐쉬에 대해서 풀어서 길게 설명하기 보다는 해당 기능이 캐쉬 기능을 한다고라고 짧고 명확하게 전달이 가능합니다.

캐쉬라는 단어를 사용하지 않으면 이렇게 까지 쓸 수 있습니다. ^^;;

이 클래스는 데이터베이스와 동일한 정보를 담는 멤버를 가지고 있는데, 이는 속도를 향상시키는데 사용된다. 나중에 이 클래스가 읽히면, 멤버 변수가 값을 가졌는지를 확인하고,

만약 값이 있으면 그 값을 반환한다. 값이 없으면 데이터베이스에서 값이 읽혀져서 전달하는 동시에, 나중에 이용될 수 있게 멤버에 값을 저장한다.

이렇게 쓰기 보다는 “이 클래스는 데이터베이스에 대한 캐시 계층으로 기능한다.”라고 명료하고 짧게 전달이 가능합니다.

예제를 적극 활용합시다.

어떤 함수가 동작을 하는가에 대해서 설명을 하기 보다는, 적절한 예를 통해서 설명을 해주는 것이 좋습니다. 이에 대한 예는 고민이 될 수 있는 경우들을 하나하나 선별해서 보여주는 것이 좋습니다.

선별하는 기준은 사용자가 어떻게 동작하는지 애매하게 느낄 부분들 들입니다. 예를 들면 다음과 같습니다.

“unhappy”.substring(2) = “happy”“unhappy”.substring(7) = “”

이렇게 간단히 가이드를 드렸지만, 이러한 몇가지 팁에 담긴 기본이 되는 마음. 읽는 이가 편하게 읽을 수 있도록 주석을 필요한 부분을 짧고도 명확하게 전달한다는 마음을 항상 가지고 주석을 쓰도록 합시다.