이 글은 Crash Course의 Computer Science를 보고 정리한 글입니다.
하드웨어 수준에서의 프로그래밍은 번거롭고 융통성이 떨어지기 때문에 프로그래머는 컴퓨터를 프로그래밍할 수 있는 다양한 방법은 원했다. 바로 소프트웨어이다.
앞서 보았듯이, 컴퓨터 하드웨어는 원시 이진 명령어를 처리한다. 이것은 컴퓨터 프로세서가 말할 수 있는 "언어"이다. 이 언어를 기계어(Machine Language 또는 Machine Code)라고 한다. 컴퓨팅 초기에는 사람들이 전체 프로그램을 기계어로 작성해야 했다. 더 구체적으로 말하자면, 먼저 영어로 종이에 높은 수준의 프로그램을 작성했다. 예를 들면, "다음 판매를 메모리에서 검색한 다음, 하루, 주, 연도의 누적 합계를 더하고, 추가할 세금을 계산하시오." 등등 이런 것들이다.
이런 프로그램에 대한 비공식적이고 높은 수준의 설명을 의사 코드(Pseudo-Code)라고 한다. 그리고 종이에 프로그램을 모두 파악해 낸 후, 프로그래머들은 그것을 고심하여 이진 기계어로 opcode 표 같은 것을 사용하여 손으로 직접 확장하고 번역했다. 번역이 완성된 후에야 프로그램은 컴퓨터에 입력되어 실행될 수 있었다.
1940년대 말과 50년대에 이르러 프로그래머는 약간 더 높은 수준의 언어를 개발했다. 그것은 사람이 좀 더 읽을 수 있는 언어였다. opcode에는 니모닉(mnemonics)이라고 하는 간단한 이름이 지정되었다. 따라서 1과 0의 무더기로 지침을 작성하는 대신, 프로그래머는 "LOAD_A 14"와 같은 것을 쓸 수 있었다. 이전 에피소드에서 사용한 것이 이 니모닉이다.
물론 CPU는 "LOAD_A 14"가 뭔지 알지 못한다. CPU는 텍스트 기반 언어를 이해하지 못하고 오직 이진수만 이해한다. 그래서 프로그래머들은 트릭을 만들어냈다. 바로 재사용 가능한 도우미 프로그램을 이진 형식으로 만든 것이다. 그 프로그램은 문자 기반의 명령을 읽고 자동으로 이진 명령과 일치하는 것을 조합했다. 이 프로그램이 바로 어셈블러(Assembler)라고 불리는 것이다. 이것은 어셈블러 언어로 된 프로그램을 읽고 원래의 기계어로 전환한다. "LOAD_A 14"는 어셈블리 명령어의 한 예이다.
시간이 지남에 따라 어셈블러에는 새로운 기능이 추가되었고, 프로그래밍은 훨씬 쉬워졌다. 한 가지 멋진 기능은 자동으로 JUMP주소를 파악하는 것이다. 이전 에피소드에서 사용한 예제 프로그램은 JUMP명령어 뒤에 주소(ex-"JUMP 2")가 직접 입력했다. 이러한 프로그램은 초반에 더 많은 코드를 추가하면, 모든 주소들이 변경되어 프로그램을 업데이트하기 힘들다는 것이다.
그래서 어셈블러는 원래 JUMP주소를 사용하지 않고 JUMP 할 수 있는 작은 레이블을 삽입할 수 있게 하였다. 이 프로그램이 어셈블러로 전단되면, 모든 점프 주소를 알아내는 일을 한다. 이제 프로그래머는 프로그래밍에 더 집중할 수 있고, 하드웨어 메커니즘에 덜 집중하며, 불필요한 복잡성은 숨겨서 더욱 정교한 작업을 수행할 수 있게 되었다.
그러나, JUMP를 라벨에 자동 링크하는 것과 같은 멋진 어셈블러 기능이 있더라도 어셈블리 언어는 여전히 기계어에 비해 얕은 겉치장에 불과했다. 일반적으로, 각 어셈블리 언어 명령어는 해당 기계 명령어로 1:1 매핑되어 직접 변환된다. 그래서 어셈블리 언어는 본질적으로 기본 하드웨어에 묶여 있다. 그리고 어셈블러는 여전히 프로그래머에게 어떤 레지스터와 메모리를 사용할지 생각하도록 강요한다. 갑자기 추가해야 할 값이 필요하면 그에 맞는 많은 코드를 변경해야 할 수도 있었다.
1944년 Harvard Mark 1은 연합군의 전쟁 노력의 일환으로 탄생했다. 프로그램이 펀치 종이테이프에 저장돼서 컴퓨터에 입력되었다. 이때 프로그래머들은 프로그램의 잘못 뚫린 구멍(일종의 버그)에 "패치"를 붙여서 해결하였다. Mark 1의 명령 세트는 매우 원시적이었고, JUMP 명령 조차도 없었다. 동일한 작업을 여러 번 반복하는 코드를 작성하려면 펀치 테이프의 두 끝을 붙여 물리적인 루프(고리)를 만들었다. 전쟁 후에 Harvard Mark 1의 프로그래머였던 호퍼(Hopper)는 컴퓨터 업계의 최전선에서 계속해서 일했고, 컴퓨터의 잠재력을 최대한 발휘하기 위해 높은 수준의 프로그래밍 언어를 설계했다. 그것을 산술 언어 버전 0(줄여서 A-0)이라고 불렀다.
어셈블리 언어는 직접, 기계 명령어에 일대일 매핑된다. 반면, A-0는 한 줄의 높은 수준의 프로그래밍 언어로 수십 가지 명령이 CPU에 의해 실행될 수 있었다. 이 복잡한 번역을 수행하기 위해 Hopper는 1952년에 최초의 컴파일러(Compiler)를 만들었다. 이것은 전문화된 프로그램으로 프로그래밍 언어로 작성된 소스코드(Source Code)를 어셈블리 또는 이진 기계어와 같은 낮은 수준의 언어로 변환하여 CPU가 직접 처리할 수 있었다.
안타깝게도 A-0 코드의 생존 사례가 없다. 그래서 파이썬을 예시로 사용하겠다.
두 개의 숫자를 추가하고 그 값을 저장하도록 해보겠다. 어셈블리 코드에서는 메모리 값을 인출, 레지스터 및 기타 낮은 수준의 세부 사항을 처리해야 한다. 하지만 이 프로그램은 파이썬으로 간단하게 작성될 수 있다.
A = 3
B = 9
C = A + B
여기서 처리할 레지스터 또는 메모리 위치가 없음을 주목하라. 컴파일러가 그것들을 다루고 많은 낮은 수준의 불필요한 복잡성을 추상화한다. 프로그래머는 단지 변수(variables)로 알려진 메모리 위치를 위한 추상화를 만들기만 하면 된다. 단지 변수에게 이름을 주면 된다. 두 숫자를 가져와 변수를 저장하고 이름을 붙일 수 있다.
위의 경우, 변수의 이름을 A와 B라고 했지만 그 변수들은 무엇이든 될 수 있다. 그리고 둘은 더하고 새로 만든 변수 C에 결과를 저장한다. 컴파일러가 Register A를 할당하여 a값을 저장했을 수도 있다. 하지만 그걸 굳이 알 필요는 없다.
그러나 A-0 및 그 후의 변종은 널리 사용되지 않았다. "Formula Translation"에서 파생된 FORTRAN을 몇 년 후인 1957년에 IBM이 발표하여 초기 컴퓨터 프로그래밍을 지배했다. 평균적으로, FORTRAN으로 작성된 프로그램은 손으로 쓴 어셈블리 코드보다 20배 더 짧았다. FORTRAN 컴파일러는 이 코드를 변환하여 원시 기계 코드로 확장한다. 커뮤니티에서는 FORTRAN의 성능이 손으로 쓴 코드만큼 좋을지 회의적이었다. 그러나 프로그래머가 더 많은 코드를 더 빨리 쓸 수 있다는 사실 때문에 경제적으로 쉽게 선택되었다. 프로그래머 시간을 현저하게 줄이기 위해 계산 시간을 약간 늘리는 것이다.
물론 IBM은 컴퓨터 판매 사업을 하고 있었으므로 초기에는 FORTRAN코드는 IBM 컴퓨터에서만 컴파일되고 실행될 수 있었다. 그리고 1950년대의 대부분의 프로그래밍 언어와 컴파일러는 단일 유형의 컴퓨터에서만 실행 가능했다. 그리고 컴퓨터를 업그레이드했다면 종종 모든 코드를 다시 작성해야 했다. 이에 따라 산업, 학계의 컴퓨터 전문가들과 정부가 1959년에 협회를 구성하여 데이터 시스템 언어위원회를 만들었다. 다른 컴퓨터에서도 사용할 수 있는 공통 프로그래밍 언어 개발을 안내하기 위함이었다.
그 결과는 사용하기 쉽고, 높은 수준의 공통 비즈니스 지향 언어(Common Business-Oriented Language) 또는 줄여서 COBOL이라 부르는 것을 만들었다. 서로 다른 기본 하드웨어를 다루기 위해, 각 컴퓨터 구조에는 자체 COBOL 컴파일러가 필요했다. 이 컴파일러는 어떤 컴퓨터에서 실행되든 동일한 COBOL 소스코드를 수용할 수 있었다. 이 개념은 "한 번 쓰면 어디서나 실행(Write once, Run anywhere)"이라고 불렸다. 어셈블리와 기계어에서 멀어지는 이점이 있다. 하지만 여전히 CPU와는 관련이 있다.
이 모든 것의 가장 큰 영향은 컴퓨팅에 대한 진입 장벽을 줄이는 것이었다. 고급 프로그래밍 언어가 존재하기 전에는, 그것은 컴퓨터 전문가 및 애호가들에게 독점적인 영역이었다. 그리고 종종 전임하는 직업이었다. 그러나 이제는 과학자, 기술자, 의사, 경제학자, 교사 및 많은 다른 사람들이 컴퓨테이션을 그들의 작업에 통합시킬 수 있다. 이러한 언어들 덕분에 컴퓨팅은 성가시고 난해한 학문에서 범용 목적으로 접근 가능한 도구로 발전했다. 동시에 프로그래밍의 추상화로 인해 컴퓨터 전문가들은 이제 "전문 프로그래머"로서 점점 더 정교해지는 프로그램을 만들 수 있게 되었다. 수백만, 수천 또는 그 이상의 어셈블리 코드라인을 사용해서 말이다.
사실 프로그래밍 언어의 황금시대가 시작되어 컴퓨터 하드웨어의 획기적인 진보와 함께 진화를 거듭했다. 1960년대에는 ALGOL이나 LISP, BASIC과 같은 언어를 사용해고, 70년대에는 파스칼(PASCAL), C언어 및 Smalltalk가 출시되었다. 80년대에는 C++, Objective-C, Perl이 생겼다. 그리고 90년대에는 파이썬(python), 루비(Ruby), 자바(JAVA)가, 2000년대에는 Swift, C#, Go언어가 생겼다.
지금 사용하고 있는 웹 브라우저는 C++ 또는 Objective-C로 작성되었다. 지금도 새로운 언어는 계속해서 나오고 있다. 각각의 새로운 언어는 새롭고 영리한 추상화를 활용하여 프로그래밍의 일부 측면을 보다 쉽고 강력하게 만들거나 신기술 및 플랫폼을 활용함으로써 더 많은 사람들이 보다 놀라운 일들을 더 빨리 할 수 있게 한다.
많은 사람들이 프로그래밍의 성배를 평범한 영어를 사용하는 것이라고 생각한다. 문자 그대로 우리들이 컴퓨터가 할 일을 말하면 그것을 알아내고 실행하는 것이다.
댓글