IT 이야기2009. 3. 11. 02:35


대부분의 프로그램은 한번에 작성되지 않는다. 프로그램들은 그 수명주기 동안 계속해서 개정되고 재 작성된다. 요구사항의 변화와 기능성의 개선 필요성 때문에 프로그램은 계속해서 수정되어야 한다. 이러한 과정에서 반드시 인간이 원래의 코드를 읽고 이해할 수 있어야 한다. 따라서 컴퓨터가 프로그램을 이해할 수 잇는가 보다 인간이 프로그램을 이해 할수 있는가가 훨씬 중요하다.

물론 컴퓨터는 복잡성을 불평없이 다룰 수 있다. 그러나 사람은 그렇지 못하다. 무어의 법칙에 따르면 컴퓨터 칩의 집적도는 18개월마다 2배씩 향상되어 2배의 복잡함을 처리할 수 있지만(보통 알려져 있는 것과 달리 무어는 클럭 스피드가 아니라 칩의 집적도와 복잡함에 대해 말한 것이다. ) 인간은 18년이 지나도 2배의 복잡도를 가진 문제에 적응할 수 없다. 그리고 이러한 읽기 어려운 코드는 사람의 생산성을 크게 훼손시키기 마련이다. 반면 쉽게 이해할 수 있는 코드는 생산성을 높여준다. 그리고 우리는 그러한 코드에서 미를 발견한다.

컴퓨터 프로그램을 읽기 쉽게 만드는 요인은 무엇인가? 다시 말해서, 무엇이 아름다운 코드인가? 아름다운 프로그램에 대한 기준은 사람마다 다르겠지만, 컴퓨터 코드의 특성을 판정한다는 것이 단순히 미학의 문제는 아니다. 컴퓨터 프로그램은 그것이 주어진 과제를 얼마나 잘 수행하는지에 따라 판정된다. 다른 말로 하면 아름다운 코드는 프로그래머의 노력과는 무관하게 존재하는 추상적인 미덕이 아니다. 아름다운 코드라면 프로그래머를 행복하게, 그리고 생산성을 높이는데 도움을 줄 수 있어야 한다.

아름다운 코드를 논할 때 다소 논쟁의 여지를 제공하는 측면으로는 익숙함이 있다. 사람들은 자신이 생각하는 것보다 보수적이다. 대부분의 사람들은 새로운 개념을 받아들이거나 사고방식을 바꾸기를 꺼려하며, 변화보다는 참고 견디는 것을 더 좋아하는 듯 하다. 익숙한 도구를 다른것으로 교체하거나 새로운 언어를 배우는 일을 특별한 이유없이 꺼리는 사람들도 많다. 사람들은 가능하면 자신이 항상 상식으로 가눚하던 것을 잣대로 해서 새로운 방법을 평가하는 경향이 있다. 그러다보니 새로운 방법을 부당하게 저평가 해버린다.

사고방식을 바꾸는 데 드는 비용은 흔히 생각하는 것보다 훨씬 높다. 완전히 다른 개념으로 전환(이를테면 절차적 프로그래밍에서 논리적 혹은 함수적 프로그래밍으로의 전환)을 용이하게 하려면 다양한 개념들에 정통할 필요가 있다. 가파른 학습곡선은 인간의 두뇌를 고통스럽게 만들고 결국 프로그래머의 생산성을 낮춘다.

아름다운 코드란 결국 간결하며 유연함과 효율성을 가짐과 동시에 보수성을 가진다. 그런데 그것들 자체로 아름다운 코드가 보장되지는 않는다. 그런 요소들 모두의 균형을 처음부터 염두에 두어야 각 요소가 다른 요소와 조화를 이루어서 아름다운 코드가 만들어 지는 것이다. 


컴퓨터가 아니라 사람에게 쉬운 코드를 작성해야 하는 걸 알았다면 이제 사람 누구에게 쉽다는 건지를 파악해보자? 쉽다라는 말 자체가 상대적인 판단을 의미하고 판단을 내리는 주체는 코드를 작성한 사람이 아니라 코드를 읽는 사람이다. (얼마의 시간이 지난후의 작성자도 한명의 독자가 될 수 있다. )

좀더 얘기를 하기전에 이쯤에서 잠깐 퀴즈를 하나 내보자 "어떤일을 하는데 있어서 가장 빠른 방법은 무엇일까?" 정답은 어떤 일을 하지 않는 것이다. 소프트웨어에서 가장 아름다운 코드, 가장 아름다운 함수, 그리고 가장 아름다운 프로그램은 바로 전혀 존재하지 않는 코드(또는 함수, 프로그램)라는 말이 있는 것처럼 가장 쉬운 코드는 존재하지 않는 코드이고 두번째로 쉬운 코드는 읽을 필요가 없는 코드이다.

단순히 스터디를 위해서 참조하는 경우를 제외하고 프로그래머가 다른 사람의 소스를 보는 이유는 
 - 사용방법을 몰라서
 - 해봤는데 기대하단 결과가 나오지 않아서(잘못 사용했거나 버그)
 - 인수 인계 등으로 프로그램을 이해하기 위해서
이다. 그렇다는 얘기는 프로그램이 잘 설계되어 있어서 사용방법이 쉽고 예측대로 작동된다면 굳이 함수나 클래스 내용을 뒤져볼 필요가 없다는 것을 뜻한다. 그래서 사실 읽기 쉬운 코드란 코드 그 자체의 대한 이야기라기 보단 좋은 설계에 대한 이야기이다.


"어려운 코드보다 단순한 코드가 더 좋다" 라는 말을 한번쯤 들어보았을 것이다. 번역되는 책마다 용어 선택의 차이 일수도 있고 아니면 우리 언어가 가지는 추상성의 문제일 수도 있지만 이 글에서는 쉽다와 간결하다를 구분하기로 하자. 쉽다는 어렵다(difficult)의 반대 용어로 사용하고 간결하다는 복잡하다(complicate)의 반대 용어이다. 그래서 쉬우면서 복잡하거나 쉬우면서 간결한 코드가 있을 수 있다.

물론 베스트는 쉬우면서 간결한 코드이고 최악은 어려우면서 복잡한 코드이다. 문제가 되는건 쉽지만 복잡한 코드일때와 어렵지만 간결한 코드일때 어느게 더 나을까 하는 점이다.

예컨데 프로그래밍은 상상이다등의 책에서 자주 언급되는

Case1 ) if else를 사용
if (conditon)
   one line code
else
   one line code

Case 2) 삼항연산자 사용
condition ? one line code : one line code

Case1은 쉽지만 복잡한 코드이고 Case2는 상대적으로 어렵지만 간결한 코드이다. Case 1의 지지자들은 삼항연산자가 잘 쓰이지 않는 연산자이기 때문에 앞에서 말한대로 코드를 읽는 사람을 배려해야 한다고 주장한다. 이 블로그 자체가 원칙을 논하는 블로그는 아니므로 옳다라고 하는 건 아니지만 개인적으로는 Case 2) 상대적으로 어렵지만 간결한 코드를 선호한다.

물론 코드는 읽는 사람을 배려해야 하는 사실을 인정하지 못하는 것은 아니다. 이유는 두가지가 있다.

첫째 어려운 것은 시간이 감에 따라 나아지지만 복잡한것은 그리 나아지지 않기 때문이다. 인간의 지적인 순수 능력은 수십년 전에 비하면 훨신 향상되었지만 여전히 7자리 넘는 숫자를 외우는 데에는 버거워 한다. 설사 읽는 사람이 삼항연산자를 몰랐더라도 아마도 시간이 지남에 따라 곧 적응이 될 테지만 읽는 사람이 몇년차 프로그래머인지에 상관없이 복잡한 프로그램은 여전히 복잡한 프로그램이다.


두번째 이유를 설명하기 전에 위 케이스는 익숙하긴 하지만 난이도 자체가 너무 쉬위므로 아래의 소스를 보자

Case A)
(function(){
  var alertFun = window.alert, c=0;
  window.alert=function(q){
   
    if (++c%4==0) { 
      if (!confirm(q+'\nThere have been '+c+' alert boxes, continue displaying them?')) window.alert=function(){};
    } else alertFun (q);
  }
})();

위 코드를 보고 한눈에 이해했다면 자바스크립트에 비교적 능숙한 프로그래머 일것이다. 위 코드는 웹 페이지의 무한 alert 핵을 막기위해 연속으로 alert 메소드가 호출될 경우 4번마다 한번씩 확인창을 띄어서 원하지 않을 경우 중단시킬 수 있도록 window.alert을 재정의한 코드이다. 자바스크립트의 함수형 언어의 특징과 클로저가 사용되서 어려워진 위의 코드를 쉽게 사용한다면

Case B)
var alertFun = window.alert,c = 0 ;
window.alert = function() {
    if (++c%4==0) { 
      if (!confirm(q+'\nThere have been '+c+' alert boxes, continue displaying them?')) window.alert=function(){};
    } else alertFun (q);

와 같이 바꿀수도 있다. 자바스크립트를 거의 모른다 하더래도 어쨌거나 첫번째 코드에 비해 훨씬 더 이해하기 쉽다. 

이러한 선택이 주어진다면 나는 고민없이 CaseA를 택한다. 단순히 코드 자체만을 본다면 Case A의 코드가 더 어렵다. 하지만 나중에 문제가 생길확률은 B가 월등이 높다. Case B의 코드는 쉽기는 하지만 전역변수인 alertFun의 존재를 기억하고 있어야 하고 혹시 그것을 잊어버려서 다른 곳에서 동일 이름의 변수를 사용한다면 버그의 이유를 찾는데 더 오랜 시간이 걸리기 때문이다. CaseA의 코드는 어렵기는 하지만 다른 코드에 의존하는 것이 거의 없고 매우 간결하고 독립적이기 때문에 문제를 일으킬 소지가 낮아서 애초에 Case A의 소스를 봐야 할 확률이 낮다. (가장 좋은 코드는 존재하지 않는 코드라는 것을 기억하자.)

사실 코드를 읽는 사람의 수준을 고려해 쉽지만 복잡한 코드를 작성하는 것보다 - 쉬운 코드라는 것은 작성자의 입장에서는 아무런 상관이 없는 말이고 - 쉬운 코드를 버리는 대신 복잡한걸 간결하게만 만들 수만 있다면  어렵더라도 애초에 코드를 읽을 필요가 없게 작성해주는 것이 더 좋다. 


정말 아이슈타인이 만들었는지는 모르지만

1. 다섯채의 각각 색깔이 다른 집이 있다.
2. 각 집에는 각각 다른 국적의 사람이 산다.
3. 주인들은 각각 다른 음료수를 마신다.
4. 다른 종류의 담배를 피고, 다른 종류의 동물을 기른다.
5. 영국인은 빨강색 집에 산다.
6. 스웨덴인은 개를 기른다.
7. 덴마크인은 홍차를 마신다.
8. 녹색 집은 흰색 집 왼쪽에 위치해 있다.
9. 녹색 집 사람은 커피를 마신다.
10. 풀몰 담배를 피우는 사람은 새를 기른다.
11. 노란색 집에 사는 사람은 던힐 담배를 피운다.
12. 한가운데 사는 사람은 우유를 마신다.
13. 노르웨이인은 첫번째 집에 산다.
14. 블랜드 담배를 피우는 사람은 고양이를 기르는 사람 옆집에 산다.
15. 말을 기르는 사람은 던힐 담배를 피우는 사람 옆집에 산다.
16. 블루매스터 담배를 피우는 사람은 맥주를 마신다.
17. 독일인은 프린스 담배를 피운다.
18. 노르웨이인은 파란색 집 옆집에 산다.
19. 블랜드 담배를 피우는 사람은 물을 마시는 사람 옆집에 산다.

그럼 여기서 금붕어를키우는사람은 누구일까요~
.. 라는 널리 알려진 퀴즈가 있다.

보통의 프로그래머라면 3-5분 이내에 풀수 있지만 중요한건 결코 프로그램을 이딴식으로 만들어서는 안된다는 것이다.

위의 명제들은 모두 단순하지만 서로 얽혀서 이를 이해하는데 종이와 연필이 필요하다.(만약 위 문제를 머리속으로만 풀었다면 멋지다.) 위 문제는 쉽지만 복잡하다. 만약 위의 각 명제가 하나의 함수라고 가정한다면 복잡한 구조때문에 함수 하나하나는 쉽지만 코드는 무척 이해하기 어려운 구조가 된다. 달리 말해서 코드나 알고리즘의 쉽다 어렵다 보다는 구조에 있어서의 간결한 구조가 훨씬 더 중요하고 만약 구조가 간결하다면 애초에 코드 레벨의 소스를 살펴봐야할 필요는 없을 것이다.





보통의 책에서 쉽다(가독성이 좋다)는 말에는 쉽다는 말과 간결하다는 중의적 의미를 내포하고 있고 단순히 쉽다=좋다는 것이 아니므로 좀더 구분해서 이해해야 한다. 





간결함에 대해 선배들은 다음과 같이 충고하였다. 펄리스의 말은 특히 훌룡하다.  



코드를 삭제함으로써 기능을 추가하도록 노력하라

설계자는 더 추가할 것이 없을때가 아니라 더 뺄것이 없을때 완벽함을 이루었음을 알게 된다. (생떽쥐페리)


강건한 문장은 간결하다, 필요없는 단어는 생략하라(스트렁크와 화이트)

가장 싸고 빠르고 신뢰할 수 있는 요소는 바로 존재하지 않는 요소이다. (벨)

더 적은 것으로 더 많은 것을 얻도록 노력하라

만일 시간이 더 주어졌다면 편지를 더 짧게 썼을 것입니다. (파스칼)

간결함은 복잡함보다 앞서지 않는다. 그 뒤에 오는 것이다(펄리스)

적을수록 많다(브라우닝)

모든 것을 최대한 간결하게, 그러나 너무 단순하지는 않게 만들라(아이슈타인)

종종 소프트웨어는 하나의 비누 거품으로 보아야 한다(펄리스)

간결함을 통해서 아름다움을 추구해라





# 무어의 법칙
Moore의 법칙은 잘못 인용되고 있는 것들 중 하나이다. 대부분의 전문가들은 컴퓨터는 18 개월마다 속도가 두 배로 증가한다고 주장하고 싶어한다. 사실 인텔 창립자 Gordon Moore는 1965년 컴포넌트 당 가장 싼 칩의 복잡함은 매년 두배로 증가했다는 것을 관찰했고, 이러한 트랜드는 약 10년간 지속될 것이라고 예견했다. 그런데 이것은 퍼포먼스가 두 배로 증가한다는 것을 의미하는 것은 아니다. 컴포넌트의 수가 그렇다는 것을 의미한다. Moore의 예견은 데이터에 의해 합리적으로 입증되었다. 1975년 그는 18 개월로 조정했으며 이것이 바로 대부분의 사람들이 요즘 인용하는 것이다. 재미있는 것은 Moore의 법칙은 시스템 디자인의 복잡함에 대해 언급하는 것 과는 달리 클럭(clock) 스피드에 대해서 많이 언급하지 않는다.

무어의 정확한 말을 보려면 http://ko.wikipedia.org/wiki/%EB%AC%B4%EC%96%B4%EC%9D%98_%EB%B2%95%EC%B9%99로 가면된다.

소크라테스는 ‘악법도 법이다’라는 소리를 지껄인 적이 없다…는 주장이 점점 힘을 받고 있는데, ‘아 다르고 어 다르다’ 소크라테스도 공자도 자기가 하고 싶은 바를 후세에 그대로 전달하지는 못했나보다. 무엇이든 자기가 바라는대로 맞춰서 전파하려던 선글래스 독재자까지는 아니더라도 이 시대를 살아가는 사람들은 옛 사람이 남긴 말을 그대로 전달하려고 하지를 않는다.

'IT 이야기' 카테고리의 다른 글

프로젝트의 예측  (0) 2009.03.12
Scott Adams  (0) 2009.03.11
멘탈 ?  (0) 2009.03.01
소프트웨어의 변증법  (0) 2009.02.23
추상화  (0) 2009.02.22
Posted by bleujin