쉬운 코드가 장땡인가
프로그래밍을 시작한 지 얼마 안되었을 때에는 어려워 보이는 코드가 멋있어 보였습니다. 그러다가 색다른 충격을 몇 번 받고는 쉬워 보이는 코드가 멋있어 보이더군요. 지금은 단순히 쉬워 보인다, 어려워 보인다라는 일차원적 평가가 위험하다는 생각을 하고 있습니다. 그 이야기를 좀 해볼까 합니다. (기우에서 말씀드리면, 제가 제시하는 모형도 단순화한 것이기에 절대적으로 받아들이기에는 위험성이 있다는 점을 염두에 두시면 좋겠습니다)

다음 도표를 보시죠. 여기에서 E는 쉽다, D는 어렵다를 말합니다. 또, 처음 접했을 때 얼마나 쉬운지, 또 시간이 지난 후(일정한 노력을 기울인 후)에 얼마나 쉬운지를 구분하여 행에 처음 접한 난이도, 열에 나중에 느끼는 난이도를 표시했습니다. 이때 쉽다 어렵다는 것은 상대적인 것이며 코드를 읽는 사람(혹은 관리할 사람)을 기준으로 합니다.




       ~로

~에서
ED
E(1)(2)
D(3)(4)


(1) 이런 간단한 방법이 있었다니!

(1)은 처음 봤을 때도 쉬워 보이고, 시간이 지난 후에도 여전히 쉬워 보이는 코드입니다. 제가 앞에서 말한 "색다른 충격"이 이 경우였습니다. 주로 스몰토크 문화 배경을 가진 사람들의 코드가 이렇더군요. 내가 애초에 이런 코드를 생각 못했다는 것이 멍청하게 느껴지게 만드는 코드입니다. 간결하고, 투명합니다.


(2) 앗, 속았다!

(2)는 처음에는 쉬워 보였지만, 시간이 지나보니 사실은 어려운 코드입니다.

어설프게 자연언어를 모방하려고 한 코드(사실 자연언어는 오해를 많이 발생할 소지가 있는 위험한 언어입니다)가 그렇습니다. 스파게티를 깔끔한 포장지로 치장한 것에 비유할 수 있습니다. 코드를 처음에 보면, 어라! 줄줄 읽힙니다. 나름대로 머리속에 모형을 만들게 되죠(mental model). 하지만 이 모형이 실제 모형과 거리가 있습니다. 실제는 그렇게 단순하거나 아름답지 않을 수 있거든요. 조금만 예외적인 경우를 다루려고 해도 이 머리속 모형을 포기해야 합니다. 또 내부적으로 제대로 이해를 못하고 표면적으로만 흉내를 내다 보면 오해도 생기고 실수도 하게 됩니다. 코드의 행동을 정확하게 예측하기가 힘듭니다.

더 깊은 소스 코드를 자주 들여다 봐야 하고, 레퍼런스나 메뉴얼을 자주 참조해야 합니다.

부분적으로는 이해하기 쉽지만 전체적으로는 이해하기 어려운 코드도 여기에 속합니다. 여기저기 간단해 보이는 로직을 복사/붙여넣기한 코드도 그렇습니다. 일견 쉬워보입니다. 하지만 그런 코드 속에서 한 달 정도만 살다보면 악몽을 꾸기 시작합니다.


(3) 아, 알겠다!

(3)은 처음에는 어려워 보이지만 나중에는 쉬워 보이는 코드입니다.

생소한 개념들 때문에 처음에는 낯설고 어려워 보이지만, 몇 가지 핵심적 개념을 이해하면 어느 순간, 따악! 죽비 맞고 네오가 메트릭스에서 득도하여 만물을 꿰뚫어보는 듯한 경지에 달할 수 있는 코드입니다. 시간이 가면서 눈이 점점 트이고 전체 "와꾸"가 확하고 와닿는 코드입니다.

새롭고 유용한 추상적 개념을 사용한 코드, 개념적 일관성과 개념의 시스템이 있는 코드가 그렇습니다. square(제곱), root(제곱근), cube(세제곱) 등의 개별적 개념들을 따로 익히는 것은 일견 쉬울 수 있습니다. 반대로 power(거듭제곱)를 익히는 데에는 시간이 더 걸릴 수 있겠죠. 하지만 일단 power라는 개념을 알게 되면 기존의 square, root, cube들이 하나로 확 관통이 될 뿐 아니라, 실수, 허수 거듭제곱까지도 쓰임을 연장할 수 있습니다.

이 코드를 이해하면 스스로 좀 더 똑똑해졌다고 느끼고, 또 그 느낌이 지속됩니다.

이런 코드의 초기 학습 속도를 높이기 위해서는 트레이닝이나, 멘토링, 개념적 문서 등이 제공되면 도움이 되긴 하지만 원래의 필요 학습량 자체를 줄이는 것은 무척 어렵습니다. 기본적으로 "나"(혹은 나의 뇌)의 변화를 요구하기 때문입니다.


(4) 예나 지금이나 어려워

(4)는 처음에도 어렵고 시간이 지나도 계속 어려운 코드입니다.

복잡도가 지나치게 높고 추상화도 안 된 코드입니다. 이런 코드는 익숙해지기가 무척 어렵습니다. 좀 익숙해졌다 싶어도 하루 지나면 다 까먹습니다.

시간이 지나면서 계속 덧대기 작업을 한 코드가 이렇게 되기 쉽습니다. if문이 여러겹이라 한 1시간 걸려 코드 읽고는 if문 하나 새로 추가합니다. 전역변수 사용도 많아서 도무지 전체 그림을 한 사람의 뇌 위에 올려놓을 수가 없습니다.


우리가 지향해야 할 코드는

저는 우리가 (1)번과 (3)번 영역의 코드를 지향하는 것이 바람직하다고 생각합니다. 1번만 추구하려는 사람은 쉬운 코드가 장땡이라고 생각하는 경우인데, 이것은 우리 스스로를 발전시킬 기회를 놓치는 것이라고 봅니다. 3번을 같이 추구할 때 우리 스스로 더 똑똑해지고, 더 속도를 낼 수 있다고 생각합니다. 또 2번을 추구하는 사람(대개 자신이 2번을 추구한다고 생각하지는 않는데, 의심해 볼 필요가 있음)은 1번이나 3번의 대안이 가능한가를 생각해 보는 것도 유익하다고 생각합니다.

마지막으로 한 마디만 더 달자면, 2번과 4번 영역도 경우에 따라 쓸모가 있다고 생각합니다. 어쩔 수 없는 선택일 경우도 있고요(이 경우, 시스템의 한정적인 부분에서 의식적으로 사용하고 영향이 퍼지지 않게 관리, 제어하는 것이 필요합니다). 하지만 1번이나 3번의 존재를 의식하고, 그쪽을 모색하고 실험하고 또 거기로 가려고 노력하는 자세가 필요하다고 생각합니다.

p.s. 이 글은 코드뿐만 아니라 언어, 혹은 쉽고 어렵고가 내 선택의 중요한 기준 중 하나가 되는 그 밖의 것들에도 적용 가능합니다

--김창준
by 애자일컨설팅 | 2009/07/01 01:35 | 트랙백(4) | 덧글(18)
트랙백 주소 : http://agile.egloos.com/tb/5026291
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Tracked from ptec's me2DAY at 2009/07/01 09:45

제목 : 그린의 생각
코드에 대한 새로운 생각들… 쉬운코드가 항상 좋지는 않은가 보다. 궁극적으로는 1번을 바라지만…...more

Tracked from imays: 게임엔진 .. at 2009/07/01 10:18

제목 : 서적 Code Reading에 대한 한줄 평
그래설라무네, 당신이 어떤 복잡한 코드를 잘 분석했다면, 그것은 당신이 코드를 잘 읽은게 아니라 그 코드를 짠 사람이 잘 짰기 때문이다....more

Tracked from wowzzangga's.. at 2009/07/01 13:07

제목 : 빙그레씨의 생각
나도 쉬운코드를 만들고 싶은데 왜 자꾸만 스파게티코드가 되는걸까나...more

Tracked from 외모로 버텨온 나날들.. at 2009/07/20 13:10

제목 : 쉬운 코드가 장땡인가
프로그래밍을 시작한 지 얼마 안되었을 때에는 어려워 보이는 코드가 멋있어 보였습니다. 그러다가 색다른 충격을 몇 번 받고는 쉬워 보이는 코드가 멋있어 보이더군요. 지금은 단순히 쉬워 보인다, 어려워 보인다라는 일차원적 평가가 위험하다는 생각을 하고 있습니다. 그 이야기를 좀 해볼까 합니다. (기우에서 말씀드리면, 제가 제시하는 모형도 단순화한 것이기에 절대적으로 받아들이기에는 위험성이 있다는 점을 염두에 두시면 좋겠습니다) 다음 도표를 보시죠.......more

Commented by 개똥이 at 2009/07/01 08:06
흠... 1번과 3번을 지향해야겠지만 바쁘게 코딩하다보니 잘 지키기가 힘들네요 ㅋㅋ 점점 미궁속으로 빠져든다는... ^^*
Commented by binggre at 2009/07/01 09:13
3번과 같은 코드를 작성하고 싶다면 어떤 노력이 필요할까요?
개인적으로 3번을 지향하고 있지만 왠지 2번으로 빠져드는것 같은 느낌이 듭니다.
그래서 디자인패턴도 공부해보고 있지만 실질적으로 적용하는데는 어렵네요+ㅅ+
Commented at 2009/07/01 09:20
비공개 덧글입니다.
Commented by 애자일컨설팅 at 2009/07/01 10:49
감사합니다.
Commented by popopome at 2009/07/01 10:31
4->1
4->3
2->1
2->3
으로 갈 수가 없나요?
리팩토링과 디자인패턴을 가지고 만들 수 있나요?
아니면 아예 한번 잘못 만들어봤다고 하고 처음부터 다시 시작하는게 빠른 가요?
아니면 원천적으로 불가한가요?
Commented by 애자일컨설팅 at 2009/07/01 10:51
리팩토링 유용하죠.

1과 3은 시스템적 일관성이 있습니다. 기존 레거시 시스템 전체를 그렇게 옮겨가는 것은 많은 노력이 들어갑니다. 하지만 오래도록 관리해야할 시스템이라면 그렇게 하는 것이 이득일 경우도 있겠죠. 시스템 전체를 어떻게 옮겨가느냐 하는 것과는 별개로 부분적으로 1, 3으로 옮겨가는 것은 늘 좋다고 봅니다.
Commented by snaiper at 2009/07/01 11:21
1,3 번 코드의 예 같은거 볼 수 있을까요? 아 이거다 이런거...궁금해집니다 ^^
Commented by 영록 at 2009/07/01 13:17
전반적인 느낌에는 공감하지만 실제 코드 예시가 있었다면 좀더 확확 와닿았을 것 같습니다.
Commented by 애자일컨설팅 at 2009/07/03 01:05
맞습니다. 그런데, 제가 글에서 밝혔듯이 어렵다 쉽다는 기준이 다 개인적인 것이기 때문에 일반적인 예를 들기가 쉽지 않더군요.

제 개인적으로는 워드 커닝햄의 코드들이 주로 1, 3번인 것 같습니다. 2번은 Method Chaining을 통한 Fluent Interface 흉내낸 코드들에서 좀 봤고, 심하게 동적인 언어들에서 "아름다운 EDSL"만든 경우에도 좀 봤던 것 같습니다. 수 년 전이긴 한데 Io 언어의 구현도 무척 인상적인 3번이었습니다. 메타 모델만 이해하면 굉장히 명료하죠.
Commented by 개멍 at 2009/07/01 14:23
마침 오늘 읽은 *좋은* 글이 있어서요.
http://freeworld.thc.org/root/phun/unmaintain.html
:-)
Commented by kj at 2009/07/02 16:13
개명님 감사합니다. 너무 환상적인 글이었습니다. ㅎ
Commented by daybreaker at 2009/07/02 21:38
Django가 1번이었으면 좋겠지만, 사실 2번에 가까운 느낌이 조금 나기도 합니다. -_-;;; 다행히 mental model까지 뒤집어야 하는 건 아니고 공식 문서보다 코드에 달린 주석이 더 가치있는 경우가 많아서 결국 코드를 뒤져볼 수밖에 없다는 점에서요.
그래도 1번/3번과 같은 코드를 짜려고 노력해야겠죠? Python이 잘만 쓰면 그렇게 하기는 꽤 괜찮은 언어 같아요. :)
Commented by 애자일컨설팅 at 2009/07/03 01:08
네. 1, 2, 3, 4번이 이산적이지는 않겠죠. 연속적이라고 생각합니다만, 앞에서 밝혔듯이 단순화한 모델이죠.

Python은 언어적, 문화적으로 봤을 때에 Easy를 가치있게 여기는 것 같아서 좋아합니다.
Commented by CharSyam at 2009/07/04 02:39
1,3을 구분할 때, 언어 자체의 개념은 빼고 생각해야 되지 않을까요?

언어 자체를 모르는 사람이 봐도 1이 있을 수 있지만, 전혀 모르는 언어에 접근한다면, 보통은, 2,3이겠죠.

여기서의 쉽다, 어렵다의 개념은, 언어적인 특성은 다 같이 이해하고 있을 때, 쉬우냐? 어려우냐?(이것도 지극히

주관적이지만) 를 생각해야 할것 같습니다.

저는 언제나 1이 옳다고 생각합니다. 아니면, 학습해야 할 포인트를 알려줄 경우의 3이나요.

그러나 제 코드는 언제나, 4가 되어버리는군요
Commented by 애자일컨설팅 at 2009/07/04 16:24
언어랑 코드랑 비교적 직교적으로 생각할 수 있습니다. 그리고 여기서 어렵다 쉽다는 제가 앞에 이야기 했듯이 상대적이고 주관적인 척도입니다.

언제나 1이 옳다고 생각하시나요? 좋은 태도라고 생각합니다. 하지만 그 태도가 자칫하면 어려워 보이는 것은 무조건 나쁘다라는 잘못된 함정에 빠지게 할 수 있습니다.

예를 들어 정수론의 법칙이나 고급 미적분 개념을 사용한 코드가 있다고 칩시다. 많은 사람에게는 이 코드가 3 영역에 속할 겁니다. 반대로 그런 고급 이론을 안쓰고 무식하게(brute-force) 혹은 직접적으로 표현된 코드가 있다고 칩시다. 많은 경우 전자의 코드가 훨씬 짧을 것입니다. 저는 이런 코드의 유용성(즉, 우리를 한단계 더 똑똑하게 만들어주는)을 이야기하는 것입니다.

1부터 N까지 더한다고 할 때, 실제로 1+2+3...+N하는 방법도 있지만 N*(N+1)/2하는 방법도 있겠죠. 2!(N/2)할 수도 있고요. 저는 더 고차원적인 해결법들의 가치도 보자는 것이죠.
Commented by 달룟 at 2009/07/05 12:01
쉽다라는 것은 대단히 주관적인 것이기때문에... 물론 가독성이란 개념도 있긴하지만...
한국사람에겐 일본어가 쉽게 습득할 수 있는 언어이지만, 미국사람한테는 A 급 난이도죠...

사람마다 머리속을 관리하는 스타일도 다르고, 의사결정을 하는 스타일도 다른만큼, 쉬운 언어, 쉬운 코드라는 것이 제각각일 수 있습니다.

장황한 설명을 좋아하는 사람이 많지 않다고 한다면, 짧은 코드가 대체적으로(혹은 근사적으로) 쉬운 코드가 될 수 있겠습니다.
Commented by 영록 at 2009/07/05 17:47
마침 최근에 했던 계산기 알고리즘이 떠오르네요. 계산기 알고리즘은 단순 무식하게 recursion만 돌려서 해결할 수도 있고, operator, operand stack을 만들어서 풀 수도 있습니다. 그리고 BNF 표기법을 이용한 파서를 만들거나, 파서 제너레이터를 쓸 수도 있습니다. 물론 전부 eval 같은 함수가 없는 언어의 경우입니다.

뭐가 제일 쉬운 방법일까요? 코딩하기는 아마 recursion이 가장 쉬울 것입니다. 나온 코드도 가장 짧고 쉽습니다. 이것도 recursion은 알아야 하지만 그것만 알면 단순하죠. 개념도 명쾌하고 구현하기도 쉽습니다. 원문의 1번에 해당하는 방법일 겁니다. 하지만 이 방법은 무식합니다. 수식 문자열을 recursion 과정에서 여러 번 스캔해야 하거든요. 속도도 느리기 때문에 실전에서는 쓰이지 않습니다.

계산기 문제의 정답은 stack을 이용하는 것입니다. 이 방법은 첫번째보다 훨씬 복잡합니다. postfix 연산법의 개념을 모르면 코드를 보고 왜 이 코드가 말이 되는지 이해하기 어렵습니다. 하지만 postfix 연산법을 이해하고 나면 코드는 전혀 어렵지 않습니다. 정해진 알고리즘을 구현하는 것 뿐이니까요. 첫번째 방법보다 좀더 3번스러운 방법입니다.

더 3번스러운 방법은 문법 정의를 파싱하는 파서를 만드는 것입니다. 원리를 모르고 파서의 코드를 이해하는 것은 불가능합니다. 그렇지만 파서를 알고 나면 코드는 쉽게 보입니다. 요구사항에 복잡한 문법이 더 추가되면 어떨까요? stack을 이용한 방법은 우선순위가 다른 연산자의 종류가 늘어날수록 코드가 감당이 안됩니다. 하지만 파서를 만들어두면 쉽게 문법을 추가할 수 있습니다. 게다가 더 좋은 것은 이런 과정을 한 번 거치면 그 다음부터는 interpreter pattern을 자유자재로 쓸 수 있게 됩니다. 내가 더 똑똑해지는 것이죠.

XP에서 이야기하는 시스템 메타포도 비슷한 예가 될 수 있을 것 같습니다. SOAP을 그냥 보면 대체 왜 이런 복잡한 것에 Simple이라는 수식어를 붙였지? 하는 생각이 들 수도 있지만 우편 시스템의 메타포를 적용하고 있다는 점을 이해하면 한결 쉬운 느낌으로 다가올 수 있을 겁니다.(물론 SOAP은 조금 더 간단해질 수 있다고 봅니다만)
Commented by YH at 2009/07/07 16:31
글을 읽고 보니, TDD 강의 하셨을 때,
김창준님께서 상태머신을 예를 들어 설명하셨던 프로그래밍 관념과 유사하네요.^^ (2개의 상태와 4개의 트랜지션)
'안되는 것에서 되게하고, 항상 되는 것에서 계속 되게하라'

:         :

:

비공개 덧글

< 이전페이지 다음페이지 >


Site Meter