동적 언어와 정적 언어

Posted by 엘키의 주절 주절 on February 21, 2017

나는 프로그래밍을 정적 언어인 C언어로 시작했다. 당시 지금보다 하드웨어는 비쌌다.

소프트웨어에서 성능 문제에 많은 최적화를 요구했고, 자연스레 동적 언어는 고려대상이 되기 어려웠다.

서버 비용이 비싸던 시기에 특히나 그랬다. 특히 4~5년 전만해도 C++이 아닌 다른 언어 (C#이나 Java)로 TCP 서버를 작성한다는 얘기가 나오면, 그렇게 느린 언어들로 서버 짤 수 있어요? 라는 이야기가 다수를 이뤘으니 말 다 했다.

속도와 개발자 pool이 좀 더 큰 요인이었다면, 작은 요인으로는 클라이언트 프로그래밍 언어가 C++이던 시절에, 서버로 전향하는 나같은 케이스가 많다보니 어쩔 수 없이 C++만 선택지였던 것도 있겠다.

시대의 흐름상 서버와 다대다 통신이 덜 중요한 게임들도 등장하며, 게임 업계에도 웹서버 붐이 일었다. 서버와 1대1 통신을 기준으로하면 웹서버 만큼 장점이 많은 환경도 없다.

그렇다보니 자연스레 동적 언어에 대한 니즈나 학습이 시작됐다. 나도 그 흐름에 맞춰 관심을 갖게 된 것이 예전부터 짬짬이 공부해오던 ruby를 실무에 더 밀접하게 적용하는 것이었고.

동적언어는 정적 언어보다 확실히 느리다. 인터프리터로 동작하기 때문이기도 하고, 표현력을 위해 많은 코스트를 희생하기 때문이기도 하다.

타입을 동적으로 다룰려면 C++스럽게 생각 했을 때, 최상위 Object와 같은 객체가 필요할 것이고 상황에 따른 다형성으로 동작시키게 해야 할 것이다. 가상 함수 테이블을 통한 억세스 정도의 차이가 아니겠냐고 반문 할 수 있겠지만, 그것과는 다른 문제다.

최상위 객체에 존재하는 모든 메소드를 넣고 그것에 대한 가상 함수 테이블을 만든다고 하면 가상 함수 테이블이 너무 커질 것이고, 타입 정보를 생성해두지 않고 매번 탐색한다면 그 비용은 역시나 동적 언어만큼 들 것이다.

그렇단 얘기는 컴파일이나 캐싱이 어렵다는 뜻이다. 한다손 치더라도 같은 동작이다라는 확신이 들었을 때 동작 시간 감소나 캐싱등의 일부 이득일뿐일테고.

속도상에서 메리트가 떨어지는 동적 언어가 메인 스트림 계열로 떠오를 수 있던 것은 시대의 흐름에 영향이 있다고 본다.

동적 언어가 서버 구축 언어로 떠오를 수 있는 것은 서버 비용이 싸졌으며, 확장성이 핵심이 되었기 때문이다.

C++은 국지적 최적화에는 강하지만, 확장성있게 규칙을 만들고 구현하는 것에 적합하지 않다. 또한 표현력을 확보하거나 의도를 명확히 하기 위한 공수도 많이 들며, 생각해야 될 꺼리가 많은 편인데, 이해도가 낮은 상태에서 사용하면 자칫 동적 언어보다 느린 구현을 하는 경우도 종종 발생하기 때문이다. (혹은 굳이 느리지 않더라도 복잡도를 증가 시킨다거나 하는 문제도 많다.)


지금껏 동적 언어에 대한 장점위주로 이야기했지만, 물론 정적 언어의 장점도 여럿있다. 컴파일 타임 최적화, 컴파일시 코드 검사, 정적 코드 검사에서 좀 더 많은 부분을 검사할 수 있다.

현재는 타입 유추 기능이 대다수 정적 언어에 도입된 만큼 타입에 관한 고통이 줄어든 점도 동적 언어와의 경쟁력에 도움이 될 것이다.

하지만 위에 언급한 이유들로 인해 메리트가 떨어진다. 부분적 최적화보다는 수십 수백대의 서버를 연결해 목적을 빠르고 정확하게 달성하는 것이 더 중요해진 것이다.

특히 이런 패러다임은 단일 프로세서 연산의 시대에서, 멀티 프로세서 연산, 네트워킹 기반 분할 연산으로 변화해옴과 무관하지 않다.

즉 패러다임에 따라 더 적합한 언어들이 선택되면서, 그 과정에 동적언어가 선택됐다고 봐도 된다. 특히 함수형 언어와 함수형 프로그래밍은 더더욱 메리트가 커졌고 말이다.

얘기가 돌고 돌아 현시대의 프로그래밍 패러다임 얘기까지 나왔지만, 말하고자 하는 두 타입 언어의 차이는 역시나 반비례하는 표현력과 안정성이다.

두 타입의 언어를 다룰때마다 생각보다 발상과 경험이 달라진다. 기존 코드가 만들어놓은 제약을 훨씬 더 많이 생각해야 하는 쪽은 정적언어다. 하지만 그만큼 의도를 명확히 하기도 쉽고, 정제하기 쉽다.

동적언어는 유연하지만 그만큼 안정성 확보가 어렵다.

유닛 테스트가 여타 언어들보다 동적 언어에서 더욱 유효한 이유는 동적 언어가 표현력을 얻은 대신 런타임 코스트와 빌드타임 커버리지를 잃었다. 이는 장단점이면서 동시에 특징이다.

혹자들은 언어는 수단에 불과하다지만 막상 언어를 사용할 때마다 드는 생각과 관점이 달라지는 것을 보면, 언어가 주는 특징들을 잘 알고, 상황에 맞게 사용하는게 좋지 않을까?