VBScript 5.6과 클래스(Class)

등록일시: 2002-06-19 12:31,  수정일시: 2018-04-07 23:17
조회수: 17,324
본문은 최초 작성 이후, 약 22년 이상 지난 문서입니다. 일부 내용은 최근의 현실과 맞지 않거나 동떨어져 있을 수 있으며 문서 내용에 오류가 존재할 수도 있습니다. 또한 본문을 작성하던 당시 필자의 의견과 현재의 의견에 많은 차이가 존재할 수도 있습니다. 이 점, 참고하시기 바랍니다.

근래 들어 클래스(Class)라는 개념 그 자체는 프로그래밍 언어의 종류를 막론하고 대다수의 프로그래머들에게 보편적인 개념이 되어버린 것 같다. 물론, 클래스에 관해서 깊은 수준까지 접근하고자 한다면야 필자 같은 초보는 명함도 내밀기 힘든 어려운 분야인 것 또한 사실이지만, 대략적으로 개념을 파악하는 정도의 수준을 두고 하는 말이다.

사실, 솔직하게 말해서 ASP 프로그래밍에 반드시 클래스를 도입해야 할 필요는 없다고 생각한다. 클래스는 다분히 객체 지향적 프로그래밍(OOP, Object Oriented Programming)에 속한 주제고, 객체 지향적 프로그래밍은 일종의 방법론이며, 본질적으로 방법론이라는 것은 주어진 문제를 해결하는 방법의 효율성과 관련된 것으로서 문제 자체를 해결할 수 있느냐 없느냐 하는 것과는 어느 정도 거리가 있는 내용이다. 현실적인 관점에서 바라봤을 때, ASP 프로그래밍에 클래스를 도입한다고 해서 그 전에는 해결할 수 없었던 문제의 처리가 가능해진다든지 ASP 프로그램의 실행 속도가 비약적으로 향상된다든지 하는 일은 절대로 일어나지 않으며, 단지 약간의 편리함과 함께 프로그램 전반에 걸쳐 일부 진보된 데이터 구조를 접할 수 있을 뿐이라는 뜻이다.

조금 더 극단적으로 얘기해보자면, 지금까지 대다수의 ASP 프로그래머들은 굳이 클래스를 사용하지 않고서도 뛰어난 수준의 많은 프로그램들을 작성해왔으며, 필자 역시도 클래스를 그다지 자주 사용하는 편은 아니다. 단, 유일하게 클래스의 사용이 절대적인 경우가 있는데 바로 Remote Scripting을 사용하는 경우다. 이 Remote Scripting에 관해서는 추후 자세히 설명하도록 하겠다.

필자의 개인적인 경험으로도 주변에서 필자 이외의 프로그래머가 업무상 프로그램을 작성하면서 클래스를 사용한 사례를 접해본 것은 정확하게 단 두 번 뿐이었다.

그 중 한 번은 ASP 프로그래밍에 익숙하지 않은 어떤 프로그래머가 서블릿 프로그램을 ASP로 포팅하면서 단순하게 일대일 맞대응 방식으로 서블릿, 즉 Java의 클래스를 VBScript의 클래스로 변환했던 경우였고, 다른 두 번째 경우도 단지 서블릿이 아니라 PHP였다는 차이점만 있었을 뿐 처음의 사례와 대동소이한 경우였다. 물론, 포팅이라는 관점에서 봤을 때 두 경우 모두 최적화된 ASP 프로그램으로 포팅되지는 않았었지만, 필자로서는 개인적으로 서블릿 프로그래머들과 PHP 프로그래머들이 웹 프로그래밍에서의 클래스를 바라보는 시각을 간접적으로나마 경험해 볼 수 있었던 좋은 경험이었다.

구조적인 관점에서 봤을 때, 애시당초 절차적 언어인 ASP에서 이런 한계를 드러내는 것은 어찌보면 매우 당연한 일이라고 말할 수 있을 것이다. 따라서, 좀 더 근본적으로 이런 한계를 극복하고 싶다면 ASP가 아닌 ASP.NET을 통해서 그 해결 방안을 모색하는 것이 올바른 접근 방법이 아닌가 한다. 그 기반 언어 자체가 객체 지향적인 고려 없이 구현된 상황에서 아무리 클래스를 사용하여 훌륭한 데이터 객체를 구현해낸다고 한들 결국 얻을 수 있는 성과는 반쪽짜리일 수 밖에 없을 것이다.

결론적으로 필자가 VBScript에서 제공해주는 클래스 기능에 대해서 잠정적으로 내린 결론은 이렇다. 클래스를 ASP 프로그램에 도입하는 것은 편의에 따른 선택일 뿐 필수적인 사항은 아니며, 객체 지향적 프로그래밍의 관점에서가 아닌 유용한 유틸리티라는 시각으로 이해하는 편이 보다 현실적이라는 것이다.

이제 논점을 VBScript가 제공해주는 클래스의 기능 그 자체로 좁혀보도록 하자. 아마도 VBScript의 클래스에서 제공해주는 기능의 수준이란 여러분들이 기대했던 바에는 크게 못미칠 가능성이 높다고 생각된다.

가령, 생성자(Constructor)와 파괴자(Destructor)에 해당하는 Initialize 이벤트와 Terminate 이벤트가 존재하기는 하지만 객체 생성시 초기화가 불가능하다는 결정적인 단점이 있다. 이는 C++이나 Java에서 지원해주는 생성자의 경우, 프로그래머가 자유롭게 정의할 수 있는 프로시저의 형식을 가지고 있는 반면, VBScript의 클래스에서 지원하는 생성자는 프로그래머가 재정의조차도 할 수 없는 이벤트의 형식을 가지고 있기 때문인데, 이런 단점을 보완하기 위해서는 Initialize 이벤트와는 별도로 초기화 작업을 수행하는 프로시저를 하나 더 작성해야만 한다.

그리고, 기본적으로 추상성(Abstraction)과 은닉성(Encapsulation)만 지원될 뿐, 보다 고급 기술의 기본이 되는 상속성(Inheritance)이나 다형성(Polymorphism)은 전혀 지원되지 않으며, 따라서 Java나 .NET에서는 매우 일상적으로 접할 수 있는 인터페이스(Interface)와 같은 기술 역시도 애초부터 지원되지 않는다. 개인적으로는 Microsoft Visual Basic 6.0에서 지원해주는 Implements 문이나 아니면 그와 비슷한 작용을 하는 다른 기능이라도 지원되었더라면 하는 아쉬움을 갖고 있다.

클래스에서 상속이 불가능하다는 것은 사실상 매우 치명적인 단점이다. 예를 들어, 쇼핑 카트에 들어가는 각각의 상품들을 클래스로 구현하는 경우를 가정해보자. 만약 상속성이 지원된다면, 먼저 모든 상품들의 공통적인 필수 항목들만으로 부모 클래스를 구현하고, 실제 상품들을 구현하는 클래스는 이 부모 클래스에서 상속을 받아 종목별 특징만을 추가적으로 구현하면 된다. 이는 거의 교과서적인 내용이다. 그러나, VBScript 클래스에서는 상속성이 지원되지 않으므로 모든 종류의 상품마다 각각 따로따로 클래스를 구현해 줄 수 밖에는 없는 것이다. 더군다나, 상속성의 지원없이는 다형성까지도 구현이 불가능하다는 점을 고려해 본다면 이것이 얼마나 치명적인 단점인지 잘 알수 있을 것이다.

그러나, 일부 특수한 상황에서는 오히려 클래스 외에는 별다른 대안이 없는 경우도 있다. 그 가장 대표적인 경우가 바로 Remote Scripting을 사용할 때다. 이 Remote Scripting은 HTML 페이지를 갱신(Refresh)하지 않고서도 서버에 위치한 프로시저를 호출하고 그 실행 결과를 가져오거나 서버에 위치한 변수의 값, 예를 들어 Application 객체나 Session 객체의 특정 변수의 값 등을 얻어올 수 있는 기술이다. RDS와는 달리 브라우저의 종류에 영향을 받지 않으므로 Netscape에서도 무리 없이 사용이 가능하고 서버에는 최소한의 부하만 걸리는 특징을 가지고 있다. ASP.NET의 포스트백(Postback)과는 그 접근 방식이 다르므로 오해가 없기를 바란다.

간략하게 살펴보자면 Remote Scripting은 구조적으로 크게 두 부분으로 구성되어 지는데, 그 중, 서버쪽 부분에는 VBScript 클래스로 작성된 ASP 파일이 위치하게 되고, 클라이언트쪽 브라우저에는 대략 5K 정도의 눈에 보이지 않는 Java 애플릿이 위치하게 된다. 바로, 이 두 부분 중 서버쪽 부분을 구성할 때 클래스가 반드시 필요한 것이다. 그게 마음에 들지 않는다면 그 부분을 아예 JScript로 구성하는 방법 외에는 다른 대안이 없다. Remote Scripting에 관한 보다 자세한 설명은 클래스에 대한 기본적인 설명이 모두 끝난 후 클래스를 활용하는 실례로서 별도의 글을 마련하도록 하겠다.

클래스가 유용한 또 다른 경우는 ASP 프로그램을 작성하면서 C 또는 C++의 구조체에 해당하는 무언가가 필요할 경우다. Visual Basic 6.0에서는 이와 유사한 목적에 사용하기 위한 Type 문이 지원되지만 ASP 프로그램에서는 클래스만이 그 유일한 대안이다. 만약, 서로 연관성을 갖고 있는 수 개에서 수 십개의 변수를 임의의 함수에 일일이 인자로 넘기거나 하고 싶은 마음이 없다면 충분히 고려해볼만한 선택이다. 현재까지는 이런 경우, 대부분 Dictionary 객체를 사용하곤 했지만 Dictionary 객체를 사용하는 경우에는 클래스에서와 같은 멤버 함수를 사용할 수 없고 접근 지정이 불가능하다는 단점이 있었다.

그리고, 한 프로젝트에 다수의 개발자가 투입되었고 이 때 Include해서 사용하는 파일의 수가 꽤 많거나 구조적으로 복잡하다면, 그런 경우에도 각각의 Include 파일들을 클래스로 구현하는 것을 고려해볼만하다고 생각한다. 물론, Include 파일들의 내용을 단순히 클래스로 구현한다고 해서 실행 속도가 빨라진다거나 하지는 않는다. 이 경우 개발자가 얻을 수 있는 직접적인 이점은 각각의 클래스들이 일종의 네임스페이스와 같은 역활을 하여 변수와 각종 프로시져들의 관리를 용이하게 도와주며 예상치 못한 부작용을 큰 노력 없이도 최소화시켜준다는 것이다.

이 말이 잘 이해되지 않는다면, 여러분들의 ASP 프로그램과 Include 파일들의 내부 곳곳에서 빈번하게 정의되고 또 사용되고 있는 변수 i나 j 등을 머리 속에 떠올려보기 바란다. 개발자 한 명이 전체 프로그램을 개발할 때와는 달리 다수의 개발자가 아무런 규정도 없이 변수명으로 i나 j 등을 남발할 경우 각각의 Include 파일들이 한 곳에 집합되면 부작용이 일어날 가능성이 매우 높아진다.

더군다나 변수 선언을 강제하는 Option Explicit 문조차도 사용하지 않은 상태에서, 설상가상으로 ASP 프로그램과 Include 파일들의 여기저기에 On Error Resume Next 문까지 사용한 상태라면 추후 디버그 자체가 곤란해질 정도로 문제가 매우 복잡해진다.

VBScript의 클래스가 도움이 되는 가장 중요한 또 한 가지 경우는 바로 학습적인 측면이다. 당연한 얘기일지도 모르겠지만 VBScript의 클래스와 Microsoft Visual Basic 6.0의 클래스 모듈은 그 문법 자체가 매우 유사한 편인데, 그 유사한 정도가 어느 정도 수준인가 하면 마이크로소프트의 VBScript 개발 담당자가 귀찮은 나머지 Microsoft Visual Basic 6.0의 클래스 모듈 문법을 그냥 그대로 요약하여 만든 것이 바로 VBScript 클래스가 아닐까 하는 황당한 의심이 들 정도이다.

따라서, VBScript의 클래스에 익숙한 사람은 Microsoft Visual Basic 6.0의 클래스 모듈을 학습하는데 그다지 큰 노력이 필요하지 않고 또한 그 반대의 경우도 마찮가지라고 말할 수 있다. 이 사실이 중요한 이유는 Microsoft Visual Baisc 6.0에서 클래스 모듈은 바로 COM/COM+ 컴포넌트를 작성하는데 기초가 되는 기술이라는 점이다. 필자가 생각하기에는 이제 막 초급 단계를 뛰어넘어 보다 고급의 기술을 익히고자 노력하는 ASP 프로그래머들이라면 그 누구라도 COM/COM+ 컴포넌트에 대한 욕심을 어느 정도 갖고 있을 것이라고 믿는다.

필자의 경우에는 Microsoft Visual Basic 6.0을 사용해서 실제로 COM 컴포넌트를 만들기 전에 미리 약식으로 VBScript 클래스를 사용하여 클래스를 구성해보기도 하고, 때때로 이렇게 만들어낸 클래스가 나름대로 쓸만하다고 생각되면 상황에 따라 그 VBScript 클래스를 그냥 그대로 사용하는 경우도 자주 있다. 실무에서는 약간의 성능적인 이득보다는 유지보수의 용이성이 더 중요한 경우가 많으므로 이와 같은 상황은 생각보다 자주 발생하는 편이다. 어떤 면에서 이런 작업 방식은 컴파일을 하거나 이진 호환성을 관리할 필요가 없으므로 코드 자체에만 신경을 쓸 수 있다는 장점을 갖고 있다.

일반적인 프로시저를 클래스의 멤버 함수로 변환하기

이제 지루한 설명은 이 정도로 마치고 바로 본론으로 들어가서 VBScript 클래스에 관한 간단한 예제를 살펴보도록 하자. 이번에는 기존에 이미 ASP 프로그램에서 사용하고 있던 프로시저를 클래스의 멤버 함수 형태로 변환하는 비교적 간단한 유형의 작업을 가정해보겠다.

다음 코드를 살펴보자. 이 코드에서 사용되고 있는 Sum() 함수는 지극히 일반적인 내용으로 두 개의 숫자값을 인자로 받고 그 합을 구해서 리턴하는 함수다. 간단한 코드이므로 별도로 설명을 하거나 하지는 않겠다.

<%

  '****************************************************************
  '* Sum() 함수
  '****************************************************************
  
  Function Sum(ArgX, ArgY)
  
    Sum = ArgX + ArgY
    
  End Function

  
  '****************************************************************
  '* Sum() 함수를 실제로 사용하는 부분.
  '****************************************************************
  
  Dim x, y
  
  x = 1
  y = 3
  
  Response.Write Sum(x, y)
  
%>

이 Sum() 함수처럼 간단한 프로시저를 클래스의 멤버 함수로 변환하는 과정은 싱겁게 느껴질 정도로 단순하다. 그저 Class [Class Name] 문과 End Class 문으로 해당 프로시저의 전후를 감싸주면 되는 것이다. 이 때, Class [Class Name] 문의 [Class Name]에는 클래스의 이름을 입력하면 되는데, 표준 변수 명명 규칙을 만족하는 문자열이라면 어떤 이름도 지정이 가능하다.

다음 코드가 바로 그 작업의 결과로 이런 유형의 클래스가 VBScript에서 작성 가능한 가장 간단한 형태의 클래스 중 하나라고 말할 수 있을 것이다. 붉은색으로 강조된 부분들을 유의해서 살펴보기 바란다.

<%

  '****************************************************************
  '* MyClass 라는 이름으로 클래스를 선언한다.
  '****************************************************************
  
  Class MyClass
      
      Function Sum(ArgX, ArgY)
      
        Sum = ArgX + ArgY
        
      End Function
      
  End Class

  
  '****************************************************************
  '* MyClass 클래스를 실제로 사용하는 부분.
  '****************************************************************
  
  Dim MyClsObj
  Dim x, y
  
  x = 1
  y = 3
  
  
  Set MyClsObj = New MyClass           
  Response.Write MyClsObj.Sum(x, y)
  Set MyClsObj = Nothing
  
%>

이미 얘기했던 것처럼 추가적인 설명을 한다는 것이 무의미할 정도로 단순한 결과다. 따라서, 간단하게 몇 가지 사항만을 짚고 넘어가기로 하겠다.

이 코드에서처럼 일단 필요한 클래스를 선언하고 나면 필요할 때 얼마든지 선언한 클래스의 인스턴스를 생성해서 그 즉시 사용할 수 있는데, 클래스의 인스턴스를 생성할 때는 Server.CreateObject() 메서드가 아닌 New 연산자를 사용한다는 점에 주의하기 바란다. 정규 표현식에 관한 일전의 글에서도 이미 얘기한 바가 있지만 VBScript를 사용해서 작성된 ASP 프로그램에서 New 연산자가 사용되는 단 두 가지의 경우 중 한 가지 경우가 바로 지금과 같이 클래스의 인스턴스를 생성하는 경우인 것이다. 또한, 사용이 끝난 클래스의 인스턴스는 언제나처럼 Nothing 키워드를 사용해서 참조를 해제해주어야 한다는 점도 역시 기억해두기 바란다.

그리고, Microsoft Visual Basic 6.0에 익숙한 분들일수록 실수하기 쉬운 부분이 하나 있는데 VBScript는 전적으로 후기 바인딩되는 Script 언어고 As 키워드도 지원되지 않으므로 아무리 New 연산자를 사용한다고는 해도 다음과 같이 Microsoft Visual Basic 6.0에서와 같은 코드를 사용할 수는 없다.

Dim MyClsObj As New MyClass

이번에는 현재 Sum() 함수에서 인자 ArgX와 인자 ArgY를 통해서 직접 입력 받고 있는 두 개의 숫자값을 클래스의 멤버 변수를 통해서 접근하도록 위의 코드를 변경해보기로 하자. 여기에서 오해하지 말아야 할 점은, 지금 말하고 있는 멤버 변수란 프로퍼티(Property)가 아니라 말 그대로 변수(Variable)라는 점이다. 프로퍼티에 관해서는 다음글에서 자세히 설명할 예정이므로, 일단 본문에서는 멤버 변수에 관해서만 얘기하도록 하겠다. 다음 코드가 그 변경된 결과다.

<%

  '****************************************************************
  '* MyClass 라는 이름으로 클래스를 선언한다.
  '****************************************************************
  
  Class MyClass
      
      Dim X, Y                 '** 일반적인 변수의 선언 방법과 동일하다.
      
      Function Sum()
      
        Sum = X + Y
        
      End Function
      
  End Class

  
  '****************************************************************
  '* MyClass 클래스를 실제로 사용하는 부분.
  '****************************************************************
  
  Dim MyClsObj
  
  Set MyClsObj = New MyClass
  MyClsObj.X = 4
  MyClsObj.Y = 5
  Response.Write MyClsObj.Sum()
  Set MyClsObj = Nothing
  
%>

필자가 설명의 편의를 위해서 의도적으로 접근 제한문, 즉 Public 문이나 Private 문을 사용하지 않은 점을 감안한다고 하더라도 이 코드는 특이한 부분이 전혀 없는 매우 일상적인 코드다. 이처럼 기존에 사용하고 있던 프로시저를 클래스의 멤버 함수 형태로 변환하는 작업은 그다지 어려울 바 없는 손쉬운 작업인 것이다.

그러나, 지금까지 살펴본 특징들이 VBScript에서 제공해주는 클래스의 기능의 전부는 아니다. 본문의 샘플에서 살펴볼 수 있었던 각각의 특징들은 지극히 평범한 일부에 불과할뿐 VBScript의 클래스만이 제공해주는 보다 깊은 내용들까지는 다루지 못하고 있다. 실제로는 이보다 더 강력한 고급 기능들도 상당히 많이 제공해주고 있는데, 가령 앞에서 얘기했던 Initialize 이벤트와 Terminate 이벤트라든가 Default 키워드, Property Get 문, Property Let 문, Property Set 문, 그리고 인자를 갖는 프로퍼티 등, ASP 프로그래밍을 보다 풍성하게 해주는 수 많은 기능들이 바로 그것이다. 다음글부터는 본격적으로 이런 VBScript 클래스의 고급 기능들에 대하여 알아보도록 하겠다.