어떤 프로그래밍 언어도 혼자서 굴러가지 않는다. 프로그래밍 언어로 코드를 짰다면, 코드를 실행하기위한 과정을 거쳐야한다
우리와 컴퓨터의 의사소통 방식에 대해 이해하기 위해선 몇가지 개념에 대한 설명이 필요하다.
첫번째는 바로 'Low-level Language' & 'High-level Language' 즉 '저레벨 언어'와 '고레벨 언어'이다.
간단하게 저레벨 언어는 컴퓨터가 알아듣기 쉬운 언어이고, 고레벨 언어는 우리(개발자)가 알아듣기 쉬운 언어이다.
가령 우리는 인사할때 안녕?
이라고 하지만 컴퓨터는1011001101101
뭐 이런식으로 할거다. 왜냐면 컴퓨터는 이진법을 사용하기 때문이다.
이때 1011001101101
에 가까운 언어일수록 저레벨 언어
라고 한다.
문제는 인간은 10진법을 사용하고 무엇보다 '문자'를 사용한다.
이런 인간이 이진법을 배워서 1011001101101
이런 식으로 컴퓨터와 대화를 시도하기엔 애로사항이 많다. 때문에 우리는 프로그래밍 언어를 만들었다.
프로그래밍 언어는 컴퓨터에 가깝게 '기호화'한 언어라고 볼 수 있다.
결국 컴퓨터와 인간 사이에 애매한
String str = "Hello";
이런 언어를 프로그래밍 언어라 칭한다.
하지만 컴퓨터는 여전히 알아듣지 못한다.
왜냐면 컴퓨터는 정말 1011001101101
이런 이진법 밖에 모르기 때문이다.
그렇기 때문에 우리는 또 한번 번역과정을 거쳐야한다.
이를 컴파일
혹은인터프리팅
이라고 한다.
컴파일러와 인터프리터의 차이는 그럼 뭘까?
일단 설명안해도 알겠지만 Compiler & Interpreter는 컴파일링
혹은 인터프리팅
을 실행하는 장치이다.
이때 이 장치 즉 응용 소프트웨어를 제어하는 방식이 컴파일
이냐 인터프리트
냐에 따라 해당 제어 언어도 인터프리터 언어
인지, 컴파일 언어
인지 나누어진다.
요즘은 이런식의 언어분류가 점점 의미없어지기도 한다. 왜냐면 언어가 발전함에 따라 컴파일 인터프리트 둘 다 지원하는 언어도 생기기 때문
컴파일러
는 우리가 작성한고레벨 소스코드
를 한번에 번역 한다.
때문에 빌드 과정프로그램을 실행시키기 위한 목적 파일을 만드는 과정
을 하는데 비교적 시간이 걸리지만, 모든 고레벨 소스코드를 한번에 번역하기 때문에 최적화에 용이하다. 또한 강력한 정적 타입의 언어로 코드를 짤 경우 "컴파일이 된다면 버그는 없다" 할 정도로 컴파일
과정은 코드상의 많은 오류들을 체크하고, 직접 수정하거나, 컴파일을 중지하고 에러를 띄워 잘못된 코드의 동작을 미연에 방지한다. 이런 컴파일 방식을 정적 컴파일이라 하기도 한다.
인터프리터의 핵심은 실행기라는 것이다.
즉 번역기
인 컴파일러
와는 다르게 인터프리터
는 빌드 과정이 없이 바로 코드를 한줄 한줄을 읽어내리며 번역하고 분석하고, 실행한다. 때문에 최적화가 어렵고, 그렇기에 실행속도가 느리다.
최적화와 관련하여 예를 한번 들어보자. 혹시 논문이나 레포트같은 비교적 많은 양의 글을 번역해 본적 있는가? 아니면 책 한페이지도 괜찮다.
우리는 번역을 진행하면서도 앞뒤 문맥, 글의 분위기 등에 따라 이미 번역한 부분을 좀 더 매끄럽게 다듬기도한다. 이는 전반적인 글의 흐름을 알 수 있어야 가능하지만, 좀 더 이해하기 쉽게(최적화된) 번역을 할 수 있다.
// 컴파일러(정적 컴파일)
반대로 만약 누군가가 한 줄씩 나에게 번역하라고 건내준다고 가정해보자.
우리는 앞뒤 문맥 등 전반적인 부분을 모르기 때문에 매끄러운 번역은 쉽지 않을것이고, 이는 독자(컴퓨터)도 이해하기에 애로사항이 있을것이다.
// 인터프리터
- 빌드 과정이 없다
즉 결과를 바로 확인할 수 있다는 것이 인터프리터
의 최대 이점이다.
이는디버깅
등 개발의 편의성이라는 측면에서 상당한 이점으로 작용한다. 컴파일러
를 사용한다면 프로그래밍을 할때 신중할 수 밖에 없는데, 프로그램이 크면 클수록, 코드를 다시 수정하고 빌드(컴파일) 하는 과정이 굉장히 번거로워지기 때문이다.
하지만 인터프리터
를 사용한다면 픽스&체크를 거의 동시에 할 수 있기 때문에 무지성 코딩 가능 디버깅
시 훨씬 편리하다.
디버깅이 편리하다는 점은 단순 수정 과정에서의 이점이다.
만약 코드에 뭔가 문제가 있다면, 인터프리터 방식은 문제를 찾기 매우 힘들어진다. 이는 인터프리터 방식을 지원하는 언어들이 동적 타입의 언어들이기 때문인데, 컴파일 과정이 아닌 실행과정에서 변수의 타입이 변화할 수 있기 때문에
프로그램을 실행하다 오류가 발생하는 상황이 비교적 많이 생길 수 있다. 더해서 오류가 어디서 일어났는지 찾는것도 비교적 쉽지 않다. 이는 마냥 인터프리터 언어가 유지보수에 유리하다고 말 할 수 없는 이유이다.
위의 내용을 보면 변화가 적은 환경 즉 특정 하드웨어를 구동시키는 프로그램에서는 컴파일 언어를 사용하는게 소프트웨어의 성능 측면에서 유리할거고, 만약 브라우저 같이 변화가 많은 환경에서는 인터프리팅 언어를 사용하는 것이 성능은 불리할지 몰라도 유지 및 보수에 유리할 것이다.
다음으로는 많은 사람들이 헷갈려하는 부분인 스크립트 언어
와 인터프리트 언어
에 대해 알아보자.
스크립트 언어와 인터프리트 언어는 별개다.
스크립트 언어는 그 용도가 주로 운영체제 위에서 움직이는 새로운 프로그램을 만드는 것보다는, 기존에 존재하는 어떤 다른 프로그램들을 제어하기 위해 쓰이며 그 기존의 프로그램들 위에서 구동이 지원되는 언어들을 뜻한다. 웹 브라우저에서 구동이 지원되는 JavaScript
나,참고로 대표적인 브라우저인 크롬은 c++로 만들었다.
플래시를 제어하기 위해 플래시에서 구동이 지원되는 ActionScript
등이 대표적인 스크립트 언어이며. 다른 프로그램을 제어하기위해 사용하다보니, 수정이 용이한 인터프리터 방식을 주요 사용한다.
많은 사람들이 스크립트 언어와 인터프리트 언어를 혼용하여 사용하는 경우가 많다. (나만 그랬을 수도 있다.)
하지만 위에서 설명했듯 스크립트 언어는 이미 존재하는 소프트웨어를 제어하기 위한 용도로 쓰이는 언어이다. 단지 그 용도에 인터프린터 방식
이 유리하기 때문에 인터프린터 방식
을 사용하는것 뿐이다.
즉 스크립트 언어는 인터프리팅 언어가 될 수 있지만, 모든 인터프리팅 언어가 스크립트 언어인 것은 아니다.
하지만 위에서 위에서 스크립트 언어로써 언급된 JavaScript를 봐도 웹 환경이 고도화, 표준화되고 Node.js 런타임이나 Electron 등이 등장함에 따라 그 자체만으로도 독립적인 프로그램 개발에 사용될 수 있도록 발전됨에 따라 이를 단순히 웹 브라우저용 제어 언어라고만 정의할 수가 없게 되었다. 더 나아가 TypeScript나 CoffeeScript처럼 컴파일 결과물로 기계어가 아닌 JavaScript를 출력해서 동작하는 언어까지 등장했다.
결론적으로 초창기 프로그래밍 언어론 교과서가 쓰였던 시절과는 달리 프로그래밍 언어들이 고도로 발달하고 높은 수준의 추상화가 진행됨에 따라 단순하게 어떤 언어와 그 언어가 동작하는 런타임을 뭉뚱그려서 '이 언어는 XX형 언어이다'라는 식으로 정의하는 것 자체가 무의미해져가는 추세에 있다.
그럼 대표적인 스크립트 언어인 JavaScript를 실행하는 JavaScript Engine은 인터프리터일까?
🔥 컴파일러는 번역기 / 인터프리터는 실행기이다.