Dynamic language 유감

예전 회사에서는 C 와 Java 가 사내 개발 언어였다.
근자에 들어 Dynamic 한 속성을 중시하는 script 언어들이 널리 회자되면서 Java 언어는 사용하기에 불편한 언어군에 속하는 것으로 여겨지지만, 예전에 C 로 개발하는 부서와 협업을 하다보면 Java 로 개발하는 것은 어느 정도 거저 먹는구나 란 느낌을 언제나 받았다.
전 직장에서는 수행시간에  critical 한 제품은 C로 개발하는 것이 당연시 되고 생산성과 유지 보수 및 향후 확장성이 더 중요한 제품은 Java 가 선택되었다.
나는 Java 를 사용하여 Middleware 를 만드는 부서에 속해 있었고, 나를 비롯한 구성원들의 화두는 Java 의 생산성과 확장성을 유지하면서도 C 만큼의 Performance 를 어떻게 하면 낼 수 있을까 였다.
그동안 Native thread 에 대한 지원, Garbage collector 의 성능 향상, Native io 지원, Hot spot VM 혹은 JIT compiler 등 Java 언어 및 가상머신은 그 성능에 있어 괄목할만한 발전을 이루어 냈고 우리는 이러한 발전을 오롯히 제품에 반영하려고 노력함으로써, 내심 이정도 Performance 를 내는 Middleware 를 확장성과 안정성 및 유지 보수의 용이성을 전혀 희생하지 않고서 C로 구현한다는 것은 어떠한 경우라도 수지타산이 맞지 않을 것이다란 생각을 가졌다.
그리고 해당 제품과 Java 로 만들어진 다른 Middleware 들이 Mission critical 한 영역에까지 저변을 넓히는 것을 목격하면서 우리의 생각이 틀리지 않았다는 확신을 가질 수 있었다.

예전 포스트에서도 언급한 바 있듯 지금은 Ruby 를 사용한 web application 을 개선하는 일을 하고 있다.
혹자는 Java 언어에 비해 생산성이 3배에서 10배까지 높다는 script 언어를 실무에서 사용할 기회를 얻은 것을 행운이라고 생각할지도 모르겠다.
일반적으로 Script 언어는 구닥다리? 컴파일 언어에 비해 생산성이 높다고 한다. 특히 Ruby 의 경우 여러 설문 결과 및 개인적인 경험담들을 쉽게 찾을 수 있다.
하지만 내가 이 글을 쓰는 이유는 과연 Ruby 의 생산성 신화는 과연 타당한 것인지 의문이 생겼기 때문이다.

지금 파악된 바로는 내가 소속된 부서에서 맡은 서비스는 일반적인 RDBMS 에 데이터를 저장하고 web page 를 서비스하는데 그치지 않고 SMS, MMS 문자 전송이나 OPEN API 지원까지 포함하다보니 코드의 라인 수가 10만 라인을 훌쩍 넘는다. 그리고 개발 인력의 수가 10여명 정도이다.

내가 느끼는 애로사항은 Ruby는 지나치게  Dynamic 하게 사용하기가 쉽다는 것이다.
예를 들어 코드 상에서 특정 메써드가 어디에 정의되어 있는지 알고 싶을 때 grep 이나 ack 로 이름 검색을 해야 한다는 건 좀 지나치지 않는가? 그렇게 대충 찾은 후엔 해당 위치를 일일이 파악하면서 과연 어느 정의가 내가 찾던 그 정의인지 확인해야 하는 작업을 해야 한다는 건 집중력을 흐트러뜨리는 데는 이것만한 것이 없었다.
이것만 해도 슬슬 어깨가 결려오는데 아무리 찾아도 안 찾기던 경우가 2가지 있었다. 하나는 클래스명과 메써드 명을 - 그것도 변수명에 넣어서 넘긴 후 introspection 을 사용하여 runtime 시에 동적으로 클래스 인스턴스를 생성한 후 메써드를 호출하는 경우였고 두번째는 method_missing 을 썼는데 parameter 로 넘긴 문자열의 prefix 가 무엇인가에 따라 prefix 를 뗀 나머지 문자열을 이름으로 가진 메써드를 호출하는 경우였다.
이러한 경우 여러 사람이 작업하다 보면 본의 아니게 이름공간이 훼손되는 경우가 생길 가능성이 짙다. Java 로 예를 들자면 Date 객체가 있는데 이게 대체 java.util.Date 인지 java.sql.Date 인지 모호한 경우가 되겠다.
Strictly typed 언어인 경우 compile 시에 이게 모호하다는 경고와 함께 발견 가능하다. IDE 를 쓰는 경우 ambiguity 여부를 바로 알려주기도 한다. 그런데 Ruby 에서 이런 일이 발생하면 이 에러가 동작시에나 검출된다. 이미 배포해서 서비스 하는 도중에 이런 일이 발생했다는 걸 알면 등에 식은 땀이 흐를 것이 뻔하고 미리 좀 알수 있었으면 얼마나 좋을까 란 생각이 절로 날 것이다.

물론 이러한 Dynamic 언어들을 옹호하는 측에선 작성자의 완전한 자유를 보장하는 것이 무엇보다 중요하기 때문에 의도적으로 그러한 가능성을 열어 둔 것이며, 이러한 오류는 테스트 케이스를 촘촘하게 준비함으로써 피할수 있다 라고 주장한다. 적절한 시간적인 여유가 있는 경우에는 그럴 수도 있겠다. 그런 여유를 가지고 구현하고 있는 곳을 알면 나에게도 좀 알려주었으면 한다.
테스트 케이스를 잘 잡으면 모든 오류를 방지할 수 있다 란 이야기가 어느 정도 먹혀들어가고 있다는 사실은 아직 Ruby 로 현실적인 상황에서 Mission critical 한 시스템은 구축된 적이 없다는 반증으로 밖엔 생각할 수 없다.

생산성의 정의를 협의로 생각한다면 한정된 시간에 얼마나 많은 기능을 구현할수 있는가에 대한 척도라고 할 수 있겠다. 이러한 점에서 3배, 10배 이야기도 나오는 것일 게다.
10사람이 할 일을 한 사람이 동일한 시간에 한다면 10배 이런 식일 것이다.
자 여기서 곰곰히 생각해 보자. 동일한 능력을 가진 사람이 사물을 보고 행동할 때 특정 패러다임을 다른 패러다임으로 바꾸었더니 10배 더 많은 Output을 내려면 어떻게 해야 할까?
내 생각에는 어느 한 패러다임이 굉장히 규격화된 경우라서 많은 기능을 생각없이 찍어낼 수 있으면 가능하다고 생각한다. 아마도 Active* 계열을 쓰는 Rails 프레임워크가 대표적인 경우일 것이다.
그런데 이건 좀 이상하지 않은가?
우리는 굉장히 자유로운 표현력을 가진다. 그런데 우리는 굉장히 높은 생산성도 가진다.
아무리 생각해도 이 두 문장은 미묘한 위화감을 준다.
아마도 두번째 문장 뒤에
- 단 우리가 미리 결정한 방식을 따르는 경우에는
이런 구절이 덧붙으면 적절할 것 같다.

생산성은 위에서 말하는 협의의 뜻으로 생각할 것이 아니라 향후 유지 및 보수의 유이성까지 포함한 광의로 사용되어야 한다. 그리고 설정보다 관례란 이야기에서 상당히 심한 강제의 냄새를 맡는다면 내가 지나치게 성마른 것일까?
표현력을 추구하자면 파악이 어려워져 유지보수가 어려워지고 (협의의) 생산성을 극대화 하자면 정해진 관례를 따라야만 한다.

Ruby 의 생산성에 대한 올바른 평가는
  1. Mission critical 한 부분에서
  2. 상당히 많은 수의 사람이 협업하며
  3. 복잡하고 많은 기능을 구현하는
3가지 조건을 만족하는 프로젝트의 결과를 본 후에야 납득할 만한 결론이 나올 것 같다.

Posted by eoh

2009/10/31 04:44 2009/10/31 04:44
, , , ,
Response
No Trackback , No Comment
RSS :
http://endofhope.com/tc/rss/response/10

자연스러움에 대하여

하나의 프로그래밍 언어에 어느 정도 익숙해 지면 필요없이 번잡하다고 느껴지는 API 들이 눈에 거슬리기 마련이다. 그래서 특정한 작업을 수행하는데 있어 제공되는 API 들을 사용하여 일일히 나열하기보다 스스로 작성한 서브루틴들을 사용해 깔끔함을 추구하게 된다.
하지만 조금 더 경험을 쌓다 보면 결국 서브루틴으로 묶는 것으로는 한계에 부딛치는데, 대표적으로는 약간 다른 일들을 하는 여러 비슷한 서브루틴들을 만들어야 하는 상황이 닥치는 것이다.
단순하게는 서브루틴들을 더 잘게 쪼갠 원자적 서브루틴들의 조합으로 만들면 되겠지 란 생각이 들겠지만, 이를 직접 해 보면 결국은 언어의 문법과 거진 1:1 로 매치해야 된다는 것을 알아채곤 바로 포기하게 된다.
이 정도에 다다르면 해당 언어에서 제공되는 문법 자체가 자연스럽게 느껴지지 않게 되어 내가 문법을 설계한다면 더 "자연스러운" 문법을 만들어낼수 있을 것이라고 생각한다.

프로그래밍 언어에서 자연스러움이란 무엇일지 생각해보았다.
먼저 내가 가지고 있는 책의 한 부분을 인용한다면
Ruby에 관한 오래된 문구 중에는 '놀라운 최소의 법칙' 이라는 게 있다. Ruby 커뮤니티에서 막연히 공유되고 있는 Ruby다운 사고방식으로, Ruby는 이 생각에 비추어 자연스럽게 행동해야 한다는 것이다.
- 출처 입문자를 위한 루비 - 유구이 저
라고 말하고 있다.
자연스럽다는데 막연하다니. 내가 느끼기엔 아무래도 왜? 자연스러운지에 대한 해답은 되지 않을 것 같고 따라서 자연스럽지 않다고 생각하는 사람에게 이렇기 때문에 자연스럽다 라고 주장할 수는 있어도 설득하기엔 근거가 약해 보인다.
(2..100).each do |candidate|
  sqrt = Math.sqrt(candidate)
  factor_found = (2..sqrt).any? {|i| candidate%i == 0}

  if factor_found then
    print "#{candidate}는 합성수\n"
  else
    print "#{candidate}는 소수\n"
  end
end
코드를 처음부터 읽어 내려가며 의미가 통하는 것에 주목하기 바란다.
- 출처 입문자를 위한 루비 - 유구이 저
라고 말하면서 "알고리즘이나 소프트웨어 개발의 보편적인 개념을 설명하는 사람들은 코드 예문으로 Ruby를 이용하게 되었다." 라고 쓰고 있다.
그런데 내겐
  1. 일단 아무런 사전 예고 (선언) 없이 나온 변수 sqrt 와 Math.sqrt 가 좀 헷갈린다.
  2. (2..sqrt).any?{..} 의 모습을 보건대 2 부터 sqrt 까지 돌면서 {..} 을 수행하고 그 결과가 any? 인지 - 즉 참인 것이 있는지 여부를 따지는 것으로 겨우 짐작할수는 있겠는데, 이게 자연스러운것과 무슨 관련이 있는 건지는 모르겠다.
  3. if factor_found then ... 를 보고 나서야 factor_found 가 boolean 값이구나 라고 짐작이 가능했다. 솔직히 말하면 if 조건 으로 factor_found 가 쓰인 것 을 보고서야 (2..sqrt).any?{..} 문장이 boolean 을 반환하는지 짐작할 수 있었다. 물론 ? 가 끝에 붙은 메써드는 boolean 을 반환하도록 미리 약속되어있다 라고 알고 있다면 쉽게 이해 되겠지만 어쨋든 한번에 이해하지 못한 내겐 결국 자연스럽지 않았다는 결론에 이르게 된다.
자. 자연스러운가?
루비 문법을 아는 사람에게는 아주 자연스러울 것이다.
하지만 내겐 그렇게까지 자연스럽지는 않다. 왜냐면 나는 루비 문법에 익숙하지 않으니까.
그러면 루비 문법에 익숙하면 자연스러워질 것인가?
까놓고 말해보자. 익숙하면 뭐든 다 자연스럽게 느껴진다. ;-)
다시 말하자면 자연스럽다는 것은 너무나 개인적인 감정인 것이다.

내가 이 코드 조각이 생각난 것은 "간만에 세미나를 가서 CUDA 에 관한 발표를 들었다" 는 아는 사람의 글을 보고 나도 시간을 내서 CUDA 를 사용해 보고 싶은데 왠지 CUDA 를 이용해 소수 찾기 알고리즘을 구현해 볼까 란 생각을 했기 때문이다.

모든 일들이 다 그렇듯 어른의 사정은 복잡하고도 미묘하다.
소수 찾기도 위에서 인용한 "자연스러운" 방법으로 접근하면 당연히 경쟁력이 없다.
그러면 루비로 어른스러운 알고리즘을 사용하여 소수찾기를 해 보면 어떨까?
과연 그 어른스러운 알고리즘도 "자연" 스러울까?
굳이 소수 찾기 같은 오덕스러운 분야는 제외한다면, 일반적인 프로그래밍이 얼마나 "자연" 스러울지는 내가 아직 루비 경험이 일천하여 판단하기 어렵다.

Posted by eoh

2009/09/26 04:44 2009/09/26 04:44
,
Response
No Trackback , No Comment
RSS :
http://endofhope.com/tc/rss/response/7


블로그 이미지

말할 수 있는 것은 분명하게 말해질 수 있다. 말해질 수 없는 것에 대해서는 침묵해야 한다. 논리 철학 논고 - 루드비히 비트겐슈타인.

- eoh

Archives

Authors

  1. eoh

Recent Comments

Recent Trackbacks

Calendar

«   2012/05   »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Site Stats

Total hits:
20059
Today:
44
Yesterday:
47