1980년대 중반 소프트웨어의 사용 범위와 규모가 폭발적으로 늘어나게 되면서 소프트웨어를 구성하는 프로그램의 논리는 점점 더 복잡한 실타래처럼 꼬여갔다. C 언어로 대표되는 기존의 ‘절차적’ 언어가 그런 변화를 감당하기에 역부족이라는 사실은 누구의 눈에도 분명했다. 이와 같은 상황에 등장하여 사태를 단숨에 제압한 존재가 바로 ‘객체’였다. 객체가 제공한 ‘코드의 재사용(reusability)’과 ‘다형성(polymorphism)’이라는 약은 중병을 앓던 소프트웨어의 세계에서 놀라운 효능을 지닌 처방이 되었다. 객체의 ‘약’맛을 본 프로그래머들은 세부적인 알고리즘의 구현에 점점 덜 구애받게 되었다. 세부적인 논리보다는 요구사항(requirements)을 분석한 결과에 따라서 객체를 정밀하게 설계하는 일이 더 중요하게 되었기 때문이었다. 하지만 모든 약이 그렇듯이 객체도 모든 병에 대한 만병통치약이 될 수는 없었다. 객체의 개념과 장단점을 정확하게 파악하고 있는 프로그래머에게 객체는 분명 약이 되었지만 그렇지 않은 프로그래머에게는 오히려 ‘독’이 되기도 했던 것이다. 객체지향의 창시자, 와드 커밍햄과 켄트 벡1987년에 객체지향 언어인 ‘스몰토크(Smalltalk)’를 이용해서 소프트웨어 설계 작업을 하던 와드 커닝험(Ward Cunningham)과 켄트 벡(Kent Beck)은 막바지에 이른 작업의 완성을 위해서 소프트웨어를 이용하게 될 사용자들이 직접 설계를 끝내도록 맡겼다. 이 때 커닝험과 벡은 스몰토크에 익숙하지 않은 사용자들이 잘못된 설계를 하는 것을 방지하기 위해서 스몰토크 언어를 이용한 설계에서의 몇 가지 핵심적인 내용을 간추린 ‘패턴(pattern)’을 정리해서 교육시켰다. 교육의 결과는 만족스러웠다. 커닝험과 벡은 이 경험으로부터 객체지향 언어에 있어서 디자인 패턴의 중요성을 처음으로 깨닫게 되었다. 그리하여 그들은 1987년에 열린 OOPSLA(Object-Oriented Programming, Systems, Languages & Applications) 컨퍼런스에서 패턴의 개념과 그 의미심장함을 강변했다. 이것은 컴퓨터 프로그래밍의 세계에서 하나의 작은 획이 그어지는 순간이었다. 하지만 커닝험과 벡이 발견한 패턴은 ‘아이디어’를 뒷받침할 만한 구체적인 실체가 결여되어 있었기 때문에 사람들의 주목을 충분히 끌지는 못했다. 지금은 쮜리히(Zurich)에서 살면서 IBM의 이클립스(Eclipse)나 비주얼에이지(VisualAge) 같이 잘 알려진 프로젝트에 참여하고 있는 에리히 감마(Erich Gamma)는 80년대 후반에 박사 논문을 쓰는 대학원생이었다. 감마는 자신의 논문을 정리하는 과정에서 객체지향 언어로 객체를 설계할 때 특정한 패턴을 나타내면서 반복되는 ‘무엇’이 존재한다는 점을 분명히 인식했다. 하지만 그 ‘무엇’을 다른 사람에게 전달할 ‘어휘’ 혹은 ‘의사소통’의 방법이 구체적으로 드러나지 않고 있었다. ‘네 명의 일당’과 패턴의 등장그리하여 감마는 불확실한 ‘무엇’의 존재를 연구하여 ‘합성(Composite)’, ‘결정자(Decider)’, ‘관찰자(Observer)’, 그리고 ‘제한자(Constrainer)’라는 일정한 패턴으로 정형화했다. 프로그래밍 고수들의 머릿속에서 추상적으로만 맴돌던 패턴이 마침내 두꺼운 옷을 입고 현실에 모습을 드러낸 순간이었다. 추상적인 개념이 구체적인 존재로 탈바꿈을 하면서 소프트웨어 설계에 있어서의 패턴에 대한 프로그래밍 고수들의 연구는 가속도가 붙게 되었다. 그리하여 마침내 1991년에 개최된 OOPSLA에는 훗날 ‘네 명의 일당들(Gang of Four)’라는 별칭으로 불리게 되는 에리히 감마, 리처드 햄(Richard Helm), 랄프 존슨(Ralph Johnson), 존 블리시데스(John Vlissides)가 한 자리에 모이게 되었다. 이 네 명이 여러 개의 패턴을 집대성해서 저술한 책이 유명한 “디자인 패턴 : 재사용 가능한 객체지향 소프트웨어의 요소들(Design Patterns: Elements of Reusable Object-Oriented Software]”이었다. 패턴이라는 초식을 익히고자 하는 프로그래머라면 한번쯤 읽지 않을 수 없는 책이다.
“각각의 패턴은 우리를 둘러싸고 있는 환경에서 반복적으로 나타나는 특정한 문제와 그에 대한 해결책을 설명한다. 그리고 그 해결책은 계속 사용될 수 있기 때문에 동일한 과정을 반복할 필요가 없다.”
건축으로부터 빌려온 패턴의 개념패턴에 대해서 이와 같이 간명한 정의를 내린 사람은 크리스토퍼 알렉산더(Christopher Alexander)라는 사람이었다. 패턴이라는 개념을 최초로 포착한 그는 놀랍게도 컴퓨터 프로그래머가 아니라 건축가였다. 결국 소프트웨어 설계에서 나타나는 패턴이라는 개념은 알렉산더가 ‘건축’ 분야에서 정립한 개념을 빌려온 것이다.프로그래밍 세계에서 패턴의 개념을 정립한 사람들은 건축 설계에 몰두했던 알렉산더의 저술에서 영감을 받았다. 위에 인용한 패턴의 정의는 컴퓨터 프로그래밍이 아니라 건축과 관련이 있는 것이었지만 어떤 대상을 새롭게 디자인하는 과정 일반에 적용되는 보편적인 방법론을 가리키고 있기 때문에 소프트웨어 설계의 과정을 포함했다. 한편 건축보다는 소프트웨어 구현에 더 많은 관심을 가졌던 ‘네 명의 일당’이 정의한 소프트웨어 설계 패턴은 다음과 같이 보다 구체적이었다.
“설계 패턴은 객체지향 시스템 안에서 반복해서 등장하는 설계와 관련된 문제를 해결하기 위한 일반적인 기법에 이름을 붙이고, 동기를 부여하고, 설명을 한다. 그것은 문제를, 해결책을, 그리고 그 해결책을 언제 적용해야 하는지, 적용한 결과는 무엇인지 등을 설명한다. 그것은 또한 실질적인 구현에 대한 힌트와 예제도 제공한다. 해결책은 대개 문제를 해결하기 위해서 필요한 객체와 클래스를 일반적인 방식으로 배치한다. 해결책은 주어진 문제를 특정한 문맥(context) 안에서 해결하기 위해서 다듬어지고 구현된다.”
패턴을 익히는 것은 마치 바둑에서 ‘정석(定石)’을 익히는 것과 같아서 패턴의 내용이나 이름을 기계적으로 ‘암기’하는 것은 아무런 의미가 없다. ‘네 명의 일당’이 밝힌 바와 같이 각각의 패턴이 필요한 동기, 그 패턴이 제공하는 해결책을 사용해야 할 시점, 그리고 그 해결책을 사용한 결과 등을 충분히 이해하는 것이 핵심이기 때문이다. 그렇지만 프로그래머를 채용하기 위한 면접 과정에서 설계 패턴에 대한 질문을 던지면 머리 속에 암기하고 있는 패턴의 이름을 앵무새처럼 이야기하는 사람들을 종종 만나게 된다. 다시 한 번 이야기하지만 중요한 것은 패턴의 ‘이름’이 아니라 그 이름이 담고 있는 ‘내용’이다(철학자들은 이것을 ‘형식’과 ‘내용’ 혹은 ‘기표’와 ‘기의’라는 어려운 말로 표현하기도 한다). 프로그래머들이 가장 흔히 알고 있는 패턴으로 대표적인 것은 ‘싱글턴(Singleton)’ 패턴과 ‘팩토리(Factory)’ 패턴이 있다. 둘 다 객체를 생성할 때 흔히 사용하는 기법이기 때문에 적어도 한번쯤 들어보거나 구현해본 적이 있을 것이다. 예를 들어 자바 언어에서 자바 가상머신(VM) 내부에 생성되는 객체의 인스턴스 수를 하나로 국한시키고자 할 때 사용하는 ‘싱글턴’ 패턴을 생각해 보자. 싱글턴 패턴을 숙지하고 있는 사람들은 다음과 같은 코드를 작성한다.
private static MyObject instance = null;public static MyObject getInstance (){ if (instance == null) { instance = new MyObject (); } return instance;} private MyObject (){ // 객체 생성에 필요한 초기화 작업을 여기에서 수행한다.}
앞의 코드는 MyObject라는 이름의 객체를 만들기 위한 클래스를 정의하고 있다. 클래스의 생성자(constructor)가 프라이빗(private)으로 선언되어 있기 때문에 MyObject의 인스턴스가 필요한 코드는 반드시 퍼블릭(public)으로 선언되어 있는 ‘getInstance 메쏘드’를 통해서 접근해야 한다. getInstance 메쏘드는 스태틱(static)으로 선언되어 있기 때문에 ‘MyObject.getInstance()처럼’ (객체를 생성할 필요 없이 바로) 클래스에 대한 참조를 이용해서 접근할 수 있다.
싱글턴 패턴의 유용성싱글턴 패턴은 단순하지만 유용해서 실전 프로그램에서 널리 사용되는 대표적인 패턴의 하나이다. 보통 ‘생성적(creational)’, ‘구조적(structural)’, 그리고 ‘행위적(behavioral)’이라는 세 범주로 구분되는 여러 개의 패턴은 싱글턴 패턴이 인스턴스의 수를 하나로 국한시키고자 하는 목적을 갖는 것처럼 저마다의 목적을 가지고 탄생했다. 그리고 소프트웨어를 설계하는 프로그래머들은 의식적이든 아니든 그러한 패턴의 도움을 받으면서 복잡하고 정교한 객체의 건축물을 완성해왔다. 커닝험과 켄이 패턴의 개념을 포착한 이후로 패턴은 고수가 되고자 하는 프로그래머가 반드시 익혀야 하는 초식이 되었지만, 객체와 마찬가지로 그것은 만병통치약은 아니다. 객체의 설계든, 정교한 알고리즘의 작성이든, 그것은 ‘약’의 힘으로 하는 것이 아니라 오직 프로그래머 본인의 힘으로 해야 하는 일이기 때문이다. 프로그램의 ‘완성도’와 ‘미학’은 패턴 자체에 놓여있는 것이 아니라 그 패턴을 이용하는 프로그래머의 능력과 자세에 달려있는 것이다. @
* 이 기사는 ZDNet Korea의 자매지인 마이크로소프트웨어 8월호에 게재된 내용입니다.