*이 글을 보기 전에

- "모든 악의 근원 : 불완전성의 원리"




어떤 사람들은 완벽하려고 하고, 어떤 사람들은 위험을 먼저 본다. 그리고 어떤 사람들은 위험보다 기회가 먼저 보인다.


불완전성의 원리를 증명한 쿠르트 괴델은 완벽해지려고 노력했던 사람인 듯 하다. 그리고 당대의 많은 수학자들은 수학의 완전성이 무너지는 것을 보고 그 분야를 연구하기를 외면했다.


하지만 지금 우리가 컴퓨터를 최초로 만든 사람들로 알고 있는 일련의 사람들은 그곳에서 기회를 찾았다. 이들이 불완전성을 무시했던 것은 아니다. 이미 불완전성은 다양한 형태로 소프트웨어 분야에서 명제화 되어 있다. 하지만 괴델이 증명에 사용했던 알고리즘의 시초에서 어떤 이들은 컴퓨터와 소프트웨어라는 자동 계산 기계에 대한 기회를 발견했다.


당시는 한창 2차 세계 대전이 진행 중이었고, 전쟁에서 이기기 위해 암호 해독, 무기 개발 등 다양한 연구를 수행하고 있었다. 연구를 위해서는 수학, 물리학 등 다양한 분야에서 당대 최고의 학자들을 모아 놓을 필요가 있었는데, 이들 중에 현대 컴퓨터 구조의 아버지라 불리는 폰 노이만이 있다.


그는 당대의 모든 학자들 중에서도 단연 최고의 천재라 불릴 만큼 대단한 사람이었다. 그에 대한 수많은 일화가 있고, 그것이 사실인지는 확인이 필요하지만 소프트웨어라는 것을 어떻게 생각했는지를 알 수 있는 일화가 하나 있다. 


컴퓨터는 만들어졌고, 컴퓨터를 구동시킬 알고리즘을 구현해야 했던 상황에서 당시에 활용할 수 있는 것은 0과 1로만 이루어진 기계어 뿐이었다. 폰 노이만의 제자들 중에서 기계어를 가지고 알고리즘을 구현하는 것이 무척 어려움을 느끼고 그보다 더 고급 언어(아마 어셈블리어 쯤 되지 않을까 한다)를 만들려고 하고 있었다. 고급 언어를 만들기 위해서는 언어를 정의하고, 정의된 형식대로 프로그램을 작성하고, 작성된 프로그램을 컴퓨터에 입력하고, 컴퓨터에 입력된 프로그램을 다시 기계어로 바꾸는 작업이 필요하다. 이러한 일련의 과정에는 컴파일러라는 프로그램이 필요하고 컴파일러는 컴퓨터의 컴퓨팅 능력이 없으면 동작하지 않는다.


요컨데 인간이 이해하기 쉬운 컴퓨터 언어를 만들어 사용하려면 컴퓨터의 연산 능력을 활용해야 한다는 의미이다. 폰 노이만이 이에 대해 한 말은 '완벽한 신의 언어가 있는데, 그걸 놔두고 저런 조잡한 걸 만들려고 하느냐?(위키)'였다.


개인적으로 저 일화가 진짜인지 확인하기는 어렵지만 일화가 알려주는 몇가지 중요한 문제들이 있어 짚어보고자 한다.


코드의 명료성

그렇다. 기계어는 인간이 이해하기 너무 어렵다. 얼마나 어렵냐면, 기계어로는 너무나 어려워서 기계어로 컴파일러를 만들고 조금 쉬운 언어를 정의해서(언어가 '조금' 더 쉬운 것이지 언어를 정의하는 일이나 새로 정의된 언어가 쉬운건 아니다) 그 언어를 컴퓨터에 입력할 수 있는 기계어 프로그램을 만들 생각을 하고 실천해야 했을 만큼 어렵다. 당시의 소프트웨어는 현대의 소프트웨어만큼 비 결정적이고 변덕스럽지 않다.(이 말의 의미는 잘 알고 있을 것이다. 현대의 소프트웨어게 사람들은 미래의 기대도 만족 시킬 수 있을 정도의 유연성을 요구한다. 미래의 기대는 아직 나타나지도 않았는데 말이다.) 폰 노이만과 같은 천재가 아니라면 기계가 바로 동작 시킬 수 있는 기계어로 현대의 소프트웨어를 만든다는 것은 불가능한 일이다.


이 일화에서 끄집어 내고 싶었던 부분은 범용 컴퓨터가 만들어진 시절부터 이미 코드의 이해 측면, 즉 인간이 이해할 수 있는 언어를 만들겠다는 생각이 존재했다는 점이다. 이것은 중요한 관점인데, 현대에도 잘 짜여진 코드의 중요한 덕목이 명료성이기 때문이다. 명료성이란 한마디로 말하자면 인간이 이해하기 편해야 한다는 특성이다. 어떻게 만들든지 기계어는 명료하지 않다. 현대의 언어로 만들어진 코드라고 해도 명료성을 추구하지 않으면 코드의 품질은 이루 말할 수 없이 저하된다. 하물며 기계어를 계속 다루었던 사람들이라면 (폰 노이만을 제외하고) 보다 고급 언어를 정의하여 사용하고 싶다는 욕구가 지금보다 더 강했을 것을 것이라 생각해 볼 수 있다.


현대의 언어를 접하면서 우리가 염두해 두어야 할 것은 언어의 문법을 이해하는 것보다 언어의 관점을 이해하는 것이 더 중요하다는 점이다. 문법은 우리에게 가능성을 열어준다. 문법이 정의되어 있지 않으면 우리는 어떤 생각을 코드로 표현할 수 없다. C언어에는 객체지향 문법이 없다. 따라서 C언어로 객체지향을 표현하기가 어렵다. 따라서 문법을 잘 알지 못하면 표현하고 싶은 것이 있어도 표현하지 못한다. 따라서 문법을 공부하는 것은 당연히 중요하다. 문제는 많은 이들이 문법을 공부하고 깊이 이해하면 이해할 수록 문법이 주는 자유에 빠져들어 간다는 것이다. 어떤 이들은 문법이 "허용된 자유의 범위"라고 생각한다. 마치 문법을 문자 그대로 "법"이라고 생각하는 것 같다. 그래서 법으로 정해진 범위 내에서 모든 것이 가능하다고 생각한다. 이러한 생각을 표현한 말이 "돌아가기만 하면 된다"는 말이다. 문법이 "법"으로써 강제하는 정도는 그리 심하지 않다. 개수를 나타내는 변수 이름을 count라고 쓰지 않는다고 해서 컴파일러가 문법 오류를 발생시키지 않는다. 그래서 어떤 사람들은 이것을 "자유"라고 칭하고 변수 이름을 a라고 짓는다. 이것은 인간의 인지 능력에 대한 테러에 가깝다.


문법을 "자유"라고 생각하는 것은 관점을 무시한 생각이다. 관점이란 언어를 디자인한 목적을 말한다. 현대의 많은 언어들이 객체지향 언어이다. 객체지향 언어는 문법도 상당히 어렵다. [상속에 대한 올바른 이해]에서도 이야기 했듯이 객체지향 언어를 처음 접한 이들은 문제 해결과 직접 연관이 없는 문법들을 공부하느라 머리가 아파진다. 하지만 그러한 문법이 왜 생겼는지에 대한 생각, 즉 언어가 드러내고자 하는 관점을 이해하지 않으면 문법도 이해하기 힘들다. 문법이 정해져 있다는 것은 일반 "법"과 마찬가지로 제약이 정해진다는 것이다. 제약이 정해졌다는 것은 "법"과 마찬가지로 해악을 바로잡겠다는 의지가 담긴 것이다. 인간의 의지가 담겨 있을 정도로 언어적 제약이 중요했기 때문이다.


그러면 문법에 어떤 의지가 담겨 있는 것일까? 딱 한가지 의지, 즉 관점만 이야기 해보자면 바로 "아무렇게나 한다고 모두 코드가 아니다"라는 관점이다. 어셈블리어를 정의한 이유는 기계어가 가졌던 완벽히 기계어적인 자유를 박탈해야 했기 때문이다. 0과 1로만 이루어진 코드가 가진 자유는 인간에게 허용되기에는 너무나 큰 자유다. 정확히 어떤 자유냐면 "인간이 이해하기 힘들 만큼 어려운 자유, 인간이 다루기에는 너무 이해하기 힘들 만큼의 자유"다. 불완전성의 원리에서 이야기 했듯이 불완전성을 다룰 수 있는 유일한 도구는 바로 인간의 두뇌다. 따라서 인간의 두뇌가 가진 인지 능력을 자꾸 벗어나려고 하는 코드는 제약을 가해 바로 잡을 필요가 있다. 어셈블리어의 관점이란 그것을 표현한 것이다.


그러면 C언어의 관점은 무엇일까? C언어는 구조적 언어의 관점을 포함하고 있다. 소프트웨어가 점점 커지고 복잡해질수록 거대한 소프트웨어를 부분으로 나누어 개발해야 한다는 생각이 자리 잡기 시작했다. 구조적 언어를 달리 표현하는 말이 "절차지향 언어"라는 말인데, 이 말은 구조적으로 분리된 부분들을 순서에 맞춰 수행시키겠다는 의미이다. 이것은 이전 언어인 어셈블리어가 가지지 못한 관점이다. 어셈블리어는 이해 측면에서는 기계어보다 나았을지 몰라도 역시 비 구조적 언어의 특성을 함께 가지고 있었다. 따라서 전체 소프트웨어가 부분 부분으로 분리되어 있지 않았고, 전체 소프트웨어의 절차, 즉 어떤 순서로 실행되는 것인지 이해하기가 어려웠다. 이러한 문제점을 보고 해결하려고 했던 노력이 담긴 것이 C언어이다. C언어는 문제를 함수라는 부분으로 나누고, 부분으로 나뉜 함수들을 어떤 순서로 실행할지를 정할 수 있다. 왜 이렇게 만들었을까? 언어가 발전해 온 이유, 즉 무엇인가를 왜 만들었을까에 대한 답은 항상 한가지이다. 인간이 이해하는데는 그렇게 만드는 것이 더 낫기 때문이다.


자 이제 말하고 싶었던 내용을 정리해 보면 이렇다. 소프트웨어를 만드는 프로그래밍 언어는 점점 더 인간이 이해하기 좋은 형태로 발전되어 왔다. 그 이유는 인간이 이해하지 않으면 소프트웨어를 관리하는 것이 불가능해지기 때문이다. 그래서 다시 언어의 관점을 정의해 보면 다음과 같다. 언어의 관점은 인간의 인지 능력을 보다 효율적으로 사용할 수 있도록 해야 한다는 것이다. 이것이 어셈블리어 같은 자연어 언어를 만들어 내고, C언어와 같은 구조적 언어를 만들어 내고, 객체지향 언어를 만들어 냈다. 함수형 언어나 스크립트 언어는 뭔가 특별한가? 아니다. 그것도 그들 나름대로 인간의 인지 능력에 최적화하려고 노력한 언어들이다. 어떤 부분에서는 인간이 신경쓰지 않아도 될 일들을 적절한 수준에서 감추었고, 어떤 부분에서는 기존의 언어들이 주지 못했던 유연성을 보충해 주었다. 이렇게 함으로써 인간이 해야 할 일과 인간이 하지 않아도 될 일들을 구분해 주었다. 인간이 해야 하는 일은 소프트웨어가 불완전성에 의해 오동작 하는 것을 방지하는 일이다. 인간이 하지 않아도 되는 일은 무의미한 반복, 비즈니스 로직과 상관 없는 코드의 갑작스런 출현 등이다.


비 구조적 언어

그렇다면 왜 처음부터 인간이 이해하기에 좋은 언어를 만들어 내지 못했을까?


폰 노이만은 괴델이 불완전성의 원리를 발표했던 장소에 있었다고 한다. 그리고는 "모든게 다 끝장 났다"고 말했다는 일화도 있다. 이 일화는 폰 노이만이 불완전성의 원리를 이해하고 있었다는 의미이다. 하지만 컴퓨터를 만들 생각을 한 걸 보면 그는 역시 기회를 더 많이 본 것이 아닐까 생각한다.


하지만 안타깝게도 그가 설계한 컴퓨터가 이해한 언어, 즉 기계어는 그 이후에 출현한 어셈블리어와 마찬가지로 비 구조적인 언어이다. 비 구조적 언어라는 것은 "구조가 없는 소프트웨어를 만들어 내는 언어", 즉 소프트웨어가 일정한 부분들로 분리될 수 없고 소프트웨어 전체가 하나의 단위로 만들어지는 언어라는 말이다. 현대에 소프트웨어를 공부하는 사람들이 이해하기 쉽게 설명하자면, 최근의 소프트웨어는 적어도 전체 소프트웨어를 다수의 변수와 다수의 함수로 구분시킬 수 있다. 객체지향 언어라면 객체 단위로도 구분지을 수 있다. 비 구조적 언어를 현대 언어로 개발하는 방식에 비유해 보자면 몇만 라인짜리 소프트웨어를 단 하나의 함수에 구현한 것이라고 볼 수 있다.(지금도 이렇게 하는 사람이 많지만...... 이렇게 만든 것이 쓸모 있다면 그를 폰 노이만으로 부르겠다) 지금은 몇 만 라인 코드가 흔하지만 당시에 언어는 기계어나 어셈블리어이다. 만만치 않은 일이었을 것이다. 그것도 함수 하나에다 구현하는 것은 더더욱 그렇다.


이렇게 된 데에는 두가지 원인이 있다. 


하나는 최초 괴델의 증명에 사용되었던 알고리즘의 시초는 구조적인 형태가 아니었다. 그것에 영감을 받아 만들어진 것이 폰 노이만의 컴퓨터이다. 그래서 소프트웨어를 구조적으로 만들어야겠다는 생각을 먼저 하지는 못했을 것이다. 최 우선으로 생각해야 할 것은 괴델이 만든 알고리즘이 동작 가능하도록 하는 것이었다. 그런 상황에서 소프트웨어의 머나먼 미래를 내다 보고 구조적 언어로 기계어를 설계한다는 것은 불가능했다.


두번째 원인은 폰 노이만의 천재성 때문이다. 앞서의 일화가 사실이라면 그에게는 기계어를 다루는 것이 현대의 고급 언어들을 다루는 일보다 쉬운 일이었을 것이다. 그런 그가 알고리즘을 구조적으로 구현할 필요성을 느끼지 못했을 것은 자명하다. 기계어로도 그런 일을 충분히 할 수 있는데 굳이 컴퓨터의 연산 능력을 사용해 가면서 컴파일이라는 비 생산적인 일을 해야 할 이유를 못 느꼈을 것이다. 어쩌면 컴퓨터의 구조는 단순한 것이 좋고, 인간이 이해하고 작성하기 편한 소프트웨어를 만드는 것은 컴퓨터의 연산 능력을 이용하는 편이 좋다고 생각했을지도 모른다. 하지만 아무래도 폰 노이만에게는 그런 생각은 없었을 것 같다.


사실 위의 두가지 원인은 결과를 놓고 유추해 본 것에 불과하다. 폰 노이만은 천재이면서도 인간에 대한 이해가 높은 사람이었다. 컴퓨터가 유용해지고 더 많은 사람들이 컴퓨터를 접하는 시기가 오면 소프트웨어도 보통의 인간들이 다룰 수 있는 수준이 되어야 할 것이라는 생각을 못하지는 않았을 것 같다. 그래서 다른 하나의 원인을 생각해 보자면 인간이 이해하기 쉬운 언어를 만들어 내는 일보다는 다른 일이 더 중요했고 시간이 부족했지 않을까 생각한다. 천재라고 해서 모든 일을 다 할 수는 없는 것이니 말이다.


소프트웨어의 예견된 위기

컴퓨터는 폰 노이만과 같은 천재들에 의해 만들어졌다. 그리고 암호 해독이나 무기 개발 등 다양한 분야에 필요한 계산 기능을 수행함으로써 그 유용성이 증명되었다. 그리고 컴퓨터가 계산한 결과로 만들어진 무기들이 정확하게 작동하는 것을 확인하면서 이제 사람들은 컴퓨터의 연산 능력을 계속 향상시켜서 더 많은 계산을 수행하게 만들어야겠다는 생각을 하게 된다. 폰 노이만 이외에도 수많은 천재 수학자, 물리학자들이 같은 일을 하고 있었지만, 그들 같은 천재는 세상에 그렇게 많지 않다. 


폰 노이만은 당시의 컴퓨터나 계산기들보다 더 빠른 계산을 할 수 있었다고 한다. 하지만 계산을 항상 천재들에게 의존하는 것은 효율적이지 못하다. 우선 인간은, 특히 그런 천재들은 돈만 준다고 해서 일하는 사람들이 아니다. 그들 나름대로의 지적 탐구 방향과 주어진 일이 맞아 떨어져야만 가능한 일이다. 그들도 의지를 가진 인간이기 때문이다. 하지만 컴퓨터에게는 그런류의 불확실성이 없다. 컴퓨터를 이용해서 더 많은 계산을 시키겠다는 것은 합리적인 생각이다. 비록 당대의 천재보다는 못했다 하더라도 기술을 계속 발전시키면 그렇게 되지 못할 것도 없었고, 실제로도 그렇게 되었다.


이처럼 컴퓨터의 유용성에 눈 뜬 과정은 상당히 짧았으나, 그와 함께 탄생했던 소프트웨어 기술의 중요성에 눈을 뜨기 시작한 것은 그보다 한참 후였다. 그 원인을 좀 생각해 보면 다음과 같다.


우선 초기 컴퓨터는 성능이 떨어졌기 때문에 지금처럼 거대한 소프트웨어를 만들 필요가 없었다. 컴퓨터를 이용하는 목적은 일반적인 사람들보다 더 빠른 공학적, 수학적 계산이다. 목적이 명확한 상태에서 성능이 부족한 컴퓨터에 작은 소프트웨어를 개발하는 것이다. 아마도 많은 소프트웨어가 단 한 사람의 개발자의 손에서 개발될 수 있었을 것이다. 이러한 환경에서는 굳이 컴파일러는 만들고 프로그래밍 언어에 대한 이론을 만들 필요가 없었다. 


두번째 이유는 초기 컴퓨터를 개발하고 소프트웨어를 개발하던 사람들이 당대 최고의 지성인들이었다는 점이다. 초창기 소프트웨어 개발자들의 전공은 다른 분야였겠지만 많은 사람들이 수학자나 물리학자, 공학자들이었고, 수학과 같은 논리적인 사고에 익숙했던 사람들이었다. 게다가 당시는 전시이다. 그들 중에서도 뛰어난 사람들만 끌어 모을 수 있었을 만큼 자본은 충분했다. 이런 이들이 모여 만든 소프트웨어다. 장담하건데 당시에는 소프트웨어에 작은 버그 하나만 나와도 수많은 천재들 앞에서 조롱을 당했을 것 같다. 이런 분위기라면 대부분의 소프트웨어가 완벽한 상태였을 것이고, 그런 상황에서 소프트웨어 기술을 개발한다는 것은 생각하기 힘들다.


하지만 시간이 지날수록, 즉 컴퓨터의 성능은 점차 좋아지고, 상업적인 이용 가치가 부각되면서 컴퓨터와 소프트웨어를 연구하는 사람들은 점점 더 많아지고, 이와 더불어 경쟁이 치열해 지면서 시간적 여유는 부족해지게 되었다. 특히 상업적으로 발전하게 된 상황을 보면 소프트웨어가 위기에 빠지게 된 이유를 이해할 수 있을 것이다.


최초의 컴퓨터가 군사적 목적이었다는 점은 자원이 풍부했다는 것을 의미한다. 소프트웨어에서 자원이 의미하는 것은 곧바로 인적 자원을 말한다. 즉 논리적 사고에 특화된 고급 인력들이 소프트웨어를 만들어 왔다. 하지만 컴퓨터와 소프트웨어 개발이 상업화 되면서 금전적 이득을 추구하게 되면서 초창기 우수한 인력들에 비해 낮은 비용으로 채용된 사람들이 그들의 자리에 들어 앉게 되었다. 이것은 그들과 현대의 수많은 소프트웨어 개발자들을 비하하고자 해서 하는 말이 아니다. 전체적으로 보면 소프트웨어 개발자 집단은 예전이나 지금이나 상당한 수준의 창의성과 지성을 갖춘 인재들이다. 하지만 상업적인 목적을 위해서 어느 정도 규모 이상의 인력을 확충하다 보면 아무래도 군사적 목적으로 끌어들인 최고의 인력들과 같은 수준의 비용을 지불하기 어렵고, 그러면 그렇게 뛰어난 사람을 모두 잡기는 어려웠을 것이다. 이 상황에서 나름대로 선발 기준을 잘 정립한다 해도 개중에는 질이 떨어지는 사람들이 끼어 들어오는 것을 막기가 힘들다. 그리고 그때나 지금이나 마찬가지로 소프트웨어는 개개인의 생산성을 측정하기가 상당히 어려운 분야이다. 대다수의 사람들이 창의성과 지적인 능력을 가지고 성실하게 일을 했다고 해도 문제의 대다수는 소수 인원의 무지에 의해서 발생한다. 그리고 이것이 상업적 목적, 즉 이윤 추구와 만나면서 개발 기간이 자주 축소되고, 요구사항이 자주 변경되며, 개개인의 사정에 의해 개발 인력이 자주 바뀌는 상황과 맞물리게 되면 아무리 뛰어난 인력이라고 해도 고전하는 것은 당연하다.


이렇게 고전할만한 요소들이 갖춰지자 이전에는 간과되었던 부분들이 중요한 부분으로 떠오르게 되었다. 소프트웨어도 하드웨어 개발에 준하는 개발 프로세스가 필요하다는 것, 소위 말하는 '통짜' 프로그램을 개발하는 것이 아니라 구조적인 개발, 즉 설계가 필요하다는 것, 그리고 설계의 의도를 반영할 수 있고, 이전의 비 구조적 언어의 관행을 돌아가지 않게 해 줄 단단한 문법을 갖춘 언어가 필요하다는 것이다.

Posted by 이세영2
,