현재, 컴퓨터 공학 개론 수업 시간에 어느 프로그래밍 언어가 가장 적절한지 일치된 견해가 없습니다. 대부분의 학교는 전통적인 시스템 프로그래밍 언어인 C, C++, Java, 또는 Ada 같은 언어를 CS1 수업과 CS2 수업시간에 사용합니다. 그렇지만, Tcl과 Perl 그리고 Python 같은 언어가 점차로 인기있는 소프트웨어 개발 도구가 되고 있습니다. 이 글에서는 스크립팅 언어를 컴퓨터 과학 교과과정에 첫 언어로 사용하면 얻는 장점들에 관하여 생각해 보고자 합니다. 시스템 언어보다 스크립팅 언어가 더 간단하고 안전하며 더욱 유연합니다. 특히 파이썬은 첫 프로그래밍 언어로 가장 이상적인 후보자로 떠오르고 있습니다.
어떤 사람들은 ``언어 전쟁''은 끝났고 (유일한) 합리적인 선택은: C, C++, Java, Ada (또는 Eiffel)이라고 제안했습니다([footnote]. SIGCSE '98회의의 ``Possible Futures for CS2'' 패널 토론에서 이렇게 합의된 듯 합니다.) 나는 전쟁이 끝났다고 선언하는 것은 너무 이르게 패배를 인정하는 것이라고 믿습니다. 첫 언어에 대하여 전혀 합의가 없을 때가 바로 제일 원리로 돌아가 첫 언어가 무엇이 되면 좋은가 생각해 보기에 좋은 시간이라고 생각합니다. 그러다 보면, 가장 훌륭한 후보들이 고려되지 않았다는 것을 발견하게 될 것입니다.
이 논고에서는 아주 높은-수준의 스크립트 언어인 Python, Perl, Tcl, Rexx, 그리고 Visual Basic이 첫 언어로 더 좋은 후보라고 주장합니다. 특히, 파이썬은 거의 이상적인 언어입니다.
첫째, CS1/CS2 교과과정은 근본적으로 컴퓨터 프로그래밍에 관한 것입니다. 분명히 이런 강의들은 컴퓨터 과학 이론과 실제의 문제들을 더 넓게 다루고 있지만, 이런 첫 수업에서 컴퓨터 과학의 핵심은 여전히 문제-해결과 디자인 그리고 프로그래밍입니다. 프로그램하는 법을 배우는 것은 손수 참여하는 활동입니다. 그리고 이런 수업들은 열린 랩 설정 또는 닫힌-랩 설정에서 다양한 크기의 디자인과 프로그래밍 프로젝트가 관련됩니다.
둘째, 프로그래밍 언어는 본질적으로(per se) 이런 수업에서 초점이 아닙니다. 학생들이 종종 이런 수업들을 ``C++ 수업''이나 ``Java 수업''이라고 언급하지만, 그 강좌들은 컴퓨터 과학의 분야를 소개하도록 디자인되어 있습니다. 사용되는 언어는 실제로는 부차적인 문제입니다. CS1 수업을 특정 언어에 대한 소개시간이라고 인식하는 경향은 사용되는 그 언어가 보통 복잡하기 때문입니다.
셋째, 이런 수업들은 문제 해결과 디자인에 대하여 오늘날 사용중인 기본적인 패러다임을 학생들에게 소개합니다. 즉, 명령적(서술문-지향적) 언어로 구현된 구조화된 방법론과 객체-지향적 방법론을 소개합니다. 다른 접근법을 강력하게 주장하는 사람도 있지만(예를 들어, 첫 수업에 기능형 언어를 사용하자는 것), 대다수의 개론 수업에서는 전통적인 길을 따르는 경향이 많습니다.
넷째, 아마도 가장 논쟁이 될 것 같은데, 나는 CS1 수업의 목적이 컴퓨터 과학도들을 교육하고 참여시켜서, 새로운 과학도를 보충하는 것이 아닐까 생각합니다. 현재 졸업생들은 정보 테크놀로지를 이해해야만 하고 또 교육받은 모든 개인이 그럴 필요가 있다면, CS1을 ``쓸모없는(weedout)'' 수업으로 생각하는 것은 심각한 피해입니다. 프로그래밍은 어렵지만, 쓸데없이 더 어렵게 만들지 않도록 노력해야 합니다.
개론 강좌는 손수 실험하는 본성이 있는데 이것도 언어의 선택에 관련됩니다. 최소의 부담으로 디자인을 표현하도록 허용하는 언어는 실험과 재작성을 장려합니다. 그러므로, 그 언어는 아주 높은-수준이고 유연하여, 학생들이 신속하고 쉽게 또다른 다자인을 실험할 수 있어야 합니다. 이렇게 하면 낮은-수준의 구현 세부정보보다 알고리즘과 디자인 문제에 관하여 생각하는 것을 촉진시킵니다. 가능하면, 그 언어는 실험에 안전도 제공해야 합니다. 우리는 포인터 에러나 배열-한계 에러 때문에 불가사의하게 충돌하는 것으로부터 지켜주는 언어를 좋아합니다. 이 수준의 학생들은 에러를 추적해서 고치는 테크닉만 배웁니다; 그 언어는 학생들을 좌절시키는 것이 아니라, 학습을 도와야 합니다.
또 중요한 것은 그 언어가 추상화와 캡슐화 그리고 객체-지향 테크닉을 싸 넣어 디자인하는 현대적인 접근법을 지원해야 한다는 것입니다. 객체-기반의 디자인은 어떤 언어로도 구현할 수 있지만, 한 언어에서 객체를 지원하면 보이는 그대로 훨씬 더 직관적으로 구현할 수 있습니다. 역시, 이 덕분에 수업은 구현 세부정보보다 더 높은-수준의 개념적 문제들에 집중할 수 있습니다.
마지막으로, 한 언어의 선택에는 실용적인 고려가 있습니다. 그 언어가 널리 다양한 플랫폼으로 얻을 수 있으면 아주 바람직합니다. 비슷하게, 상아탑을 벗어난 실용주의자들이 사용하는 언어가 오직 ``수업 전용''인 언어보다 더 좋습니다. 위에 언급한 다른 기준들을 만족하기만 한다면 말입니다. 단순히 흔하게 사용되는 언어라고 해서 언어 X를 가르치는 것은 그 자체로 중요하게 고려되어서는 안 됩니다. 학생들은 앞으로 많은 언어를 배우고 사용하게 될 것입니다. 첫 강의에서 중요한 것은 그들에게 핵심적인 원리와 테크닉에 최고로 좋은 토대를 제공하는 것입니다. ``실세계''에서 마주할 다양한 언어에 채택하고 적용할 수 있도록 말입니다.
...머신은 더 빨라지고, 스크립트 언어는 더 좋아지며, 그래픽 사용자 인터페이스와 컴포넌트 골격구조의 중요성이 증가하고 인터넷이 성장하는 최근의 이런 경향 때문에 스크립팅 언어의 적용이 엄청나게 증가하였다. 이런 경향은 다음 십년동안도 계속되어 전체가 스크립팅 언어로 작성되고 시스템 프로그래밍 언어는 주로 컴포넌트들을 만드는 데만 사용하는 어플리케이션이 점차 늘 것이다.
전통적으로, 컴퓨터 과학 프로그램은 시스템 프로그래밍 언어를 스크립팅 언어보다 강조해 왔습니다. 그렇지만, 스크립팅 언어는 특히 프로그래밍 개론 수업에 수 많은 장점이 있습니다. 스크립팅 언어는 일반적으로 문법과 의미구조가 시스템 언어보다 더 간단합니다. 동적인 형정의와 해석 때문에, 스크립팅 언어는 아주 유연하며 실험을 장려합니다. 아주 높은-수준의 본성 덕분에 학생들은 구현 노력을 덜 들이면서도 보다 섬세하고 흥미로운 프로젝트들을 구축할 수 있습니다.
아마도 스크립팅 언어에 관한 무관심은 스크립팅 언어가 ``장남감'' 언어라서 범용 목적의 프로그래밍에는 적합하지 않다는 선입견으로부터 유래하는 것 같습니다. 물론 초기의 스크립팅 언어라면 맞는 말일 수도 있지만 (예, 유닉스 쉘 스크립트), 현대의 스크립트 언어에는 맞지 않는 말임이 분명합니다.
if (x < 0) cout << "x was negative"; x = -x;
파이썬에서 상응하는 코드는 예상대로 실행됩니다. 들여쓰기 그 자체가 블록을 결정하기 때문입니다:
if x < 0:
print "x was negative"
x = -x
파이썬은 함수와 클래스의 사용을 지원하지만 그것을 강요하지는 않습니다. 간단한 프로그램은 정말 간단합니다. 예를 들어, 파이썬으로 어디에서나 볼 수 있는 ``Hello World'' 프로그램을 만들어 봅시다:
print "Hello World!"
C++은 이 프로그램을 한 함수에 포장해 넣기를 요구하며 전처리 명령어가 앞에 옵니다:
#include <iostream.h>
int main()
{
cout << "Hello World!";
}
자바에서 상황은 더욱 더 나쁩니다. 모든 코드가 한 클래스 안에 있어야 하기 때문입니다:
public class helloWorld
{
public static void main(String [] args)
{
System.out.println("Hello World!");
}
}
의미구조적으로도 파이썬은 간단합니다. 파이썬은 동적으로 형이 정의됩니다. 그래서 변수 선언이 필요없습니다. 이 덕분에 학생들이 작성해야 할 코드 양이 줄어들고 또한 선언과 정의 그리고 사용 사이의 미묘한 차이를 오해함으로써 야기되는 흔한 에러들이 제거됩니다. 예를 들어, C++과 Java에서 학생들은 종종 실제로 사용할 곳에서 ``우발적으로'' 변수들을 재선언합니다. (count = 0를 뜻하면서 int count = 0;를 타자하는 것). 그런 실수들은 추적해 내기가 아주 어렵습니다.
파이썬은 최소한으로 작지만 완벽하고 간단한 제어 구조를 갖추고 있습니다: 한 개의 선택 구조 (if-elif-else), 한개의 유한 회돌이 (for) 그리고 한 개의 무한 회돌이(while)가 있습니다. 파이썬은 또한 C++과 Java의 예외처리 매커니즘과 비슷한 현대적인 예외 처리 메커니즘이 있습니다. 그렇지만, Java와는 다르게 간단한 프로그램을 작성하기 위하여 그 예외 메커니즘을 이해할 필요가 없습니다. 교육학적 관점에서, 파이썬의 for 회돌이는 그 예입니다. for 회돌이에서 제어 변수 하나가 연속열에서 값들을 연속적으로 취할 수 있습니다. 리스트(배열) 또는 문자열 같은 어떤 연속열도 회돌이하는데 사용될 수 있습니다. 예를 들어, 리스트에서 항목은 다음과 같이 인쇄가 가능합니다:
for item in List:
print item
range 연산은 주어진 범위에서 일련의 숫자들을 생산합니다. 예를 들어, range(5)는 [0,1,2,3,4]의 리스트를 생산합니다. 수치로-통제되는 회돌이를 제공하는데 이것을 사용할 수 있습니다. 앞의 코드는 (대충) 다음과 같이 작성할 수 있습니다:
for i in range(len(List)):
print List[i]
for 회돌이는 간단하고 안전해서, 아주 일찍 무한 회돌이라는 공포 없이 소개할 수 있습니다.
파이썬은 한가지 형태의 간단한 데이터 모델이 있습니다. 변수들은 언제나 힙에 할당된 값들(객체)에 대한 참조입니다. 데이터 모델은 일관성이 있어서, C++에서 힙 대 자동 변수 사이의 혼란 또는 자바에서 원자명령어(primitive) 대 객체 유형 사이의 혼란이 없습니다. 이 두 언어 모두 상대적으로 단순한 프로그램을 구현하는 것조차도 다중 할당 모델을 가르치기를 요구합니다.
비슷하게, 파이썬은 (값으로) 매개변수 건넴 메커니즘이 오직 하나입니다. 매개변수를 건네려면 그냥 호출 시간에 형식 매개변수에 실제로 할당하기만 하면 됩니다. 학생들은 이 간단한 할당 모델을 이해하면, 매개변수 건넴을 공짜로 배울 수 있습니다.
시스템 개발이라는 관점에서 파이썬의 한가지 약점은 캡슐화가 기껏해야 관례를 통하여 강제될 뿐이라는 것입니다. 클래스 멤버를 숨기도록 지정하는 메커니즘이 없습니다. 교육적으로, 이것은 중대한 약점이 아닙니다. 왜냐하면 데이터-감춤의 원리를 설명하는 것이 여전히 가능하기 때문입니다; 단지 파이썬 언어에서 강요하지 않을 따름입니다. 파이썬은 우아하면서도 단순함을 유지하는 메커니즘을 제공합니다. C++이나 Java에서는 반드시 다루어야 하는 다양한 "가시성 모드"라는 복잡성을 피할 수 있습니다.
파이썬의 동적인 형정의 모델 덕분에 데이터 구조 수업시간에 그릇 클래스를 공부하는데 특히 편리합니다. 예를 들어, 스택 클래스는 객체 유형에 상관없이 저장하는데 사용될 수 있습니다. 정수 스택도 될 수 있고, 실수 스택, 문자열 스택, 또는 혼합 유형들의 스택이 될 수 있습니다. 이렇게 하기 위해 총칭성(주형틀)을 도입할 필요도 없으며 또는 동적인 강제 형변환을 수행할 필요도 없습니다. 그림 1은 간단한 유한 스택 클래스를 정의한 예입니다.
class Stack:
def __init__(self,size):
self.data = [None]*size
self.size = 0
def push(self,item):
self.data[self.size] = item
self.size = self.size + 1
def pop(self):
self.size = self.size - 1
return self.data[self.size]
def is_empty(self):
return self.size == 0
def is_full(self):
return self.size == len(self.data)
파이썬은 깔끔한 모듈 시스템도 제공합니다. 자바와 비슷하게 실행-시간에 동적으로 파일을 적재합니다 (단, 성가신 꾸러미 조직 제한들은 빼고 말입니다). 이 덕분에 C++의 헤더 파일과 전처리 지시어들 없이도 프로젝트들을 모듈 단위로 쉽게 관리할 수 있습니다 (Laird & Soraiz, 1998a). 스택 구현은 도입(import) 서술문을 통하여 사용할 수 있습니다:
from bstack import Stack
myStack = Stack(100)
myStack.push("Hello")
다른 구현으로 교체하는 것은 그냥 그 모듈의 이름을 도입 서술문에서 바꾸어 주기만 하면 됩니다.
Pascal, C++, 그리고 Java 같은 언어를 가르쳐 본 경험에서 나는 확신했습니다. 초보 프로그래머에게 컴파일-시간 에러 점검이라는 장점들은 허상일 뿐입니다. 첫째, 컴파일러가 탐지하는 에러의 대부분은 아주 평범한 것입니다 (예를 들어, 수 없이 빼먹는 ";"). 파이썬 같은 언어는 이런 흔한 에러들을 더 간단한 구문을 통하여 대부분 제거합니다. 게다가, 나머지 순수한 구문 에러도 대부분 파이썬 인터프리터가 즉시 보고할 것입니다. 파이썬은 프로그램의 구문을 적재시에 분석합니다. 둘째, 컴파일 시간에 더 미묘한 에러들을 잡아내는 것은 별로 이점이 없습니다 (예. 유형 비호환). 흔한 유형 에러는 선언과 사용이 불일치할 때 야기됩니다. 이런 에러들은 대부분 선언에서의 에러일 뿐입니다. 선언이 없는 언어에서, 이런 에러들은 일어나지 않습니다. 그 에러가 한 유형이 어떻게 사용되는가에 관한 순수한 에러이면, 그 에러는 동적으로-형정의되는 언어에서도 잡힐 것입니다. 단지 그 에러가 실행-시간에 진단되고 나포되는 것이 다를 뿐입니다. 전형적으로 첫 두 CS 수업에서 작성되는 프로그램 유형에 대하여, 컴파일-시간 점검은 별로 장점이 없습니다. 편집-해석 주기라는 단순함이 컴파일 시간에 여러 에러를 찾아내는 장점을 훨씬 더 능가합니다.
컴파일-시간 점검은 실제로 두 가지 면에서 학생들에게 해로울 수 있습니다. 첫째, 사기를 떨어뜨립니다. 학생은 먼저 구문적으로 완벽한 프로그램을 가진 다음에야 결과를 얻을 수 있습니다. 프로그램을 컴파일하면서 불쾌한 메시지로 가득한 화면을 바라보는 일은 따분하고 짜증나는 활동입니다. 인터프리터 언어에서는, 적어도 무엇인가는 나타납니다; 작성한 프로그램은 에러 때문에 멈추기 전에 부분적으로 출력결과를 만들어냅니다. 학생은 그 프로그램이 (부분적으로) 작동하는 것을 보면서 에러를 한 번에 하나씩 수정하면 됩니다. 고칠 때마다 더 나아갑니다. 이것이 훨씬 더 장려할 상황입니다.
격렬한 컴파일-시간 점검의 두 번째 단점은 학생들이 철저함(thoroughness)이라는 환상에 빠진다는 것입니다. 학생들은 프로그램이 컴파일되면, 아주 올바를 것이라고 믿습니다. 이런 증상은 부적절한 테스트로 나타납니다. 또다른 문제는 디자인 에러의 탐지를 지연시킨다는 것입니다. 나의 경험에 비추어 보면, 학생들은 상당한 시간을 프로그램에 투자하고 알아내지 못하는 버그가 단 하나만 있기 때문에 거의 다 끝났다고 느끼는 경우가 빈번합니다. 그러나 그 한가지 작은 버그가 컴파일 에러임이 밝혀집니다. ``거의 끝나기는 커녕'', 과제는 두 시간에 마쳐야 하는데 프로그램 컴파일조차도 마치지 못합니다! 자신의 해결 로직에서 중대한 결점을 발견할 기회가 거의 없습니다. 인터프리터 언어에서, 에러를 발견하는 일은 테스트와 함께 진행됩니다; 유형 에러가 있더라도 더 심각한 디자인 에러의 발견을 막지 않습니다.
어떤 경우든 실행 효율에 대한 이런 걱정은 잘못입니다. 프로그래머의 시작은 보통 생산 코드를 작성하는 것이 아닙니다. 그들의 프로그램은 보통 시간에 제약이 없으며 기껏 몇 번 실행될 뿐입니다. 효율에서 진정한 걱정거리는 그 프로그램을 개발하는데 드는 시간의 양입니다. 이곳에서 스크립트 언어가 찬란하게 빛을 냅니다. 스크립트 언어는 편집/해석 주기가 빠르고, 선언이 없으며, 그리고 본성상 높은-수준이기 때문에 이런 환경에서 완벽한 도구가 됩니다.
문제는 이제 어느 언어가 첫 수업의 언어가 되어야 하는가? 첫 수업에서 C++, Java 또는 Ada 같은 언어를 가르치자는 주장은 이런 언어들 그 자체로 매우 복잡하고 어려워서 학생들이 충분한 시간을 가지고 정복하기 위해 곧바로 그 언어들을 배울 필요가 있다는 것입니다. 이 주장은 앞뒤가 맞지 않습니다. 첫 수업은 언어에 관한 것이 되어서는 안됩니다. 오히려 컴퓨터 과학에 관한 것이 되어야 하며, 근본적으로 디자인에 관한 것이 되어야 합니다. 복잡한 언어를 가르치려고 하면 필연적으로 그 목표로부터 멀어집니다. 왜냐하면 학생들은 더 많은 시간을 들여 그 언어를 정복해야 하고, 그러므로, 다른 것들을 정복할 시간이 그 만큼 더 줄어듭니다. 이 때문에 어떤 교육자들은 C++을 대신할 더 간단한 대안이 자바라고 생각합니다. 그러나 자바도 역시 파이썬에 비하면 아주 복잡합니다.
보다 합리적인 접근법은 디자인을 먼저 가르치고, 학생들에게는 간단하지만 강력한 언어로 시작하도록 하는 것입니다. 프로그래밍과 디자인을 제대로 이해하면 정적 유형정의, 가시성, 총칭성과 다형성 같은 개념들을 훨씬 더 쉽게 이해할 수 있습니다. 상상 실험을 해 봅시다. helloWorld Java 프로그램의 각 부분의 의미를 초보 프로그래머에게 실제로 설명한다고 생각해 봅시다. 그 학생들이 이미 함수, 클래스, 실제 변수, 클래스 변수, 데이터 유형과 배열을 알고 있다면, 학생들에게 public, class, static, void, 그리고 String [] 같은 개념들을 설명하기가 얼마나 더 쉬울까 상상해 봅시다. 시스템 언어의 더 복잡한 구조들은 (예. C++ 주형틀, 가상 메쏘드, 동적 형변환(casts)) 실제로는 정적으로 형정의되는 작업틀 안에서 동적인 언어가 제공하는 유연성을 얻기 위한 메커니즘입니다. 왜 개념들을 먼저 가르치지 않습니까? 그 개념들을 표현하기 위해 복잡함을 요구하지 않는 언어로 말입니다. 이학년-수준의 원리들을 다루는 프로그래밍 언어 수업이나 시스템 프로그래밍 수업이 시스템 언어의 복잡성을 다루기에 더 적절한 곳이라고 생각합니다.
이 글은 자바로 전환을 고려하고 있는 분들에게 주의를 드립니다. 언어를 전환할 생각이라면, 전환해야할 동기를 세심하게 살피시기 바랍니다. 교육학적으로 고려하면 시스템 언어로부터 스크립팅 언어로 이주할 명분이 서고, 파이썬이 아주 훌륭한 선택입니다. 필요한 것은 몇몇 담대한 사람들이 파이썬을 들고 뛰어들어 적절한 재료들을 개발하는 것입니다. 아마도 인기있는 파이썬 교과서를 개발하기로 마음 먹은 저자들이 있을 것입니다.
Scheme의 약점은 교과과정 다른 곳에서 사용되는 시스템 언어와 상당히 다른 외톨이 언어로 인식된다는 것입니다. 이 때문에 인기가 CS1 수업에 머물고 맙니다. 파이썬은 Scheme의 장점들을 많이 이어받으면서도 여전히 C++, Java, 그리고 Ada 같은 시스템 언어와 비슷하여, 쉽게 그런 언어로 이주할 수 있습니다. 여러 프로그래밍 패러다임을 첫 수업에서 경험하고 싶은 학생들을 위하여, 파이썬은 기능적 스타일의 프로그래밍을 지원합니다. 여기에는 제일-순위 함수들, map, apply, lambda 그리고 울타리(closures)1)가 포함됩니다.
학생들에게 주지시키고 싶은 한가지 주요한 개념은 주어진 일에 적당한 도구를 사용하라는 아이디어입니다. 한 고객이 나에게 와서 아주 짧은 시간 안에 프로그램을 작성해주기를 요구한다고 해 봅시다. 그 프로그램은 시간에 구애받지 않고 메모리에 제약이 없으며, 일단 완성되면 몇 번만 실행할 요량입니다. 그렇다면, 나는 즉시 적절한 도구로 스크립팅 언어를 제안하겠습니다. 대부분의 CS1 수업과 CS2 수업시간이 바로 이러한 상황 아래에서 프로그래밍이 진행됩니다. 모듈방식의 프로그램 디자인과 객체-지향 프로그램 디자인을 훌륭하게 제공하는 파이썬 같은 스크립팅 언어가 존재한다면, 그것을 사용하지 말아야 할 좋은 이유가 없습니다. 스크립팅 언어가 개론 시간에 가장 적절한 도구입니다. 현재 유일한 첫 언어에 합의가 없지만, 이 때가 바로 스크립팅 언어로 이주하기 시작할 좋은 시간입니다. 개론 수업에 파이썬의 사용을 고려해 봅시다.
Laird, C., Soraiz, K., (1998). Get a Grip on Scripts, Byte, June, pp. 89-96.
Lutz, M., (1996). Programming Python, O'Reilly & Associates, Inc.
McCauley, R. and Manaris, B., (1998). Computer Science Programs: What Do They Look Like? Proceedings of the 29th SIGCSE Technical Symposium on Computer Science Education, February, pp. 15-19.
Ousterhout, J., (1998). Scripting: Higher Level Programming for the 21st Century, IEEE Computer, March.
Watters, A., van Rossum, G., Ahlstrom, J., (1996). Internet Programming with Python, M & T Books, New York, New York.