Dynamic Typing과 관련된 글을 블로그에 Static Type Checking이란 제목으로 쓴 적이 있는데 여기서 다시 한 번 정리해 보고자 한다.

블로그를 돌아다니다보면 많은 사람들이 TDD가 Dynamic Typing하는 언어의 특징이라고 생각하고 있음을 알 수 있다. 특히 일부 파이썬/루비 팬들이 운영하는 블로그에서 TDD가 언급되면 어김없이 동적 타이핑 언어의 테스트 편리성(혹은 크게는 생산성)에 대한 이야기가 뒤따라 온다.

하지만 C/C++처럼 수십 년도 더 된 구세대 언어와, 소프트웨어 개발 방법론과 테스팅에 대한 어느정도 이해가 쌓인 후에 나온 파이썬/루비와 같은 언어를 정적/동적 타이핑 면에서만 놓고 비교하는 것은 공정하지 못한다. 사실 너무 불공평하다.

파이썬/루비와 정반대 선상에서 정적 타입핑의 극상을 달리는 친구들은 ML과 Haskell 같은 함수형 언어(functional)들인데, 이 놈들은 C/C++ 보다 더 엄격하게 컴파일 타임에 타입 검사를 한다. 하지만 이쪽 언어 사용자들의 주장에 따르면 ML과 Haskell은 절대 테스트하기 불편한 언어도 아니고, 코드 길이가 길거나 생산성이 떨어지는 언어도 아니다.

순수하게 타이핑 측면에서만 바라본다면, 동적 타이핑은 컴파일 타임에 해주는 검사가 적은만큼(상당히 귀납적이다) 테스트를 통해 더 많은 버그를 찾아내야 하므로, 테스트를 훨씬 더 철저하게 많이 해야 한다. 잘못된 타입 연산 등의 간단한 버그 조차도 테스트를 통해서만 발견할 수 있다는 것은 재앙이다(타입 검사는 연역적이다)

테스트의 부담이 더 큰 파이썬/루비 같은 동적 타이핑 언어가 테스트를 강조하는 것은 당연한 일이다. 같은 기능을 하는 다른 프로그램 보다 더 많은 테스트를 해야 프로그램이 제대로 동작하기 때문이다. 즉 원래 언어적인 측면에서 태생적인 약점이 있으므로, 후천적인 노력으로 개선을 한 셈이다.

파이썬과 루비 같은 동적 타이핑하는 스크립트 언어의 테스트 편리성은 동적 타이핑이라는 속성에 기인한 것이 아니다. 이는 언어의 추상화(abstraction) 수준과 관계가 있다. 추상화 수준이 높을수록 코드는 사람이 생각한 바(스펙)에 가까워지고, 알아보기 쉬워지며, 금방 만들 수 있다.

C 언어와 파이썬/루비의 추상화 수준은 어떻게 다를까? 간단한 통계로 C 언어 construct 하나가 보통 1-10개의 머신 인스트럭션으로 컴파일 되는 반면에, 파이썬과 루비의 construct 하나는 100-1000개 이상의 머신 인스트럭션으로 실행된다.

즉, 파이썬이나 루비 개발자가 그토록 강조하는 "가독성", "짧은 코드"는 절대로 동적 타이핑(흔히 스크립트 언어)의 특성이 아닌 셈이다. 강력한 정적 타이핑 언어인 헤스켈(Haskell)의 퀵 소트 코드를 본 적이 있다면, 타이핑은 생산성이나 테스트 편의와는 직접적인 상관 관계가 없다는 데 동의할 것이다.

qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)

위 Haskell 코드는 polymorphic하다. qsort에 넘길 수 있는 타입은 >= 연산자가 정의된 list이기만 하면 된다. Haskell이 이처럼 간결한 코드를 보여줄 수 있는 이유는 파이썬/루비와 같은 수준의 추상화 레벨이면서, type inference를 통해 불필요한 타입 어노테이션을 필요를 상당히 줄였기 때문이다.

이처럼 같은 추상화 수준이라면 당연히 동적 타이핑보다는 정적 타이핑이 유리하다. 비유하자면, 타입 이론은 '사람은 모두 죽는다' '그러므로 소크라테스도 죽는다'라고 말하는 것이고, 테스트는 'A도 죽었고, B도 죽었고, C도 죽었으니 아마 소크라테스도 죽을 것이다'라고 말하는 셈이다.
  1. Favicon of http://snaiper.tistory.com BlogIcon snaiper

    | 2006.10.05 14:09 | PERMALINK | EDIT | REPLY |

    글 잘 읽었습니다. 꽤나 많이 생각하신 흔적이 들어나네요.

    제 생각은 이렇습니다. 테스트 편리성이 언어의 추상화 정도와 관련있다는 얘기는 하셨는데...저는 약간 생각이 다릅니다. 예를 들어 저는 오래전에 T-SQL로 단위 테스트 코드를 작성한 적이 있습니다. 아시다시피 이것도 정적타입이고, 추상화 정도가 상당히 높습니다. 하지만 정적 타입이다 보니 테스트코드가 상당히 길어지고 코드 중복이 많이 발생했습니다. 테스트 코드 만드는 것이 상당히 고통이 되죠. 만약 Ruby 와 같은 동적 타입이라면 코드를 절반이하로 줄일 수도 있었겠지요.
    그래서 테스트 편리성이라는 건 추상화 정도도 정도지만 얼만큼 테스트 코드를 적게 중복없이 코딩할 수 있냐가 중점이 될겁니다. 이런 의미에서 Typing 의 다름이 장점이 될 수도 있을 겁니다.

    말씀하신 Haskell 은 저도 얼마전에 조금 공부해 본 지라 잘 모르겠습니다. 만약 이런 측면에서 가능하다면, 그것도 테스트 편리성이 높다고 하겠지요. 그렇다면 스크립트 언어 자체가 TDD에 더 좋다고 해야 할까요? ^^

  2. Favicon of http://www.gomdoong.net/skyul BlogIcon 아저씨

    | 2006.10.05 15:44 | PERMALINK | EDIT | REPLY |

    snaiper님 의견을 잘 읽었습니다. ^.^

    테스트 케이스 작성의 편리성이라는 측면을 본다면 말씀하신 것처럼 여러 가지 특성이 관련되어 있을 수 있습니다. 일반적으로 코드 작성이 쉽고 빠른 언어의 경우, 테스트 케이스 작성도 쉽고 빠른 경우가 많죠. 실제로 자바 같은 정적 타이핑 언어도 테스트 케이스를 작성할 때는 Groovy 같은 스크립터 언어를 사용하길 권하기도 합니다.

    다만 원글에도 언급한 것처럼 동적 타이핑 언어는 안정성을 거의 전적으로 테스트에 의존하고 있기 때문에 정적 타이핑 언어보다 훨씬 테스트 케이스 작성을 많이 해야 한다는 문제를 안고 있습니다. 정적 타이핑 언어는 내부 논리를 테스트하는 몇 가지 테스트 케이스만 필요한 반면에, 동적 타이핑 언어는 온갖 타이핑 언어에 대한 테스트가 다 추가되어야 하거든요.

    그리고 동적 타이핑 언어의 또 다른 장점으로 드신 '코드 중복'을 줄이는 특성은 동적 타이핑이란 특성에 기인한 것이 아닙니다. 말씀하신 부분은 Parametric Polymorphism(C++의 템플릿이나 Java의 Generic)의 장점에 가깝습니다. foo(x) 이렇게 선언할 경우 x가 어떤 타입이든 상관없다는 거죠. 하지만 이 경우에도 파이썬이나 루비처럼 런타임에 타입 체크가 가능한 것과 컴파일 타임에 최대한의 Type Inference를 통해서 타입 오류 알려주는 것은 큰 차이가 있습니다.

    snaiper님이 T-SQL을 사용하시면서 겪으신 정적 타이핑의 불편함은 정적 타이핑 자체의 속성이라기보다는 Type Inference/Parametric Polymorphism 등의 부족이 원인이 아닐까 싶습니다. 이런 부분을 최대한 해주는 언어일수록 현대 언어에 가까운 것이고요. 이런 측면에서 C/C++ 같은 고전적인 정적 타입 언어는 테스트 케이스 작성이 힘들죠.

    스크립트 언어의 여러 특성(높은 추상화 레벨, Polymorphism을 비롯한 각종 편의 기능들)이 테스트 케이스 작성에 도움을 주는 것은 사실이지만, 동적 타이핑 한다는 사실 자체는 테스트에 대한 부담감을 늘릴 뿐이라고 생각합니다.

    요지는 스크립트 언어가 테스트에 나쁘다는 것이 아니라, 스크립트 언어의 동적 타이핑이라는 특성은 '많은 테스트 케이스' 작성을 요구하는 속성을 가지고 있으며, 파이썬과 루비 같은 스크립트 언어는 다른 수많은 장점들로 테이스 케이스를 쉽게 작성할 수 있게 만들어 그런 약점을 메우고 있다는 것이죠.

  3. Favicon of http://snaiper.tistory.com BlogIcon snaiper

    | 2006.10.05 17:03 | PERMALINK | EDIT | REPLY |

    음..그렇게도 생각이 가능하겠군요.

    Parametric Polymorphism 입장에서 접근하면 확실히 해결됩니다만....문제는 항상 그게 모든걸 해결해주지 못합니다. 제가 Java 전문가는 아니라서 잘 모르겠습니다만 Java나 C# 의 Generics의 문법이나 사용을 보던지, 또는 C++ 에서 사용해본 경험에 따르자면 그게 모든 걸 해결해줄 수는 없습니다. 오히려 쓸데없이 복잡한 코드를 대가로 치루는 경우가 휠씬 많습니다. 그래서 그걸로 끝날 수 있다면 좋은데 테스트 코드상 그런건 오히려 생각의 오버헤드를 대가로 하는 경우가 많습니다. 그래서 그런 의미에서 동적 타입이 오히려 더 간단합니다. 심플한게 좋은거죠...^^
    - 아 haskell 은 잘 모르겠군요. 언듯 보기에는 없는듯 한데, 패러다임이 다르니 비교 대상이 될런지 잘 모르겠습니다. -

    그리고 테스트 케이스를 늘린다는 얘기는 ... 제 경험상으로는 버그는 타입의 문제보다는 로직상의 오류가 문제입니다. 말씀하신대로 완벽한 테스트를 위해서는 테스트 케이스가 많아져야 한다는 사실자체에는 확실히 동의할 수 있습니다만, 하지만 진짜로 테스트를 하는 목적에서 보자면 동적이나 정적이나 그리 차이는 없다고 보여집니다. 실제로 타입에 대한 문제는 굳이 테스트 케이스를 만들어서 테스트를 안 할지라도 개발 단계에서 왠만한 건 발견이 됩니다. 설사 개발 단계에서 지나친다고 해도 개발자 내부 테스트와 QA 까지 거치면 이런 건 거의 발견이 되죠. 그러니까 허술한 듯 보여도, 실제로 사용하기에는 큰 문제가 없더라는 얘깁니다.

    글고 더 중요한 건 로직상의 오류이고 이건 발견하기 쉽지 않다는 건 이미 알고 계시겠죠? 그래서 정적 타입이라고 해서 부담감이 더 줄고, 동적이라고 해서 더 늘지는 않는다는 겁니다. 그래서 정적 타입이 더 좋을 거라는 생각에는 그리 쉽게 동의가 되지는 않는다는 얘깁니다. 그런 연유로 이미 알고 계시겠지만 Bruce Eckel 이나 Robert C. Martin 도 그런 결론에 다다른게 아닌가 합니다.

  4. Favicon of http://www.gomdoong.net/skyul BlogIcon 아저씨

    | 2006.10.05 23:45 | PERMALINK | EDIT | REPLY |

    의견 감사합니다^^

    Parametric Polymorphism과 Dynamic Typing에 대한 이야기는 글이 길어져서 별도의 글에 실었습니다. http://www.gomdoong.net/skyul/69

    논리 버그를 잡아내는 것이 중요하다는 사실에는 동의합니다 하지만 실제로 프로그래머를 괴롭히는 수 많은 버그들은 전부 타입 오류입니다. 화상 탐사선이 대기권에 돌입하다가 폭발하고, 많은 돈 들여 만든 프로젝트가 소프트웨어 결함으로 실패하는 경우를 분석해 보면 논리야 수 백 수 천에 걸쳐 검증했지만 정수 오버플로우나 단위 불일치(unit mismatch) 같은 사소한 타입 오류가 남아있어서 발생한 문제였습니다.

    스나이퍼님 말씀대로 타입 오류를 테스트와 QA를 거쳐서 쉽게 발견해 낼 수 있다(타입 오류는 별로 대다한 버그가 아니라고 쳐도)고 하더라도 검출을 위해서는 여전히 테스트 비용을 지불해야 합니다.

    이렇게 생각하면 간단하지 않을까요? 동적 타이핑을 하던 정적 타이핑을 하던 논리 오류는 어차피 잡아야 할 문제이며, 정적 타이핑은 타입 오류를 잡는 데 추가 비용이 거의 들지 않는데 비해서 동적 타이핑은 타입 오류도 테스트를 통해 잡아야 한다는 거죠. 논리(logic) 용어에 따르면 정적 타이핑은 Sound/Complete한 반면에 테스트는 Sound하지도 Complete도 하지 않기 때문입니다.

    Bruce Eckel 아저씨의 논리는 동적 타이핑을 하기 때문에 '생산성이 엄청나게 향상되고' 남는 시간에 테스트를 더해서 정적 타이핑 보다 나을 수 있다는 얘긴데, 제가 원 글에서 했던 얘기는 파이썬의 생산성이 좋다는 점에는 동의하지만 파이썬이 보여주는 생산성이라는 게 동적 타이핑과는 큰 상관 관계가 없다는 게 요지였죠.


    ---

    SNAIPER님 논지의 핵심은 사실 타입 시스템이라는게 말이 많고(verbose) 복잡해서 올바르게 쓰려면 드는 노력이 크기 때문에 득보다 해가 더 많다는 건데, C++이나 자바 등을 보면 사실 맞는 말이기에 저도 수긍 합니다.

    이 논지는 실제로 타입 시스템에 대한 주된 비판의 근거이기도 하죠. 필요없이 복잡한데 비해서 별로 보장해 주는 게 없으니깐요. 하지만 그에 대한 대안으로 동적 타이핑은 임시 방책에 불과하고, 궁극적으로는 타입 시스템에 대한 연구가 맞는 방향이라고 봅니다^^... 좋은 의견 주셔서 많이 생각해 보게 되었네요. 감사합니다.

  5. Favicon of http://www.hybrid.pe.kr/tt BlogIcon Hybrid

    | 2006.12.31 21:53 | PERMALINK | EDIT | REPLY |

    좋은 글 잘 보고 갑니다.
    Practical Common Lisp 책을 보다가 관련된 내용이 언급이 됐는데, 전반적으로 Dynamic Typing과 Test Driven Development 가 잘 이해가 안갔는데, 어느정도 감을 잡고 갑니다.(책은 계속해서 볼 수 있을 정도로.. ^^;)
    나머지는 따로 공부해나가야겠지요. RSS 구독도 신고합니다~ㅎ

  6. Favicon of https://skyul.tistory.com BlogIcon 서광열 lambda

    | 2007.01.09 01:44 신고 | PERMALINK | EDIT |

    감사합니다^^ 공부 열심히 하셔서 좋은 가르침을 주세요.

Write your message and submit
« PREV : 1 : ··· : 203 : 204 : 205 : 206 : 207 : 208 : 209 : 210 : 211 : ··· : 244 : NEXT »