Top Banner
43

프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

Jul 22, 2016

Download

Documents

크리스티나 로페즈 지음 | 이상주 옮김 | 프로그래밍 & 프랙티스 시리즈 _ 010 | ISBN: 9791158390051 | 25,000원 | 2015년 07월 21일 발행 | 312쪽
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법
Page 2: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

프로그램스타일.indb 1 2015-07-10 오후 1:54:41

Page 3: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

01PART

02PART

03PART

전통적 형식

기본 형식

함수 합성

/ 목 / 차 /4

CHAPTER 01

그리운 옛날 24

CHAPTER 02

포스로 35

CHAPTER 03

일체식 49

CHAPTER 04

요리책 55

CHAPTER 05

파이프라인 63

CHAPTER 06

코드 골프 74

CHAPTER 07

무한 거울 82

CHAPTER 08

앞으로 차기 88

CHAPTER 09

유일 95

프로그램스타일.indb 4 2015-07-10 오후 1:54:43

Page 4: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

04PART

05PART

전통적 형식

기본 형식

함수 합성

객체와 객체 상호작용

반영과 메타프로그래밍

5/ 목 / 차 /

CHAPTER 10

사물 104

CHAPTER 11

우편함 114

CHAPTER 12

닫힌 맵 121

CHAPTER 13

추상사물 128

CHAPTER 14

할리우드 138

CHAPTER 15

게시판 146

CHAPTER 16

자기관찰 156

CHAPTER 17

반영 161

CHAPTER 18

애스펙트 169

CHAPTER 19

플러그인 175

프로그램스타일.indb 5 2015-07-10 오후 1:54:43

Page 5: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

06PART

07PART

재난

데이터 중심

/ 목 / 차 /6

CHAPTER 20

구성주의 186

CHAPTER 21

발끈하기 192

CHAPTER 22

수동공격 198

CHAPTER 23

선언한 의도 204

CHAPTER 24

격리 212

CHAPTER 25

영속 데이터 226

CHAPTER 26

스프레드시트 234

CHAPTER 27

게으른 강 240

프로그램스타일.indb 6 2015-07-10 오후 1:54:43

Page 6: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

08PART

09PART

병행성

쌍방향성

재난

데이터 중심

7/ 목 / 차 /

CHAPTER 28

행위자 250

CHAPTER 29

데이터 공간 259

CHAPTER 30

맵리듀스 264

CHAPTER 31

이중 맵리듀스 272

CHAPTER 32

삼위일체 280

CHAPTER 33

REST 방식 289

프로그램스타일.indb 7 2015-07-10 오후 1:54:43

Page 7: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

글을 잘 쓰는 방법 중 하나가 많은 글을 써 보는 것이라 한다. 하지만 상황에 따

라 내용을 더 효과적으로 전달하기 위한 글쓰기 방법은 여전히 존재하며 이는

곧 문체로 나타난다. 레몽 크노는 ‘문체 연습(Exercises de style)’이란 책을 통

해 별것 아닌 소재 하나로 다양한 문체를 사용해 글쓰기를 시도한다. 마치 아주

단순한 소절을 다양한 변주를 통해 멋진 음악을 만들어 내듯.

마찬가지로 프로그래밍 실력을 높이는 방법 중 하나는 많은 프로그램을 만들어

보는 것이며, 특히 간단한 프로그램을 다양한 방법으로 풀어 보는 것이라 한다.

하지만 생각만큼 쉬운 일은 아니다. 게다가 무려 서른 가지가 넘는 방법으로 풀

어 보라면 어떨까. 서른 가지라고? 설마 세 가지를 잘못 얘기한 건 아니겠지?

앞서 언급한 ‘문체 연습’에서 크노는 간단한 소재 하나로 무려 99가지 서로 다른

형식의 이야기로 만들어 냈다. 이 책은 그에 영감을 받아 단어 빈도 세기라는 간

단한 주제로 무려 33가지 서로 다른 형식의 프로그램을 만들어 낸다. 누구나 흔

히 생각해 낼 수 있는 전통적 방법부터 최신 기법에 이르기까지 다양한 방식으

로 변주하며 그 예를 보여 준다. 더구나 예에 그치지 않고 실제 시스템을 설계할

때 어떤 식으로 활용할 수 있을지를 고민할 뿐만 아니라, 해당 형식이 어떻게 탄

생하게 됐는지 그 배경을 살짝 엿보는 즐거움은 덤으로 얻을 수 있다.

현재 개발하고 있는, 그리고 앞으로 개발해야 할 시스템은 과연 어떤 모습이어

야 더 효율적일까. 오늘도, 내일도 항상 이러한 고민을 거듭하고 있는 개발자라

면 이 책을 일독하길 권해 본다. 또한 이제 프로그래밍을 막 시작한 개발자라도

좋다. 생각지도 못한 다양한 방식으로 구현할 수 있음을 마음속에 새겨 두고 천

천히 연습하며 필요할 때 활용해 보면 분명 많은 발전이 있으리라 생각한다.

마지막으로, 김윤래 님께 먼저 감사 인사를 드린다. 두고두고 되새겨 볼 좋을

책을 찾아 소개해 주신 덕분에 이렇게 빛을 보게 됐다. 또한 투박하고 오류 많은

글을 검토하고 세련되게 다듬으며 바로잡아 독자 여러분께 더 나은 책을 전할

수 있게 많은 도움을 주신 이대엽 님께도 감사드린다.

/ 역 / 자 / 서 / 문 /8

프로그램스타일.indb 8 2015-07-10 오후 1:54:44

Page 8: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

코드

이 책은 http://github.com/crista/exercises-in-programming-style에 공개

한 코드에 대한 참고서다.

대상 독자

이 책의 바탕이 되는 코드는 프로그래밍의 예술을 즐기는 모든 이를 위한 것이

다. 이 책을 쓴 이유는 일부 관용구(idiom)가 쉽게 이해하기 어려울 수 있어 그

코드를 보완하고 설명하기 위해서다. 다년간의 경험을 쌓은 소프트웨어 개발자

는 이 책에서 폭넓게 다루고 있는 친숙한 프로그래밍 형식을 다시 음미하고 흔

히 사용하지 않는 형식을 배울 수 있을 것이다.

이 책은 컴퓨터 과학과 소프트웨어 공학 과정에서 고급 프로그래밍 강좌의 교과

서로 사용할 수 있으며, 강의 슬라이드 같은 추가 수업 자료로도 사용할 수 있

다. 이 책에서는 프로그래밍 입문 과정을 고려하지 않았다. 그 이유는 학생들이

달릴 수 있기 전(즉, 어떤 일을 하는 다양한 방법이 수없이 많다는 것을 인식하

기 전)에 길 수 있는 것(어떤 일을 하는 방법이 단 하나밖에 없다는 환상 속에서

프로그래밍을 배우는 것)이 중요하기 때문이다. 그러므로 대부분의 독자가 학부

3/4학년이나 대학원에 갓 진학한 학생일 것이라 생각한다. 각 장 끝에 있는 연

습 문제를 통해 각 형식을 독자가 얼마나 이해했는지 시험해 볼 수 있으며, 더

읽을거리는 대학원생에게 적합하다.

또한 이 책은 프로그래밍에 관한 지식이 적거나 프로그래밍 기술에 큰 흥미가

있는 작가에게도 흥미로울 것이다. 프로그램을 만드는 것과 일반적인 글쓰기는

중요한 차이점이 있음에도 비슷한 구석이 많다.

9/ 저 / 자 / 서 / 문 /

프로그램스타일.indb 9 2015-07-10 오후 1:54:44

Page 9: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

집필 동기

1940년대에 프랑스 작가 레몽 크노(Raymond Queneau)는 문체 연습

(Exercises in Style)이라는 보석과도 같은 책을 저술했다. 이 책은 정확히 같

은 이야기를 99가지 서로 다른 문체로 쓴 것이 특징인데, 이야기를 풀어갈 수

있는 수많은 방법의 예를 보여주는 글쓰기 기법의 걸작이다. 이야기 자체는 아

주 평범하고 항상 같으며, 책에서는 내용보다 형식에 집중한다. 즉, 이야기를

풀어가는 방법이 그 이야기를 인식하는 데 어떤 영향을 주는지 설명한다.

크노의 이야기는 극히 단순하며 두 문장으로 요약할 수 있다. ‘S’ 버스를 타고 있

던 화자는 모자를 쓰고 있으며 목이 긴 한 남자를 주목하는데, 그 남자는 자기

바로 옆자리에 있는 남자와 언쟁을 벌인다. 두 시간 후 화자는 그 남자가 생 라

자르 역 근처에서 친구와 함께 있으며, 친구가 그 남자에게 외투에 단추를 하나

더 달라고 조언하는 모습을 보게 된다. 그 뿐이다! 그다음엔, 예를 들면 완서법

(litotes), 은유법(metaphor), 정령숭배사상(animism) 등을 통해 이 이야기를

99가지로 변주해 간다.

지난 몇 년간 여러 프로그래밍 과정을 강의하면서 일반적으로 학생들이 프로그

램을 만들거나 시스템을 설계하는 다양한 방법을 이해하는 데 어려움을 겪는다

는 것을 깨달았다. 학생들은 한 가지 또는 많아야 두 가지 프로그래밍 언어로 배

우므로 그 언어에서 권장하는 형식만 이해하며 다른 형식을 이해하는 데 어려움

을 느낀다. 이는 학생들의 잘못이 아니다. 대부분의 컴퓨터 과학 과정에 형식에

관한 교육학적 자료가 부족하다는 점과 프로그래밍 언어의 역사를 통해 보건대,

방대한 경험이 축적된 후라도 누구도 그 문제를 제기할 것 같지 않다. 그렇다고

해도 형식은 다른 이에게 여전히 설명하기 어렵고, 이로 인해 여러 기술적 논쟁

이 벌어지는 프로그램의 무형자산으로 존재한다. 그러므로 프로그래밍 형식에

적절한 몫을 부여하기 위해 크노에게서 영감을 받은 대로 똑같은 계산 작업을

몇 년에 걸쳐 여러 형식으로 작성하는 프로젝트를 시작하기로 결심했다.

/ 저 / 자 / 서 / 문 /10

프로그램스타일.indb 10 2015-07-10 오후 1:54:44

Page 10: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

그러면 형식(style)이란 무엇인가? 울리포(Oulipo, 프랑스어로 Ouvroir de la

littérature potentielle이며 대략 ‘잠재 문학 작업실’로 옮길 수 있는)로 알려

진, 크노의 지식인 모임에서 형식이란 치환이나 리포그램(lipogram)1과 같이 흔

히 수학적 개념을 기반으로 하는 제약하에서 만든 결과에 지나지 않는다. 이러

한 제약은 이야기 그 자체 외에 지적으로 흥미로운 무언가를 자아내는 방법으로

사용한다. 이 생각은 수년 동안 유행했으며, 몇몇 문학 작품은 울리포의 제약을

사용해 저술되기도 했다.

이 책에서도 프로그래밍 형식은 제약조건 집합에 따라 프로그램을 작성한 결과

물이다. 제약조건은 외부에서 유래하거나 스스로 만들 수 있고, 해당 환경에 의

한 진정한 도전이거나 인위적일 수 있으며, 과거 경험과 측정 가능한 데이터 또

는 개인적 선호에서 유래할 수도 있다. 그렇지만 그 기원과는 별개로 제약조건

은 형식의 씨앗이다. 여러 다른 제약조건을 존중함으로써 프로그램이 수행하는

일의 관점에서는 사실상 같지만 그 일을 하는 방법 면에서는 근본적으로 다른,

다양한 프로그램을 작성할 수 있다.

훌륭한 프로그래머가 반드시 알아야 하는 모든 것이 존재하는 세상에서 프로그

래밍 형식 모음은 컴퓨터의 계산 능력에 대한 영향보다 인간에 대한 영향에 초

점을 맞출 때 어떠한 자료 구조와 알고리즘 만큼이나 중요하다고 본다. 프로그

램은 단지 컴퓨터만이 아니라 더 중요하게는 이를 읽는 사람에게 정보를 전달한

다. 어떤 표현 형식이든 이야기하는 대상의 결과를 형상화하고 그 대상을 이야

기하는 방법을 통해 감화를 준다. 고급 프로그래머는 잘 작동하는 올바른 프로

그램을 작성할 수 있어야 할 뿐만 아니라 다양한 목적에 따라 그 프로그램을 표

현하는 적절한 형식을 택할 수 있어야 한다.

하지만 통상적으로 프로그램을 표현하는 미묘한 차이를 가르치는 것보다 알고

리즘과 자료 구조를 가르치는 것이 훨씬 쉽다. 자료 구조와 알고리즘에 관한 책

1 (옮긴이)특정글자나문자집단을사용하지않고문단이나문학작품을만드는것을뜻한다.

11/ 저 / 자 / 서 / 문 /

프로그램스타일.indb 11 2015-07-10 오후 1:54:44

Page 11: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

은 모두 의사 코드, 설명 그리고 복잡도 분석이라는 거의 동일한 공식을 따른

다. 프로그래밍에 관한 작품은 프로그래밍 언어를 설명하는 책과 설계 또는 아

키텍처 패턴 모음을 제시하는 책으로 나뉘는 경향이 있다. 하지만 프로그래밍

언어가 결국에는 프로그램을 구성하는 여러 프로그램 요소의 조합을 촉진/강

제한다는 개념에서 출발하는 수많은 프로그램 작성법에도 연관성이 존재한다.

즉, 언어와 패턴은 서로서로에게 밑거름이 되고, 언어와 패턴을 별개의 것으로

구분하는 것은 잘못된 이분법이다. 크노의 모든 작품이 그렇듯이 표현 형식을

설명하기 위한 근거로 그가 제약에 초점을 맞춘 것은 프로그래밍 세계에 존재하

는 수많은 중요한 창작물을 통합하는 데 더할 나위 없이 훌륭한 모델이었다.

제약조건을 소프트웨어 시스템 내 표현 형식을 설명하기 위한 훌륭한 통합 원칙

으로 본 것은 내가 처음이 아니다. 아키텍처 형식에 관한 연구는 오랫동안 있었

다. 고백하건대 형식이 제약조건(어떤 것은 허용하지 않고 어떤 것은 반드시 존

재해야 하며 어떤 것은 제한적이어야 한다는 등)에서 기인한다는 개념을 처음에

는 약간 이해하기 어려웠다. 누군들 제약조건에 따라 프로그램을 작성하고 싶어

할까? 크노의 작품을 마주칠 때까지는 그렇게 생각하지 않았다.

크노의 이야기처럼 이 책에서 다루는 계산 작업은 아주 평범하다. 텍스트 파일

을 주면 그 파일에 들어있는 단어와 해당 단어의 빈도 목록을 만들고 빈도를 내

림차순으로 출력한다. 이 계산 작업을 단어 빈도(term frequency)라 한다. 이

책에는 단어 빈도 작업을 작성하는 형식이 각 장별로 하나씩 33가지가 있으며,

크노의 책과 달리 각 형식별 제약조건을 말로 표현하고 예제 프로그램을 설명한

다. 또한 대상 독자가 정해져 있더라도 그러한 통찰력을 독자가 해석하게 하기보

다 명시적으로 알려주는 편이 중요하다고 생각한다. 각 장은 해당 형식의 제약조

건을 제시하면서 시작한 다음, 예제 프로그램을 보여주고 그 코드에 대한 상세

설명이 뒤따른다. 각 장에서는 시스템을 설계할 때 해당 형식을 활용하는 것과

해당 프로그래밍 형식이 나타난 역사적 맥락에 관해 소개한다. 역사는 중요하다.

뭔가를 훈련할 때는 핵심 개념의 기원을 잊지 말아야 하기 때문이다. 또한 더 읽

을거리에 있는 참고문헌을 찾아 읽을 만큼 독자가 흥미를 가지면 좋겠다.

/ 저 / 자 / 서 / 문 /12

프로그램스타일.indb 12 2015-07-10 오후 1:54:44

Page 12: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

왜 33가지 형식인가? 나는 개인적 도전의 한도로 33가지를 선택했다. 크노의

책에는 99가지 문체가 있다. 99장으로 구성한 책을 쓰는 것을 목표로 했다면 아

마 절대로 이 책을 펴내지 못했을 것이다! 하지만 이 책의 바탕이 되는 코드가

있는 공개 저장소는 계속해서 성장할 것이다. 형식은 9가지 범주로 나뉜다. 전

통적, 기본, 함수 합성, 객체와 객체 상호작용, 반영과 메타프로그래밍, 재난,

데이터 중심, 병행성 그리고 쌍방향성이다. 이 범주는 이 책을 구성하는 방법에

서 나왔으며 하나로 묶은 형식은 서로 더 밀접한 관계가 있다. 다른 범주 역시

가능하다.

크노의 책과 비슷하게 이러한 프로그래밍 형식 연습은 분명 연습이다. 이러한

연습은 소프트웨어의 밑그림 또는 펼침화음(arpeggio)2이며 음악이 아니다. 실

제 소프트웨어 조각에서는 일반적으로 시스템에서 사용하는 부분별로 다양한

형식을 사용한다. 더욱이 이러한 모든 형식을 짜맞춰 그 자체로 흥미로운 혼합

물을 만들어낼 수도 있다.

마지막으로 중요한 한 가지를 이야기해야겠다. 크노의 책이 이 프로젝트에 영감

을 줬지만 소프트웨어는 언어 예술과 정확히 같지 않다. 소프트웨어 설계 결정

에 따른 효용 기능(utility function)이 있는데, 다시 말해 특정 목적에 더 적합한

표현식이 있다는 것이다.3 이 책에서는 명백한 상황을 제외하고 좋음과 나쁨에

대한 판단은 유보한다. 그러한 판단은 내가 아닌 각 프로젝트별 맥락에 따라 크

게 달라지기 때문이다.

2 (옮긴이)화음을이루는각음들을한꺼번에소리내지않고아래에서위로,위에서아래로,또는오르내리는꼴로내도록한화음

3 언어예술에서도그러할수있지만유감스럽게도잘모른다!

13/ 저 / 자 / 서 / 문 /

프로그램스타일.indb 13 2015-07-10 오후 1:54:45

Page 13: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

감사의 글

이 책의 초안에 값진 의견을 준 리처드 가브리엘(Richard Gabriel), 앤드류 블

랙(Andrew Black), 가이 스틸(Guy Steele), 제임스 노블(James Noble), 폴 스

테클러(Paul Steckler), 폴 맥존스(Paul McJones), 로리 트랫(Laurie Tratt), 테

이스 반 더 스톰(Tijs van der Storm) 그리고 UC 어바인(Irvine)의 INF 212 /

CS 235 (Winter 14) 학생들, 특히 마티아스 조르지오(Matias Giorgio)와 데이

비드 딘(David Dinh)에게 감사를 표하고 싶다.

IFIP 워킹 그룹 2.16에 속한 회원에게도 감사한다. 그곳에서 이 책에 관한 생각

을 처음 제시했고 그들의 의견은 이 책을 구성하는 데 큰 도움이 됐다.

지금까지 형식 연습 코드 저장소에 기여한 피터 노빅(Peter Norvig), 카일 킹

스버리(Kyle Kingsbury), 사라 트리플렛(Sara Triplett), 외르겐 에델보(Jørgen

Edelbo), 다리우스 베이컨(Darius Bacon), 유지니아 그라브리로바(Eugenia

Grabrielova), 쿤 후(Kun Hu), 브루스 아담스(Bruce Adams), 크리쉬난 라

만(Krishnan Raman), 마티아스 조르지오(Matias Giorgio), 데이비드 포스

터(David Foster), 채드 휘태커(Chad Whitacre), 제레미 맥케이브(Jeremy

MacCabe) 그리고 미르세아 룬구(Mircea Lungu)에게 특별히 감사드린다.

단어 빈도

크노의 이야기처럼 이 책에서 다루는 계산 작업은 아주 평범하다. 텍스트 파일

이 제공되면 가장 빈도가 높은 단어 N(예를 들면 25)개와 그에 해당하는 빈도를

내림차순으로 출력한다. 대문자는 모두 소문자로 정규화하고 ‘the,’ ‘for’ 등과 같

은 의미 없는 단어는 무시해야 한다. 문제를 단순하게 만들기 위해 빈도가 같은

단어의 순서는 신경 쓰지 않는다. 이 계산 작업을 단어 빈도라 한다.

다음은 입력 파일과 이 입력에 대해 단어 빈도를 계산한 후 출력한 예다.

/ 들 / 어 / 가 / 며 /14

프로그램스타일.indb 14 2015-07-10 오후 1:54:45

Page 14: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

Input:

White tigers live mostly in India

Wild lions live mostly in Africa

Output:

live – 2

mostly – 2

africa – 1

india – 1

lions – 1

tigers – 1

white – 1

wild – 1

구텐베르크(Gutenberg) 프로젝트에 있는 제인 오스틴(Jane Austen)의 오만과

편견(Pride and Prejudice)4을 대상으로 이 단어 빈도를 실행하면 다음과 같은

출력결과를 얻을 수 있다.

mr – 786

elizabeth – 635

very – 488

darcy – 418

such – 395

mrs – 343

much – 329

more – 327

bennet – 323

bingley – 306

jane – 295

miss – 283

one – 275

know – 239

before – 229

herself – 227

4 http://git.io/vkyjv

15/ 들 / 어 / 가 / 며 /

프로그램스타일.indb 15 2015-07-10 오후 1:54:45

Page 15: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

though – 226

well – 224

never – 220

sister – 218

soon – 216

think – 211

now – 209

time – 203

good – 201

이 책의 예제 프로그램에서는 이 단어 빈도 계산을 다룬다. 게다가 모든 장마다

연습 문제가 있으며, 그중에는 해당 형식을 사용해 또 다른 간단한 계산 작업을

작성하는 문제가 하나씩 있다. 그리고 몇 가지 고려할 내용을 아래에 서술한다.

이러한 계산 작업은 상급생이라면 쉽게 다룰 수 있을 정도로 간단하다. 그러므

로 알고리즘적인 어려움이 아니라 각 형식에 내재돼 있는 제약조건을 따르는 것

에 중점을 둬야 한다.

단어 색인

텍스트 파일이 제공되면 모든 단어를, 해당 단어가 나온 쪽 번호와 함께 알파벳

순으로 출력한다. 쪽 번호는 100번째까지만 표시하고 한 쪽은 45줄로 가정한

다. 예를 들면, 오만과 편견에 대한 색인 중 처음 몇 가지는 다음과 같을 것

이다.

abatement – 89

abhorrence – 101, 145, 152, 241, 274, 281

abhorrent – 253

abide – 158, 292

...

/ 들 / 어 / 가 / 며 /16

프로그램스타일.indb 16 2015-07-10 오후 1:54:45

Page 16: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

문맥상 단어

텍스트 파일이 제공되면 어떤 단어를, 해당 단어가 나온 쪽 번호와 함께 그 단어

앞뒤 내용을 포함해 알파벳순으로 표시한다. 이때 한 쪽은 45줄로 가정하고, 해

당 단어 전후로 각 두 단어씩 포함하며 구두점은 무시한다. 오만과 편견을 예로

들면, ‘concealment’와 ‘hurt’라는 두 단어에 대한 결과는 다음과 같다.

output:

perhaps this concealment this disguise – 150

purpose of concealment for no – 207

pride was hurt he suffered – 87

must be hurt by such – 95

and are hurt if i – 103

pride been hurt by my – 145

must be hurt by such – 157

infamy was hurt and distressed – 248

문맥상 단어 작업용으로 제안하는 단어는 concealment, discontented, hurt,

agitation, mortifying, reproach, unexpected, indignation, mistake,

confusion이다.

파이썬주의(PYTHONISMS)

이 책에서 사용한 예제 코드는 모두 파이썬으로 작성했지만 해당 형식을 이해하

기 위해 파이썬 전문가가 될 필요는 없다. 사실 모든 장마다 있는 연습 문제에는

다른 언어로 예제 프로그램을 작성하는 문제가 하나씩 있다. 그러므로 독자는

파이썬으로 작성할 필요 없이 파이썬 코드를 읽을 수만 있으면 된다.

파이썬 코드는 비교적 읽기 쉽다. 하지만 다른 언어를 사용해 본 독자를 혼란

스럽게 할 수도 있는 곤란한 내용이 좀 있으며, 여기서는 그중 몇 가지를 설명

한다.

17/ 들 / 어 / 가 / 며 /

프로그램스타일.indb 17 2015-07-10 오후 1:54:46

Page 17: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

≑ 리스트(List): 파이썬에서 리스트는 일반적으로 C 계열 언어의 배열과 연관된 전용 구문

으로 지원되는 원시 데이터 타입이다. mylist = [0, 1, 2, 3, 4, 5]는 리스트의 예

다. 파이썬에는 배열이 원시 타입으로 존재하지 않으며5, 파이썬에서는 C 계열 언어에서

배열을 사용하는 대부분의 상황에서 리스트를 사용한다.

≑ 튜플(Tuple): 튜플은 변경할 수 없는 리스트다. 또한 일반적으로 리스프(Lisp) 계열 언

어에 있는 리스트와 연관된 전용 구문으로 지원하는 원시 데이터 타입이기도 하다.

mytuple = (0, 1, 2, 3, 4)는 튜플의 예다. 튜플과 리스트는 유사한 방법으로 처리

하지만 튜플은 변경할 수 없으므로 리스트를 변경하는 연산은 튜플에 사용할 수 없다.

≑ 리스트 색인 연산(List indexing): 리스트와 튜플의 요소에는 mylist[some_index]처럼

색인으로 접근한다. 리스트 하한(lower bound)은 C 계열 언어처럼 색인이 0이고 리스트

길이는 len(mylist)로 구한다. 리스트 색인 연산은 방금 본 간단한 예제보다 훨씬 더

많은 것을 표현할 수 있으며, 다음은 그중 일부다.

- mylist[0] – 리스트의 첫 요소

- mylist[-1] – 리스트의 마지막 요소

- mylist[-2] – 리스트의 끝에서 두 번째 요소

- mylist[1:] – 색인 1에서 시작해 마지막 요소를 포함하는 리스트

- mylist[1:3] – 색인 1에서 시작해 색인 3 직전까지 포함하는 리스트

- mylist[::2] – 하나 건너 한 요소를 포함하는 리스트

- mylist[start:stop:step] – start와 stop 사이에서 매 step에 해당하는 요소를

포함하는 리스트

≑ 경계(bound): 리스트 길이보다 큰 색인으로 요소에 접근하면 IndexError가 발생한다. 예

를 들어, 요소가 3개인 리스트(예를 들면 [10, 20, 30][3])에서 4번째 요소에 접근하면

예상한 대로 IndexError가 발생한다. 하지만 일반적으로 리스트(와 일반적으로는 컬렉션)

5 배열데이터객체가있지만이는원시타입이아니며어떤특별한구문도없다.또한리스트만큼많이사용하지도않는다.

/ 들 / 어 / 가 / 며 /18

프로그램스타일.indb 18 2015-07-10 오후 1:54:46

Page 18: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

에 대한 여러 파이썬 연산은 색인 연산에 대해 구성주의적이다6. 예를 들어, 요소가 3개뿐

인 리스트에서 범위가 3부터 100까지인 리스트를 얻으려 하면(예를 들면, [10, 20, 30]

[3:100]) IndexError 대신 빈 리스트([])가 반환된다. 이와 비슷하게 리스트를 부분적으로 포

함하도록 범위를 지정하면 그 결과는 IndexError 없이 해당 리스트의 일부를 포함한다(예를

들어 [10, 20, 30][2:10]은 [30]이 된다). 이에 비해 좀 더 엄격한 언어를 사용한 사용자가

이러한 구성주의적 동작 방식을 처음 접하면 혼란스러울 수 있다.

≑ 딕셔너리(Dictionary): 파이썬에서는 딕셔너리 또는 맵 또한 전용 구문으로 지원되는 원

시 데이터 타입이며, mydict = {'a' : 1, 'b' : 2}은 그 예다. 이 딕셔너리에서는 두 문자

열 키를 두 정수 값에 매핑한다. 일반적으로 키와 값은 어떤 타입이든 될 수 있다. 이러한 종류

의 딕셔너리는 자바에서는 HashMap 클래스의 형태로, C++에서는 클래스 템플릿인 map 형태

로 찾을 수 있다.

≑ self: 대부분의 객체 지향 언어에서는 특별한 구문을 통해 암시적으로 객체 자신을 참조할

수 있다. 예를 들면, 자바와 C++의 this, PHP의 $this, 루비의 @이 그렇다. 이러한 언어와 달

리 파이썬에는 이를 위한 특별한 구문이 없다. 게다가 인스턴스 메서드는 단순히 객체를 첫 번

째 매개변수로 취하는 클래스 메서드인데, 이 첫 번째 매개변수를 관례적으로 self라고 할 뿐

언어에서 그렇게 쓰도록 강제하는 것은 아니다. 다음은 인스턴스 메서드가 두 개 포함된 클래

스 정의의 예다.

1 class Example:

2 def set_my_name(self, n):

3 self._name = n

4 def say_my_name(self):

5 print self._name

6 (옮긴이)구성주의는심리학,교육학에서쓰는용어로서자신의경험을바탕으로새로운지식과의미를구성한다는이론이다.예에

서볼수있듯이범위를벗어난색인연산결과가오류가아닌빈리스트이고,범위를일부포함하면그결과역시일부를포함하는

것처럼일반적인인식,즉경험에따라사용할수있음을뜻한다.C같은언어에서는시작과끝범위중하나만벗어나도오류가생기

므로일반적인경험과일치하지않는다.

19/ 들 / 어 / 가 / 며 /

프로그램스타일.indb 19 2015-07-10 오후 1:54:46

Page 19: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

두 메서드 모두 첫 번째 위치에 있는 매개변수 이름이 self이며, 해당 메서드 본체에서

이에 접근한다. self라는 단어 자체에는 특별한 것이 없으며, 메서드에서는 me 또는 my

심지어 this 등 다른 이름을 사용할 수 있지만 self가 아닌 다른 단어를 파이썬 프로그

래머는 그리 달가워하지 않을 것이다. 그런데 아래와 같이 첫 번째 매개변수를 생략하기

때문에 인스턴스 메서드를 호출하는 것이 생소할 수 있다.

e = Example()

e.set_my_name("Heisenberg")

e.say_my_name()

이처럼 매개변수 개수가 일치하지 않는 것은 파이썬에서 점 표기법(‘.’)은 단순히 다음과

같은 더 기초적인 메서드 호출 형식에 대한 편의 구문이기 때문이다.

e = Example()

Example.set_my_name(e, "Heisenberg")

Example.say_my_name(e)

≑ 생성자(Constructor): 파이썬에서 생성자는 (단어 앞뒤로 밑줄이 두 개인) __init__이라는

이름의 일반 메서드다. 파이썬 런타임에서는 객체를 생성한 직후 정확히 이 이름의 메서

드를 자동으로 호출한다. 다음은 생성자가 있는 클래스와 이 클래스의 사용 예다.

1 class Example:

2 # 이 클래스의 생성자

3 def __init__(self, n):

4 self._name = n

5 def say_my_name(self):

6 print self._name

7

8 e = Example("Heisenberg")

9 e.say_my_name()

/ 들 / 어 / 가 / 며 /20

프로그램스타일.indb 20 2015-07-10 오후 1:54:46

Page 20: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

크리스티나 (크리스타) 로페즈(Cristina (Crista) Lopes)는 캘리포니아 대학교

어바인 캠퍼스의 도널드 브렌 정보·컴퓨터 과학 대학원(Donald Bren School

of Information and Computer Sciences)에서 정보과학과 교수로 재직 중이며,

대규모 정보 및 시스템을 위한 소프트웨어 공학에 관해 연구하고 있다. 경력

초기에는 제록스(Xerox) PARC에서 관점 지향 프로그래밍(Aspect-Oriented

Programming)과 AspectJ를 개발한 팀의 창립멤버였다. 자신의 연구 프로그램

과 더불어 많은 것을 개발한 소프트웨어 개발자이기도 하다. 음향 소프트웨어

모뎀을 비롯해 가상 세계 서버인 OpenSimulator 등 오픈소스에도 기여하고 있

으며, 초기 단계의 지속 가능한 도심 재개발 계획을 위한 온라인 가상 현실에 특

화된 회사의 공동 설립자다. OpenSimulator 기반 가상 세계를 위한 검색 엔진

을 개발했으며, 이를 관리하고 있다.

로페즈 박사는 포르투갈 공과대학(Instituto Superior Técnico)에서 학사와 석

사 학위를, 노스이스턴 대학교에서 박사 학위를 받았으며, 명성이 높은 커리어

어워드(CAREER Award)를 포함해 여러 미국 국립과학재단(National Science

Foundation) 연구비 수령자다. 또한 전 세계에서 ACM의 뛰어난 과학자

(Distinguished Scientist)이자 올로 쿠도스 순위(Ohloh Kudos Rank) 9에 모

두 오른 유일한 인물이라 주장한다.

21/ 저 / 자 / 소 / 개 /

프로그램스타일.indb 21 2015-07-10 오후 1:54:47

Page 21: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

01PART

전통적 형식

프로그램스타일.indb 22 2015-07-10 오후 1:54:47

Page 22: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

컴퓨팅 시스템은 의도를 더욱 잘 표현하기 위해 수년에

걸쳐 개발하며, 층층으로 쌓아올린 추상화 계층으로 인

해 양파와 같으므로 내부 계층에서 실제로 포함하고 있

는 것이 무엇인지 아는 것이 중요하다. 처음 두 프로그래

밍 형식은 수십 년 전 프로그래밍이 어땠는지, 그리고 어

느 정도는 최신 시스템의 내부 계층이 여전히 어떤지 보여

준다.

프로그램스타일.indb 23 2015-07-10 오후 1:54:47

Page 23: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

01CHAPTER

1.1 _ 제약조건

≑ 주기억 장치의 양은 매우 적으며, 일반적으로 처리/생성할 데이터에 비해 매우 적다.

≑ 식별자가 없다. 즉, 변수명이나 참조할 꼬리표가 붙은 메모리 주소가 없으며, 숫자로 가리킬 수 있는 메

모리만 있다.

그리운 옛날

프로그램스타일.indb 24 2015-07-10 오후 1:54:47

Page 24: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

2501_그리운옛날

1.2 _ 이러한 형식의 프로그램

1 #!/usr/bin/env python

2

3 import sys, os, string

4

5 # 중간의 '보조 기억 장치'를 처리하는 편의 함수

6 def touchopen(filename, *args, **kwargs):

7 try:

8 os.remove(filename)

9 except OSError:

10 pass

11 open(filename, "a").close() # 파일을 '수정'한다

12 return open(filename, *args, **kwargs)

13

14 # 메모리 제약은 크기가 1024 이하다

15 data = []

16 # 우리는 행운아다:

17 # 의미 없는 단어는 556자에 불과하고 모든 줄은

18 # 80자 미만이므로 문제를 단순화할 수 있다.

19 # 즉, 한 번에 한 줄씩 입력받아 처리하는 동안

20 # 의미 없는 단어를 메모리에 둘 수 있다.

21 # 이 두 가정이 유효하지 않으면 알고리즘을

22 # 상당히 변경해야 한다.

23

24 # 전체 전략: (부분 1) 입력 파일을 읽어 단어를 세고

25 # 보조 기억 장치(파일)에 횟수를 증가/저장한다

26 # (부분 2) 보조 기억 장치에서 가장 빈도가 높은 단어 25개를 찾는다

27

28 # 부분 1:

29 # - 입력 파일에서 한 번에 한 줄씩 읽는다

30 # - 문자를 걸러낸 후 소문자로 정규화한다

31 # - 단어를 식별하고 파일에서 해당하는 횟수를 증가시킨다

32

33 # 의미 없는 단어 목록을 읽어 들인다

34 f = open('../stop_words.txt')

35 data = [f.read(1024).split(',')] # data[0]에는 의미 없는 단어가 있다

36 f.close()

37

프로그램스타일.indb 25 2015-07-10 오후 1:54:47

Page 25: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

26 PART 01 _ 전통적 형식

38 data.append([]) # data[1]은 (최대 80자인) 줄

39 data.append(None) # data[2]는 단어의 시작 문자 색인

40 data.append(0) # data[3]은 문자에 대한 색인이며 i = 0

41 data.append(False) # data[4]는 단어를 찾았는지 여부를 나타내는 플래그

42 data.append('') # data[5]는 해당 단어

43 data.append('') # data[6]은 단어, NNNN

44 data.append(0) # data[7]은 빈도

45

46 # 보조 기억 장치를 연다

47 word_freqs = touchopen('word_freqs', 'rb+')

48 # 입력 파일을 연다

49 f = open(sys.argv[1])

50 # 입력 파일 내의 각 줄을 순회

51 while True:

52 data[1] = [f.readline()]

53 if data[1] == ['']: # 입력 파일 끝

54 break

55 if data[1][0][len(data[1][0])-1] != '\n': # \n으로 끝나지 않으면

56 data[1][0] = data[1][0] + '\n' # \n을 추가한다

57 data[2] = None

58 data[3] = 0

59 # 해당 줄 내 문자를 순회

60 for c in data[1][0]: # 기호 c를 제거하는 것은 연습 문제로 남긴다

61 if data[2] == None:

62 if c.isalnum():

63 # 단어의 시작을 찾았다

64 data[2] = data[3]

65 else:

66 if not c.isalnum():

67 # 단어 끝을 찾았으므로 처리한다

68 data[4] = False

69 data[5] = data[1][0][data[2]:data[3]].lower()

70 # len < 2인 단어와 의미 없는 단어를 무시한다

71 if len(data[5]) >= 2 and data[5] not in data[0]:

72 # 이미 존재하는지 확인한다

73 while True:

74 data[6] = word_freqs.readline().strip()

75 if data[6] == '':

76 break;

77 data[7] = int(data[6].split(',')[1])

78 # 공백 문자가 없는 단어

프로그램스타일.indb 26 2015-07-10 오후 1:54:48

Page 26: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

2701_그리운옛날

79 data[6] = data[6].split(',')[0].strip()

80 if data[5] == data[6]:

81 data[7] += 1

82 data[4] = True

83 break

84 if not data[4]:

85 word_freqs.seek(0, 1) # 윈도우에서는 필요하다

86 word_freqs.writelines("%20s,%04d\n" % (

data[5], 1))

87 else:

88 word_freqs.seek(-26, 1)

89 word_freqs.writelines("%20s,%04d\n" % (

data[5], data[7]))

90 word_freqs.seek(0,0)

91 # 초기화하자

92 data[2] = None

93 data[3] += 1

94 # 입력 파일 처리를 마쳤다

95 f.close()

96 word_freqs.flush()

97

98 # 부분 2

99 # 이제 가장 자주 나온 단어 25개를 찾아야 한다.

100 # 메모리에 있는 이전 값은 전혀 필요 없다

101 del data[:]

102

103 # 상위 25개 단어에 대해 처음 25개 항목만 사용하자

104 data = data + [[]]*(25 - len(data))

105 data.append('') # data[25]는 파일에서 읽은 단어,빈도

106 data.append(0) # data[26]은 빈도

107

108 # 보조 기억 장치(파일)를 순회한다

109 while True:

110 data[25] = word_freqs.readline().strip()

111 if data[25] == '': # EOF

112 break

113 data[26] = int(data[25].split(',')[1]) # 정수로 읽는다

114 data[25] = data[25].split(',')[0].strip() # 단어

115 # 이 단어가 메모리에 있는 단어들보다 횟수가 더 많은지 확인한다

116 for i in range(25): # 기호 i를 제거하는 것은 연습 문제로 남긴다

117 if data[i] == [] or data[i][1] < data[26]:

프로그램스타일.indb 27 2015-07-10 오후 1:54:48

Page 27: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

28 PART 01 _ 전통적 형식

118 data.insert(i, [data[25], data[26]])

119 del data[26] # 마지막 요소를 삭제한다

120 break

121

122 for tf in data[0:25]: # 기호 tf를 제거하는 것은 연습 문제로 남긴다

123 if len(tf) == 2:

124 print tf[0], ' - ', tf[1]

125 # 모두 마쳤다

126 word_freqs.close()

참고

파이썬에 익숙하지 않으면 ‘들어가며’(파이썬주의)에 있는 리스트, 색인 그리고 경계에 관한 설

명을 참고한다.

1.3 _ 해설

이 형식에서 프로그램은 해당 프로그램을 실행하는 제약된 컴퓨팅 환경을 반영한다. 메모

리 한계로 인해 프로그래머는 어쩔 수 없이 사용 가능한 메모리 전체에 걸쳐 데이터를 회전

시키고 계산 작업을 복잡하게 할 수밖에 없다. 게다가 식별자가 없어 프로그램 본문에는 해

당 문제를 자연스럽게 설명하는 용어 역시 없으므로 주석과 문서화를 통해 대신 추가했다.

1950년대 초 프로그래밍이 이랬다. 하지만 이 형식은 사라지지 않았으며, 하드웨어를 직접

다루거나 메모리 사용을 최적화할 때 오늘날에도 여전히 사용한다.

이러한 제약에 처해본 적 없는 프로그래머에게 이 예제 프로그램은 꽤 낯설지도 모른다. 이

는 분명 파이썬이나 최신 프로그래밍 언어 중 무엇과도 연관되지 않은 프로그램인 동시에

프로그래밍 형식은 제약조건에서 창발한다는 이 책의 주제를 꽤 잘 보여준다. 하드웨어 메

모리가 제한적이거나 어셈블리 언어에서는 식별자를 지원하지 않거나 성능이 매우 중요해

서 시스템을 직접 처리해야 하는 등 제약조건이 외부로부터 생기는 일은 비일비재하다. 게

다가 유지보수성, 가독성, 확장성, 문제 영역에 대한 타당성, 해당 부분에 대한 개발자의 과

거 경험 등 다른 여러 이유로 프로그래머나 개발 팀 전체가 문제에 관해 생각하고 코드를

작성하는 데 특정 방법을 고수하는 등 어떤 때에는 스스로 제약을 가하기도 한다. 또는 단

프로그램스타일.indb 28 2015-07-10 오후 1:54:48

Page 28: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

2901_그리운옛날

순히 이 책처럼 새로운 구문을 배우지 않고 저수준 프로그래밍의 형태가 어떤지 가르치기

위해서일 수도 있다. 사실 저수준의 ‘그리운 옛날(Good Old Times)’ 형식의 프로그램은

거의 모든 프로그래밍 언어로 작성할 수 있다!

단어 빈도를 이처럼 특이하게 구현한 이유를 설명하기 위해 이 프로그램에 깊숙이 들어가

보자. 메모리 한계로 인한 영향은 너무 커서 처리할 데이터 크기를 무시할 수 없다. 예제에

서는 자체적으로 메모리 크기를 1024로 한정했다(줄 번호 #151). 여기서 ‘메모리(memory

cell)’라는 용어는 대략 문자나 숫자 같은 간단한 데이터 하나를 나타내기 위해 다소 애매한

방법으로 사용했다. 오만과 편견처럼 문자가 1024보다 훨씬 많은 책이 제공되면 데이터를

작은 덩어리로 나눠 읽고 처리하며, 주기억 장치에 맞지 않은 데이터를 저장하기 위해 ‘보조

기억 장치(파일)’를 과도하게 사용하는 방법을 생각해 낼 필요가 있다. 코드 작성을 시작하

기 전에 주기억 장치에 둘 것과 보조 기억 장치에 넣을 것, 그리고 언제 그렇게 할 것인지에

관한 여러 다른 선택에 대해 간단히 계산해 볼 필요가 있다(#16에서 #26의 주석 참고). 주

기억 장치에 접근하는 것은 보조 기억 장치에 접근하는 것에 비해 매우 빠르므로 이러한 계

산은 성능을 위한 최적화와 관련이 있다.

선택의 가능성은 무한하므로 이 형식 내에서 선택할 수 있는 수많은 해결책이 모여있는 그

우주를 탐사해 보길 권장한다. 예제 프로그램은 두 부분으로 나뉜다. 첫 번째 부분(#28에서

#98)에서는 입력 파일을 처리하고 나온 단어를 세며 그 데이터를 단어 빈도 파일에 기록한

다. 두 번째 부분(#100에서 #128)에서는 25개의 가장 자주 나온 단어를 찾기 위해 중간의

단어 빈도 파일을 처리하고 마지막엔 그 단어를 출력한다.

프로그램 첫 번째 부분에서는 다음과 같은 순서로 일을 처리한다.

≑ 대략 500자에 달하는 의미 없는 단어를 주기억 장치에 담는다(#33에서 #36)

≑ 입력 파일을 한 번에 한 줄씩 읽는데, 각 줄은 최대 80자에 불과하다(#50에서 #95)

≑ 각 줄에 대해 문자를 걸러내고 단어를 식별하며, 그 단어를 소문자로 정규화한다(#60에서 #95)

≑ 단어와 그 빈도를 보조 기억 장치에서 가져오거나 그 메모리에 기록한다(#73에서 #90)

1 (옮긴이) 바로 앞 절의 소스코드 줄 번호를 뜻하며, 이후 줄 번호라는 표현은 생략한다.

프로그램스타일.indb 29 2015-07-10 오후 1:54:48

Page 29: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

30 PART 01 _ 전통적 형식

이처럼 입력 파일 전체를 처리하고 나면 중간 파일에 누적한 단어 빈도로 주의를 돌린다.

가장 자주 나타나는 단어를 정렬한 목록이 필요하므로 프로그램에서는 다음을 처리한다.

≑ 현재 가장 자주 나타나는 단어 25개와 그 빈도를 담고 있는 메모리를 순서 있는 리스트로 유지한다.

≑ 파일에서 한 번에 한 줄씩 읽는다. 각 줄에는 단어와 그에 해당하는 빈도가 있다(#108에서 #120).

≑ 새 단어가 메모리에 있는 어떤 단어보다도 빈도가 더 크면 그 리스트 내의 적절한 위치에 삽입하고 리

스트 끝에 있는 단어를 제거한다(#116에서 #120).

≑ 마지막으로 상위 25개 단어와 그 빈도를 출력(#122에서 #124)하고 중간 파일을 닫는다(#126).

보다시피 어떤 특정 시점에 메모리에 존재하는 데이터가 얼마나 되는지 반드시 신경 써야

할 만큼 메모리 제약조건은 사용할 알고리즘에 큰 영향을 미친다.

이 형식에서 스스로 부과하는 두 번째 제약조건은 식별자가 없다는 점이다. 이 두 번째 제

약조건 또한 프로그램에 큰 영향을 미치지만 이 영향은 본질적으로 다른, 즉 가독성에 관한

것이다. 변수가 없으므로 숫자로 가리켜 접근하는 데이터 메모리만 존재한다. 프로그램 본

문에는 이 문제에 담긴 개념(단어, 빈도, 횟수, 정렬 등)이 전혀 없으며, 메모리에 대한 색인

을 통해 간접적으로 그러한 개념을 표현한다. 그러한 개념을 상기시키는 유일한 방법은 메

모리에 담긴 데이터의 종류가 무엇인지 설명하는 주석을 추가하는 것이다(이를테면, 그중

에서도 #38에서 #44, 그리고 #103에서 #106에 걸친 코드를 참고한다). 프로그램을 읽을

때는 어떤 메모리 색인에 해당하는 고수준 개념이 무엇인지 떠올리기 위해 종종 그러한 주

석을 다시 살펴볼 필요가 있다.

프로그램스타일.indb 30 2015-07-10 오후 1:54:48

Page 30: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

3101_그리운옛날

1.4 _ 시스템 설계 관점에서 본 이러한 형식

컴퓨터에 램을 기가바이트 단위로 장착하는 시대에 여기서 살펴본 메모리 제약은 대부분

과거의 희미한 기억에 지나지 않는다. 그럼에도 메모리 관리를 잊게 하는 최신 프로그래밍

언어를 사용하거나 오늘날 프로그램이 다루는 데이터의 양이 점점 늘어남에 따라 프로그램

메모리 소비를 통제할 수 없게 되어 결과적으로 실행 성능에 나쁜 영향을 주기 쉽다. 프로

그래밍 형식에 따른 메모리 사용량에 대해 어느 정도 인식하고 있는 것은 언제나 바람직한

현상이다.

오늘날, 이른바 빅 데이터(Big Data)로 알려진 환경에 처한 여러 응용 프로그램에서는 적

은 메모리를 다루는 복잡한 기법으로 다시 눈을 돌렸다. 이 같은 상황에서는 메모리가 절대

적으로 부족하지는 않을지라도 처리할 데이터 크기에 비해서는 훨씬 적다. 예를 들어, 단어

빈도를 단지 오만과 편견 대신 구텐베르크 프로젝트 전체에 적용한다면 메모리에 모든 책

을 동시에 담을 수 없을뿐더러 모든 단어 빈도 목록을 메모리에 담을 수도 없을 것이다. 일

단 데이터를 동시에 메모리에 넣을 수 없으면 개발자는 (1) 어떤 특정 시점에 메모리에 맞게

넣을 수 있도록 데이터를 나타내고 (2) 주기억 장치와 보조 기억 장치에 걸쳐 데이터를 회

전시키기 위한 현명한 계획을 반드시 고안해야 한다. 이러한 제약조건에 따른 프로그래밍

은 프로그램을 ‘그리운 옛날’ 형식 같은 느낌이 들게 하는 경향이 있다.

이름이 없는 것과 관련해서 1950년대에서 1960년대에 걸친 프로그래밍 언어 발전의 이면

에 숨어 있는 주된 원동력 중 하나는 이 예에서 보여준 것과 같은 간접적 인지 수단을 제거

하는 것이었다. 즉, 프로그램 본문에 저수준 시스템 개념을 반영한 후 외부 문서를 통해 프

로그램과 개념을 매핑하는 대신 해당 영역의 고수준 개념을 가능한 한 많이 반영하는 것이

다. 하지만 프로그래밍 언어에서 사용자가 직접 정의하고 명명한 추상화를 제공한 지 오래

됐음에도 프로그래머가 자신이 만든 프로그램 요소, 응용 프로그램 프로그래밍 인터페이스

(API; Application Programming Interface), 전체 구성 요소에 적절한 이름을 부여하

지 못해 결과적으로 프로그램, 라이브러리, 시스템이 여기서 본 것만큼이나 불분명해지는

것을 흔히 볼 수 있다.

메모리에 그렇게 많은 데이터를 담을 수 있고 프로그램의 모든 요소를 적절히 명명할 수 있

다는 사실이 얼마나 감사한지 이 ‘그리운 옛날’ 형식을 꼭 기억하자!

API(Application Programming Interface)

프로그램스타일.indb 31 2015-07-10 오후 1:54:49

Page 31: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

32 PART 01 _ 전통적 형식

1.5 _ 역사적 기록

이 프로그래밍 형식은 최초로 실행 가능한 계산 모델인 튜링 기계(Turing Machine)에

서 직접적으로 유래했다. 튜링 기계는 무한하고, 변경 가능한 상태인 ‘테이프’(데이터 메

모리)와 그 상태를 읽고 변경하는 상태 기계로 구성된다. 튜링 기계는 컴퓨터 개발과 컴

퓨터를 프로그래밍하는 방법에 지대한 영향을 끼쳤다. 튜링의 아이디어는 폰 노이만(von

Neumann) 구조, 즉 프로그램이 내장된 최초의 컴퓨터에 영향을 미쳤다. 또한 튜링은 자

동 계산 기계(Automatic Computing Engine; ACE)로 알려진 계산 기계에 관한 명세도

직접 작성했으며, 이는 많은 부분에서 폰 노이만 구조에 비해 더 진보적이었다. 영국 정부

에서는 그 보고서를 기밀로 취급하고 2차 세계 대전에 따른 정치적 문제로 인해 수년이 지

난 후까지도 튜링의 설계를 실행에 옮기지 못했으며 여전히 비밀로 남았다. 폰 노이만 구조

와 튜링 기계 모두 1950년대에 탄생한 최초의 프로그래밍 언어로 이어지며, 이 언어에서는

오랜 시간 동안 메모리 내 상태를 재사용하고 변경하는 프로그래밍 개념을 강제했다.

1.6 _ 더 읽을거리

Bashe, C., Johnson, L., Palmer, J. and Pugh, E. (1986). IBM’s Early Computers: A Technical

History (History of Computing), MIT Press, Cambridge, MA.

개요: IBM은 컴퓨터 시스템 초창기의 주요 상용 제품 판매자였다. 이 책에서는 IBM이 전기 기계식 기

계 제조자에서 컴퓨터 시스템의 최강자로 변모한 이야기를 들려준다.

Carpenter, B.E. and Doran, R.W. (1977). The other Turing Machine. Computer Journal 20(3):

269-279.

개요: 폰 노이만의 구조를 기반으로 하지만 서브루틴, 스택 그리고 더 많은 것을 포함하는 계산 기계

에 대한 완전한 구조를 기술하는 튜링의 기술 보고서 중 하나에 관한 기사. 보고서 원문은 다음 URL

에서 확인할 수 있다.

http://www.npl.co.uk/about/history/notable-individuals/turing/ace-proposal

ACE(Automatic Computing Engine)

프로그램스타일.indb 32 2015-07-10 오후 1:54:49

Page 32: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

3301_그리운옛날

Turing, A. (1936). On computable numbers, with an application to the Entscheidungs problem.

Proceedings of the London Mathematical Society 2(42): 230-265.

개요: 최초의 ‘튜링 기계.’ 이 책의 맥락에서는 해당 논문의 수학적 내용이 아니라, 기호를 사용하는

테이프와 좌우로 이동하는 테이프 판독기/기록기, 그리고 테이프에 기호를 덮어쓰는 등 튜링 기계의

프로그래밍 모델 측면에서 이 논문을 추천한다.

von Neumann, J. (1945). First draft of a report on the EDVAC. Reprinted in IEEE Annals of the

History of Computing 15(4): 27-43, 1993.

개요: 최초의 ‘폰 노이만 구조.’ 튜링의 논문과 마찬가지로 프로그래밍 모델 측면에서 추천한다.

1.7 _ 용어 사전

주기억 장치: 간단하게 메모리로 지칭할 때가 많다. 이 데이터 저장 공간은 CPU에서 직접

접근할 수 있다. 이 저장 공간에 있는 데이터는 대부분 해당 데이터를 사용하는 프로

그램 실행이 끝나면 지속되지 않는다는 점에서 휘발성이며, 시스템 전원을 꺼도 사라

진다. 오늘날 주기억 장치는 임의 접근 메모리(RAM)인데, 이는 순차적으로 검색하

는 것이 아니라 CPU에서 어느 메모리 위치든 재빨리 주소로 가리킬 수 있음을 의미

한다.

보조 기억 장치: 주기억 장치와 대조적으로 보조 기억 장치는 CPU에서 직접 접근할 수 없

는 대신 입출력 통로를 통해 간접적으로 접근할 수 있는 모든 저장 장치를 가리킨다.

보조 기억 장치에 있는 데이터는 전원을 끄더라도 명시적으로 삭제하지 않는 한 해당

장치에 계속 존재한다. 최신 컴퓨터에서 하드디스크 드라이브와 USB 드라이브는 가

장 일반적인 형태의 보조 기억 장치다. 보조 기억 장치에 접근하는 것은 주기억 장치

에 비해 매우 느리다.

프로그램스타일.indb 33 2015-07-10 오후 1:54:49

Page 33: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

34 PART 01 _ 전통적 형식

1.8 _ 연습 문제

1.1 다른 언어. 형식을 유지한 채 예제 프로그램을 다른 언어로 구현한다.

1.2 식별자를 사용하지 않음. 예제 프로그램에는 #60(c), #116(i), #122(tf) 등 식별자가 몇 개 있다. 프로그램

을 변경해 이 식별자도 제거한다.

1.3 더 많은 줄. 예제 프로그램에서는 한 번에 한 줄씩 읽어 메모리에 넣는데, 이는 주기억 장치를 충분히

이용하지 않고 있다. 프로그램을 변경해 정해둔 메모리 한계인 1024를 넘지 않으면서 가능한 한 많은

줄을 메모리에 적재하게 한다. 읽어 들이는 줄 수에 대한 근거를 제시하고 여러분이 작성한 버전이 원

래 예제 프로그램보다 더 빠르게 실행되는지 확인한 후 결과를 설명한다.

1.4 다른 작업. ‘그리운 옛날’ 형식을 이용해 ‘들어가며’에서 제안한 작업 중 하나를 작성한다.

프로그램스타일.indb 34 2015-07-10 오후 1:54:49

Page 34: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

19.1 _ 제약조건

≑ 문제를 어떤 추상 형태(프로시저, 함수, 객체 등)를 사용해 분해한다.

≑ 그러한 추상의 전부 또는 일부를 일반적으로 미리 컴파일해 두는 자체적인 꾸러미(package)에 물리적

으로 캡슐화한다. 주 프로그램과 각 꾸러미는 독립적으로 컴파일한다. 주 프로그램에서는 이러한 꾸러

미를 일반적으로(반드시 그런 것은 아니지만) 프로그램을 시작할 때 동적으로 적재한다.

≑ 주 프로그램은 동적으로 적재한 꾸러미에서 함수/객체를 사용하지만 정확한 구현 내용은 모른다. 주 프

로그램을 고치거나 다시 컴파일하지 않고 새로운 구현 내용을 사용할 수 있다.

≑ 어느 꾸러미를 적재할지 지정하는 외부 명세가 존재한다. 이는 실행 중 적재할 코드에 관한 외부 명세

를 위한 설정 파일, 약속해 둔 경로, 사용자 입력 또는 그 밖의 메커니즘으로 처리할 수 있다.

19CH

APT

ER

플러그인

Page 35: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

176 PART 05 _ 반영과 메타프로그래밍

19.2 _ 이러한 형식의 프로그램

tf-19.py:

1 #!/usr/bin/env python

2 import sys, ConfigParser, imp

3

4 def load_plugins():

5 config = ConfigParser.ConfigParser()

6 config.read("config.ini")

7 words_plugin = config.get("Plugins", "words")

8 frequencies_plugin = config.get("Plugins", "frequencies")

9 global tfwords, tffreqs

10 tfwords = imp.load_compiled('tfwords', words_plugin)

11 tffreqs = imp.load_compiled('tffreqs', frequencies_plugin)

12

13 load_plugins()

14 word_freqs = tffreqs.top25(tfwords.extract_words(sys.argv[1]))

15

16 for (w, c) in word_freqs:

17 print w, ' - ', c

config.ini:

1 [Plugins]

2 ;; Options: plugins/words1.pyc, plugins/words2.pyc

3 words = plugins/words1.pyc

4 ;; Options: plugins/frequencies1.pyc, plugins/frequencies2.pyc

5 frequencies = plugins/frequencies1.pyc

words1.py:

1 import sys, re, string

2

3 def extract_words(path_to_file):

4 with open(path_to_file) as f:

5 str_data = f.read()

6 pattern = re.compile('[\W_]+')

Page 36: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

17719_플러그인

7 word_list = pattern.sub(' ', str_data).lower().split()

8

9 with open('../stop_words.txt') as f:

10 stop_words = f.read().split(',')

11 stop_words.extend(list(string.ascii_lowercase))

12

13 return [w for w in word_list if not w in stop_words]

words2.py:

1 import sys, re, string

2

3 def extract_words(path_to_file):

4 words = re.findall('[a-z]{2,}', open(path_to_file).read().lower())

5 stopwords = set(open('../stop_words.txt').read().split(','))

6 return [w for w in words if w not in stopwords]

frequencies1.py

1 import operator

2

3 def top25(word_list):

4 word_freqs = {}

5 for w in word_list:

6 if w in word_freqs:

7 word_freqs[w] += 1

8 else:

9 word_freqs[w] = 1

10 return sorted(word_freqs.iteritems(), key=operator.itemgetter

(1), reverse=True)[:25]

frequencies2.py

1 import operator, collections

2

3 def top25(word_list):

4 counts = collections.Counter(w for w in word_list)

5 return counts.most_common(25)

Page 37: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

178 PART 05 _ 반영과 메타프로그래밍

19.3 _ 해설

이 형식은 소프트웨어 진화와 맞춤 제작의 중심에 있다. 다른 개발자 또는 심지어 동일한

개발자가 나중에 기능을 더 확장할 예정인 소프트웨어를 개발하는 경우에는 폐쇄형 소프트

웨어에는 존재하지 않는 갖가지 도전과제를 해결해야 한다.

예제 프로그램을 살펴보자. 주요 아이디어는 주 프로그램을 중요한 상세 구현 내용 없이

두 가지 단어 빈도 함수를 실행하는 ‘껍질’로만 남겨 두는 것이다. 이 예제에서는 단어 빈

도 응용 프로그램을 두 단계로 분리하는데, 첫 단계에서는 extract_words를 호출해 입력

파일을 읽고 의미 없는 단어 목록을 만들어 내고, 두 번째 단계에서는 top25를 호출해 단

어 목록을 취하고 나온 횟수를 센 다음 가장 자주 나온 단어 25개를 그 횟수와 함께 반환한

다. 이 두 단계는 tf-19.py의 #14에서 볼 수 있다. 주 프로그램인 tf-19.py는 tfwords.

extract_words 함수와 tffreqs.top25 함수에 관해서는 존재한다는 점 외에는 아무것도

알지 못한다는 점에 주의한다. 우리는 나중에 그러한 함수 구현 내용을 선택할 수 있고,

심지어 이 프로그램의 사용자가 자신이 직접 만든 구현 내용을 제공할 수 있어야 한다.

프로그램을 실행하기 전에 주 프로그램에서는 어느 함수를 사용할지 알아야 하며, 이는 외

부 설정 파일로 지정한다. 단어 빈도 함수를 호출하기 전에 주 프로그램이 처리하는 첫 번

째 일은 해당 플러그인을 적재하는 것이다(#13). load_plugins(#4-11)는 먼저 설정 파일

인 config.ini를 읽고(#5-6) 두 함수에 관한 설정을 구한다(#7-8). 설정 파일에는 설정

변수인 words(#7)와 frequencies(#8)를 찾을 수 있는 구역 이름인 Plugins가 있다고 가

정한다. 또한 각 변수 값은 미리 컴파일한 파이썬 코드에 대한 경로를 가리키기로 돼 있다.

다음 세 줄을 설명하기 전에 설정 파일의 형태가 어떤지 살펴보자(config.ini 참조). INI

라고 하는 유명한 설정 형식을 사용하고 있으며, 이는 프로그래밍 세계에서 전반적으로 지

원하는 형식이다. 파이썬 표준 라이브러리에서는 ConfigParser 모듈로 지원된다. INI 파

일은 매우 간단하고 한 줄로 된 [구역명]으로 나타내는 구역으로 구성되며, 각 구역에는 설

정 변수와 값을 키-값 쌍(이름=값)이 한 줄당 하나씩 나열된다. 예제에서는 [Plugins](#1)

라는 구역 하나와 words(#3)와 frequencies(#5)라는 변수가 두 개 있다. 이 두 변수 모두

파일 시스템 내 경로를 가리키는 값을 담고 있는데, 예를 들면 words는 plugins/words1.

pyc로 설정했으며 이는 현재 디렉터리의 하위 디렉터리에 있는 파일을 사용해야 한다는 의

미다. 이 변수 값을 변경해 사용할 플러그인을 바꿀 수 있다.

Page 38: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

17919_플러그인

이 설정 파일을 읽는 tf-19.py의 #5-8로 되돌아오자. 다음 세 줄(#9-11)에서는 설정에서

지정한 파일에 있는 코드를 동적으로 적재한다. 이는 파이썬의 imp 모듈을 이용해 처리하

는데, 이 모듈은 import 문 내부에 대한 반영(reflective) 인터페이스를 제공한다. #9에서

는 두 전역 변수인 tfwords와 tffreqs를 선언하며, 이는 모듈 그 자체를 뜻한다. 그런 다

음 #10과 #11에서는 지정한 경로에서 찾은 코드를 적재하고 이를 모듈 변수와 결합한다.

imp.load_compiled는 미리 컴파일한 파이썬 파일에 대한 이름과 경로를 취해 그 코드를

메모리에 적재한 후 해당 모듈 객체를 반환한다. 그러므로 그 객체를 모듈 이름과 결합해

둬야 주 프로그램의 나머지 부분(특히 #14)에서 이를 사용할 수 있다.

예제 프로그램의 나머지 부분인 words1.py, words2.py frequencies1.py,

frequencies2.py에서는 단어 빈도 함수의 다른 구현을 볼 수 있다. words1.py와

words2.py에서는 extract_words 함수에 대한 대체 기능을 제공하고 frequencies1.py

와 frequencies2.py에서는 top25 함수에 대한 대체 기능을 제공한다.8

19.4 _ 시스템 설계 관점에서 본 이러한 형식

이 형식의 대안, 즉 특정 기능의 다양한 구현을 지원한다는 동일한 목적을 달성하는 것들을

이해하는 것이 중요하다. 또한 그러한 대안의 한계와 이 프로그래밍 형식의 이점을 이해하

는 것 역시 중요하다.

기능은 같으나 구현이 다른 것을 지원하고 싶을 때는 호출자가 특정 구현을 요청하고 팩터

리 메서드에서는 올바른 객체를 반환하는 팩터리 패턴(Factory Pattern)과 같은 유명한

디자인 패턴을 사용해 호출자를 그러한 함수로부터 보호할 수 있다. 가장 단순화한 형식으

로 보면 팩터리는 사전에 정의한 여러 대체 기능에 대한 조건문에 지나지 않는다. 사실 대

체 기능을 지원하는 가장 단순한 방법은 조건문을 사용하는 것이다.

8� �프로그램이�있는�그대로�작동하려면�먼저�이러한�파일을�.pyc�파일로�컴파일해�둬야�한다는�점에�주의한다.

Page 39: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

180 PART 05 _ 반영과 메타프로그래밍

조건문과 연관 메커니즘은 프로그램 설계 시점에 대체 기능 집합을 알고 있다고 가정한다.

이 같은 상황에서 플러그인 형식은 지나친 면이 있고 단순 팩터리 패턴이 그 목적에 적합할

것이다. 하지만 대체 기능 집합을 정해두지 않았을 때 조건을 사용하면 금방 힘들어진다.

새로운 대체 기능마다 팩터리 코드를 편집하고 다시 컴파일해야 하기 때문이다. 더욱이 기

반 프로그램의 소스코드에 반드시 접근할 필요는 없는 서드파티에 대체 기능 집합을 열어

두기로 한다면 대체 기능을 하드코딩하는 방법으로는 그 목적을 이루기가 완전히 불가능하

며 반드시 코드를 동적으로 적재해야 한다. 최신 프레임워크는 용도별 맞춤 제작을 지원하

기 위한 이러한 프로그래밍 형식을 지원하고 있다.

최신 운영체제에서도 공유 동적 연결 라이브러리(이를테면, 리눅스에서는 .so이고 윈도우

에서는 .DLL인)를 지원한다.

하지만 이를 남용할 경우 이러한 형식으로 작성한 소프트웨어는 수많은 설정과 이해하기

어려울 수 있는 서로 다른 수많은 대체 기능으로 인해 ‘설정 지옥(configuration hell)’에

빠질 수 있다. 더욱이 맞춤 제작 요소가 서로 다른 대체 기능이 서로에게 의존하면 소프트

웨어가 이유도 모른 채 실패할 수 있다. 오늘날 사용하는 간단한 설정 언어는 외부 모듈 간

의 의존성을 표현하는 데 부족하기 때문이다.

19.5 _ 역사적 기록

이 형식의 기원은 다소 모호하지만 두 가지 개별적인 연구 흐름, 즉 서드파티 코드를 이용해

독립형 응용 프로그램을 확장하기 위한 요구와 분산 시스템 구조를 거치면서 퍼진 듯하다.

1970년대에 제록스 PARC에서 설계했고 제록스 스타(Xerox Star) 사무 자동화 시스템에

서 사용한 프로그래밍 언어인 메사(Mesa)에는 모듈 집합을 함께 결합해 완전한 시스템으

로 구성하는 방법을 링커에 알리는 데 사용하는 설정 언어가 있었다. C/메사는 (추상 사물

형식과 유사하게) 인터페이스와 구현 모듈을 분리하는 것이 특징이었으므로 C/메사 프로그

램은 구현 모듈의 내보내기(export)와 들여오기(import)를 함께 결합할 수 있었다. 이는

운영체제의 여러 변형을 하나로 조립하는 데 사용됐다.

Page 40: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

18119_플러그인

1980년대 중반에 이르자 몇몇 복잡한 네트워크 제어 시스템이 만들어졌고, 이 시스템은 서

로 연결해야 할 뿐만 아니라 잠재적으로는 다른 구성 요소로 대체할 수 있는 여러 독립 구

성 요소의 모음으로 생각할 필요가 있었다. 그 결과, 설정 언어가 제안되기 시작했다. 이

러한 설정 언어에서는 ‘설정 프로그래밍’을 별도의 관심사로서 제안하며, 기능적 구성 요

소와 그 요소의 내부 연결을 분리하는 개념을 담고 있었다. 이 연구 흐름은 1990년대까지

이어져서 오늘날 소프트웨어 아키텍처로 알려졌으며 설정 언어는 구조 기술 언어(ADL;

Architecture Description Language)가 됐다. 1990년대 동안 제안된 많은 ADL은 강

력했지만 시스템 분석을 위한 단순한 언어였으며 실행 가능한 언어는 아니었다. 이는 실행

중에 구성 요소를 링크하는 것이 (거의 C 기반이었던) 당시 주류 프로그래밍 언어의 기술로

는 처리하기 어려운 일이라는 점도 어느 정도 작용했다. 실행할 수 있는 ADL은 주류가 아

닌 틈새 언어를 사용했다.

1990년대에 이르러 몇몇 데스크톱 응용 프로그램은 플러그인을 이미 지원했다. 예를 들면,

포토샵(PhotoShop)은 초창기부터 ‘핵심’ 응용 프로그램을 사용자가 추가할 수 있는 몇몇

이미지 필터와 깔끔하게 분리할 수 있는 개념이 있었고, 데스크톱 하드웨어를 기반으로 이

미지 처리 기능을 사용자가 정의할 수도 있었다.

반영 능력을 지닌 주류 프로그래밍 언어의 출현으로 실행 중에 구성 요소를 링크하는 것이

갑자기 가능해지고 매우 쉬워지자 이에 대한 처리 방식이 바뀌었다. 스프링(Spring)과 같

은 자바 프레임워크는 반영으로 제공하는 새로운 능력을 포함한 첫 번째 사례였다. 더 많은

언어가 반영을 포함하기 시작하면서 공학 시스템에서 이 형식은 ‘의존성 주입(dependency

injection)’ 또는 ‘플러그인’이라는 이름으로 업계에 널리 퍼졌다. 이러한 사례를 통해 ADL

은 INI나 XML과 같은 단순한 선언형 설정 언어로 돌아왔다.

ADL(Architecture Description Language)

Page 41: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

182 PART 05 _ 반영과 메타프로그래밍

19.6 _ 더 읽을거리

Fowler, M. (2004). Inversion of control containers and the dependency injection pattern.

블로그�글: http://www.martinfowler.com/articles/injection.html

개요: OOP 프레임워크를 배경으로 제어 역전과 의존성 주입을 설명한다.

Kramer, J., Magee, J., Sloman, M. and Lister, A. (1983). CONIC: An integrated approach to

distributed computer control systems. IEE Proceedings 130(1): 1-10.

개요: 구조 기술 언어를 처음으로 그렇게 부르게 된 것에 대한 설명.

Mitchell, J., Maybury, W. and Sweet, R. (1979). Mesa Language Manual. Xerox PARC

Technical Report CSL-79-3.

http://bitsavers.trailing-edge.com/pdf/xerox/mesa/5.0_1979/documentation/CSL_79-3_Mesa_

Language_Manual_Version_5.0_Apr79.pdf에서 볼 수 있다.

개요: 메사는 정말 흥미로운 언어다. 모듈라(Modula) 같은 언어인 까닭에 모듈성에 관한 문제에 집중

했다. 메사 프로그램은 인터페이스를 지정하는 정의 파일과 해당 인터페이스 내 프로시저 구현을 지

정한 프로그램 파일 하나 이상으로 구성됐다. 메사는 모듈라-2와 자바와 같은 다른 언어의 설계에

큰 영향을 끼쳤다.

19.7 _ 용어 사전

서드파티 개발: 소프트웨어의 일부분에 대한 개발을 해당 소프트웨어를 개발한 개발자와

다른 개발자 그룹에서 만드는 것. 일반적으로 서드파티 개발은 해당 소프트웨어의 소

스코드가 아니라 바이너리 형태에만 접근한다.

의존성 주입: 함수/객체 구현을 동적으로 들여오는 것(importing)을 지원하는 기법의

모음.

플러그인(다른 말로 애드온): 다시 컴파일하지 않고 실행 중인 응용 프로그램에 특정 행위

집합을 추가하는 소프트웨어 구성 요소.

Page 42: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법

18319_플러그인

19.8 _ 연습 문제

19.1 다른 언어. 형식을 유지한 채 예제 프로그램을 다른 언어로 구현한다.

19.2 다른 추출 방법. extract_words에 대한 세 번째 대체 기능을 제공한다.

19.3 폐쇄형. words1.py, words2.py, frequencies1.py, frequencies2.py는 예제 프로그램에서 지금껏 고

려한 유일한 대체 가능 기능이다. 플러그인 형식을 사용하지 않고 프로그램을 어떻게 변형할 수 있

을지 보인다.

19.4 출력 대체 기능. 예제 프로그램에서는 마지막에 단어 빈도를 출력하도록 하드코딩돼 있다(#16-27).

이를 플러그인 형식으로 변형하되 마지막에 해당 정보를 출력하는 대체 기능을 적어도 두 가지 제공

한다.

19.5 소스코드 링크. load_plugins 함수를 변경해 파이썬 소스코드로 된 모듈도 적재할 수 있게 한다.

19.6 다른 작업. 이 형식을 사용해 ‘들어가며’에서 제안한 작업 중 하나를 작성한다.

Page 43: 프로그래밍 패턴 : 프로그램을 작성하는 33가지 방법