요즘 대부분의 시간을 Cambridge에서 보내는 관계로 오늘은 MIT의 Big Data Processing에 관한  겨울 수업에 잠깐 들어갔습니다. 오늘 수업은 MapReduce에 관한 것이었는데, MapReduce자체가 새로울 것은 없지만, 개념부터 Amazon Web Service를 사용한 실전까지 1시간 내에 따라해볼 수 있는 내용이라 여기서 간단히 소개합니다. 

http://dataiap.github.com/dataiap/

대부분 아시겠지만, MapReduce는 대용량 데이터 처리를 위한 프레임웍으로, 구글 논문에 처음 소개된 이래로 Yahoo 주도로 개발한 Hadoop 프레임웍이 널리 사용되고 있습니다. 최근에는 Amazon Web Service에서 가입형으로 사용할 수 있는 MapReduce 클러스터를 제공하여 Netflix를 포함한 많은 기업에서 활용하고 있습니다. 

오늘 실습은 MapReduce Python를 사용하여 Enron 이메일 코퍼스의 문서별 단어개수를 세고, 이를 Amazon클러스터에서 실행하는 것이었습니다. 구체적인 내용은 오늘의 강의자료를 참조하시고, 저는 맛보기로 여기 제가 실행한 코드와 결과물을 올릴까 합니다. 강의에서는 이를 좀더 심화하여 tf-idf계산까지를 다루었습니다. 

import sys
from mrjob.protocol import JSONValueProtocol
from mrjob.job import MRJob
from term_tools import get_terms

class MRWordCount(MRJob):
    INPUT_PROTOCOL = JSONValueProtocol
    OUTPUT_PROTOCOL = JSONValueProtocol

    def mapper(self, key, email):
        for term in get_terms(email['text']):
            yield term, 1

    def reducer(self, term, occurrences):
        yield None, {'term': term, 'count': sum(occurrences)}

if __name__ == '__main__'
MRWordCount.run() 
mapper에서 문서별 단어 개수를 세어 이를 단어별로 모아 reduce에서 합산하는 위 예제 코드를 아마존 클러스터에서 실행한 결과는 다음과 같습니다. 약 17~8분 정도에 완료되었습니다. (저도 아마존 클러스터는 처음 사용해 보았습니다.)

Running time was 1051.0s (not counting time spent waiting for the EC2 instances)

ec2_key_pair_file not specified, going to S3

Fetching counters from S3...

Waiting 5.0s for S3 eventual consistency

Counters from step 1:

  FileSystemCounters:

    FILE_BYTES_READ: 197488305

    FILE_BYTES_WRITTEN: 58258678

  Job Counters :

    Launched map tasks: 167

    Launched reduce tasks: 33

    Rack-local map tasks: 167

  Map-Reduce Framework:

    Map input bytes: 1405888038

    Map input records: 516893

    Map output bytes: 585440070

    Map output records: 49931418

    Reduce input groups: 232743

    Reduce input records: 49931418

    Reduce output records: 232743

    Reduce shuffle bytes: 26548380

    Spilled Records: 134445547  

사실 이 자체가 대단한 내용은 아니지만, 아직도 국내에서 신기술로 인식되고 있는 MapReduce가 (요즘은 안 그런가요?) 미국 대학의 교양 강좌에 소개될 정도로 툴 및 인프라가 발전했다는 사실을 느꼈습니다. MapReduce를 검색에 사용하는 방법을 좀더 배우고픈 분들은 Maryland의 Jimmy Lin 교수가 공개한 온라인 책을 읽어보시고, 위 수업에서는 이외에도 Python을 사용한 통계 및 데이터 시각화를 다루니, 참고하시기 바랍니다. 

예전에 연구자로서 개발(programming)을 한다는 것에 대한 글을 쓴적이 있지만, 박사 논문 Proposal 등을 준비하느라 코드에 한동안 손을 대지 못하다가 최근에야 다시 시작할 수 있었습니다. 예전 글에서도 파트타임 개발자(?)의 어려움을 이야기한적이 있지만, 1년 전에 작성한 코드를 다시 읽고 기능을 추가하는 일은 역시 난감했습니다. 코드를 다시 머리에 넣는 것도 문제였지만, 예전에 작성한 코드가 문제투성이로 보이는 바람에, 처음부터 새로 짤까 고민하기 시작했습니다. (개발자라면 이런 고민 해보셨을 겁니다 ;)

또 하나의 문제는, 제가 사용하는 웹 프레임웍인 Ruby on Rails (Rails)가 3.0으로 버전업되면서 기존에 작성한 코드를 상당 부분 고쳐야 한다는 것이었습니다. Rails 2.0이 나왔을 때도 비슷한 일을 겪었었는데, 이처럼 프레임웍의 진화가 역설적으로 이에 기반하는 애플리케이션의 유지보수에 어려움을 주는 것이 큰 문제라고 생각했습니다. 하지만, Rails 3.0의 변경 내용을 구체적으로 살펴보면서 이런 불만은 탄성으로 바뀌었습니다. 애자일(agile) 웹 프레임웍의 대표격으로 인정받는 Rails이지만, 변화하는 웹 환경에 발맞추기 위해 끊임없이 혁신을 지속하는 점이 놀라웠기 때문입니다. Rails 3.0이 나온지는 꽤 시간이 지났지만, 이번 글에서는 Rails의 변화된 모습과 이에 관련된 웹 개발의 동향에 대해 알아볼까 합니다.

모듈화 및 플러거블 아키텍쳐

우선 가장 눈에띄는점은 Model-View-Controller로 이루어진 웹 프레임웍의 각 부분을 모듈화해 상호간의 인터페이스를 최소화했다는 점입니다. 이는 단순히 프레임웍의 유지보수를 편하게 하는 차원을 넘어, MVC의 각 구성요소를 사용자 편의에 맞게 바꾸는 것을 가능하게 합니다. 예컨데, Model쪽에서 기본으로 제공되는 ActiveRecord라는 데이터베이스 어댑터 대신 NoSQL 류를 포함한 다른 데이터 소스(persistence layer)를 사용할 수 있게 되었고, View측면에서 Prototype이라는 자바스크립트 프레임웍 대신에 JQuery를 사용할 수 있게 되었습니다. 유닛 테스팅에도 기본으로 제공되는 Test/Unit 대신에 BDD(Behavior-driven Development)에 기반을 둔 RSpec을 사용할 수 있습니다.

이런 변화가 웹 개발환경 자체의 특성과 어떤 관련이 있을까요? 웹은 끊임없이 신기술이 명멸하고, 근본적인 패러다임이 몇 년을 주기로 변화하는 다이나믹한 환경입니다. 이런 상황에서 웹 프레임웍이 특정한 컴포넌트의 사용을 강요하는 것은 사용자의 선택을 제약할 뿐 아니라, 프레임웍 자체의 가치를 위협하는 요소인 것입니다. 예컨데, Rails에 처음 Javascript 프레임웍이 채택되었을때, Prototype은 단연 우뚝선 존재였으나, 몇년 사이에 JQuery가 더 인기를 끌게 되었습니다. 백엔드 역시 모두가 MySQL등 RDBMS를 사용하는 환경에서, NoSQL이라는 이름의 Schema-free 어프로치가 세력을 키워가고 있습니다. 

이 모두가 최근 2-3년간 생긴 변화이고 앞으로도 이러한 추세는 계속될 것이기에, 프레임웍에 더 많은 기능과 제약을 부여하기보다는 프레임웍의 크기를 줄이고 모듈화하는 Rails의 변화는 환영할만합니다. 개발자 입장에서 모듈화에 따른 또다른 장점은 Rails 프레임웍의 소스 코드를 이해하기가 훨씬 편해졌다는 점입니다. 본격적인 애플리케이션 개발을 하다 보면 많은 경우 프레임웍 자체에 어느 정도 수정을 가해야 한다는 점을 고려하면 이 역시 작은 장점은 아닙니다.

REST(레스트) 프로토콜 지원

웹 사용이 일반화되면서 꾸준히 제기된 개념이 '기계가 사용하는 웹'입니다. 그리고, 이를 실현하기 위해 근 10년간 Semantic Web이라는 이름으로 다양한 스펙이 제안되었지만, 아직 널리 사용되지는 않고 있습니다. 반면에 Web 2.0로 불리우는 웹의 실제 진화 과정에서 웹 서비스의 일부를 API형태로 제공하는 사례가 일반화되었습니다. API는 프로그램에 의해 사용된다는 측면에서 Semantic Web과 같은 개념이지만, 개발 과정에서 복잡한 스펙에 얽매일 필요가 없습니다. 문제는 API의 정의 및 개발이 쉽지 않으며 이에 대한 표준안 역시 없다는 점입니다. 

REST(Representational State Transfer)는 이처럼 웹 서비스의 일부를 표준화된 (따라서 기계가 사용할 수 있는) 형태로 제공하게 해주는 프로토콜입니다. 좀더 구체적으로, REST는 복잡한 스펙대신에 표준화된 URL과 HTML Verb (GET, PUT, POST, DELETE)를 사용하여 웹 서비스를 구성하는 각 객체를 접근하고 수정하는 API를 정의합니다. 서비스 제공자의 입장에서는 복잡한 Semantic Web 프로토콜을 구현하거나 오류를 범하기 쉬운 커스텀 API를 구현하는 대신에, 훨씬 간편한 방식으로 표준 API를 구현할 수 있으며, API 이용자 측면에서는 웹에 존재하는 임의의 객체를 동일한 방식으로 접근할 수 있습니다. 

Rails에서는 1.2버전부터 모든 객체에 대해 RESTful한 (REST 표준에 따르는) API를 제공할 수 있게 하였으며, 2.0버전부터는 컨트롤러에서 RESTful한 API를 제공하는 것을 기본으로 채택하였습니다. 이는 웹 서비스의 모든 구성요소를 최종 사용자에게 제공하는 동시에, 개발자의 추가적인 노력을 전혀 들이지 않고 표준화된 API로도 제공할 수 있다는 것을 의미합니다. 제가 Rails 2.0으로 코드를 업그레이드할 당시에 이런 변화에 대해 불평했던 기억이 나는데, 돌이켜 생각해보면 옳은 결정이라는 생각입니다. 

이밖에도 Rails 3.0은 View에서 HTML5에 호환되는 Mark-up을 지원한다고 합니다. 또한 관련 패키지를 설치하고 관리하는 훨씬 단순한 방법을 제공합니다. 기타 자잘한 변화는 여기서 확인하실 수 있습니다. 

Rails와 웹의 미래는?

이처럼 프레임웍이 개발 생태계에 (혹은 개발 생태계가 프레임웍에) 미치는 영향은 지대합니다. Rails와 같이 영향력있는 웹 프레임웍이 이미 표준화되었거나 가까운 장래에 표준화될 기술의 사용을 적극 지원하고 장려하는 것은 개방과 공유를 근간으로 하는 웹 생태계의 발전에 크게 이바지할 것입니다. 요약하면, 다음 세대의 웹은 지금보다 서비스 각각이 더 유기적으로 결합되어 마치 거대한 하나의 애플리케이션을 사용하는 듯한 느낌을 주게 되지 않을까요. 

끊임없이 바뀌는 프레임웍에 맞춰 애플리케이션 소스를 수정하는 것은 이런 의미에서 가치있는 일일지도 모릅니다. 자신이 사용하는 프레임웍이 환경 변화에 맞추어 발전하지 못한다면, 언젠가 자신의 애플리케이션 역시 시대에 뒤안길로 밀려날지도 모르니까요. 개발자 각각의 그 모든 기술 변화를 이해하고 자신의 애플리케이션의 적용하는 것은 훨씬 더 큰 노력이 필요할테니, 어떤 의미에서 프레임웍의 사용은 변화하는 환경에 적응하는 노력을 최소화해준다고나 할까요.

이제 개발이 본업은 아니지만, 이처럼 새로운 기술이 쏟아지고 모든 면에서 끊임없이 진화하는 웹 개발 환경을 바라보는 것은 흥분되는 일입니다. 이제 다시 TextMate를 켜고 코딩을 할 생각입니다. 요즘 NoSQL류 데이터베이스 중에 MongoDB가 대세라는데 한번 써 봐야겠군요 ;)

p.s. 여러분은 요즘 어떤 웹 프레임웍을 쓰시나요? 한때 우리나라에도 활발한 Ruby / Rails 커뮤니티가 있었던 걸로 아는데요, 검색을 해보니 많이 없어진 모양이네요. 어떻게 된 일인지 아시는 분?
개발과 연구, 개발자와 연구자

어린 시절 나는 찰흙을 가지고 무언가 만드느라 시간이 가는줄도 몰랐었다. 지금 생각하면 웃음이 나오는 일이지만, 신문과 TV에 나오는 각종 신기한 물건을 찰흙으로 만들어 나만의 세상을 만들고 스스로 조물주인양 흐뭇했었던 모양이다. 대학시절 전공했던 전자공학 대신 컴퓨터 관련 수업에 더 빠져들었던 것은 그때의 아련한 추억이 떠올라서였을까. 늘 물리법칙에 구속을 받는 전자공학과는 달리 컴퓨터는 프로그래머가 어떤 법칙에도 구속받지않고 마음껏 창조할 수 있는 자유를 부여하니 말이다. 

병역특례 근무를 했던 회사에서도 나는 참 즐거웠었다. 낮에는 통신회사의 복잡한 요금계산 로직을 구현하고 이를 실시간으로 처리하는 업무를 맡았지만, 밤에는 내 자신의 모든 정보를 내게 맞는 방식으로 관리해주는 프로그램을 만들었다. 처음에는 달력으로 시작했던 것이 연락처, 할일, 지식 등등이 멋붙고 나중에는 기록된 정보에 대한 통계를 멋진 차트로 만들어주는 모듈까지 생겼다. 스스로의 삶의 '만족도' 그래프가 (당시에 그런 것도 기록했었다 ;) 올라가는 것을 보면서 뿌듯했던 기억이 아직도 생생하다. 이처럼 자신에게 필요한 무언가를 만들고, 이를 실제로 활용하면서 문제점을 찾아내고, 차츰 개선해가는 과정은 참으로 만족스러운 것이었다. 

회사 생활을 마치고 유학을 시작할 무렵, 나는 드디어 내가 꿈꾸던 일을 한다는 희망에 부풀어 있었다. 혼자서 스스로를 위한 프로그램을 만드는 데서, 많은 사람이 혜택을 받을 수 있는 프로그램 및 기반 기술을 개발할 수 있을 것이라고 믿었다. 그리고 약 3년이 지나 나는 어느덧 실험하고 논문쓰는 대학원 생활에 익숙해졌다. 미국이라는 낯선 환경에도 어느 정도 적응을 했다. 그런데 최근들어 새로운 고민이 생겼다. 검색 관련 연구를 하다보니 알고리즘 및 프로토타입을 구현할 일이 자주 있는데, 예전만큼 프로그래밍이 잘 되지도 않고 개발에 대한 흥미도 많이 잃은 것이다. 

최근에 하는 고민입니다. 오늘은 이런 문제의식을 토대로 '개발(programming)'과 '연구'라는 활동의 관계를 생각해보고자 합니다. CS연구자에게 개발은 어떤 의미일까요? 개발과 연구를 병행하는 것은 가능할까요? 이를 효과적으로 하기 위해서는 어떻게 해야 하나요? 

왜 개발과 연구를 병행하는 것이 어려운가?
얼핏 생각하기에도 개발과 연구는 비슷한 점이 많습니다. 우선은 둘다 본질적으로 주어진 문제를 해결하는 과정입니다. 개발자는 프로그램의 설계와 구현을 통해서, 연구자는 가설과 검증을 통해서 문제를 풀어냅니다. 또한 끊임없이 뭔가를 쓰고, 결과를 확인하고, 고친다는 점에서도 유사합니다. 이처럼 본질적으로 유사한 활동이니 쉽게 병행할 수 있을까요? 3년간의 개발자 생활과 3년간의 대학원 생활을 통해 얻은 결론은 '생각만큼 쉽지는 않다'는 것입니다. 왜 그럴까요?

저는 두가지 활동이 각각 완전한 집중을 요하기 때문이라고 생각합니다. 폴 그라함은 좋은 개발자라면 머리속에 프로그램의 코드를 완전히 넣고 마음껏 조작할 수 있어야 한다고 말했습니다. 또한 학자들은 세상의 흐름을 밎고 자신의 문제에 오롯이 몰두하는 것이 보통입니다. 여기서 중요한 단어는 '완전한' 인데, 창조적 잠재력을 최대한 끌어내는데 있어 90%의 집중, 80%의 집중은 별 쓸모가 없기 때문입니다. 따라서 두가지를 모두 열심히 한다는 것은 서로 다른 두가지 방향으로 동시에 날려는 것과 같습니다.

또다른 측면은 연구와 개발이 내용상으로는 전혀 다른 영역의 활동이며 각각을 위해 상당한 양의 정신적 컨텍스트가 필요하다는 점입니다. 개발자가 효과적으로 일하기 위해서는 프로그램의 설계 및 구현에 관련된 세부사항, 실행환경, API, 기타 등등 엄청난 양의 배경지식이 머리속에 담겨야 하며, 연구자의 경우에도 기존 학설 및 자신의 가설, 실험 방식과 결과 등을 항상 기억해야 하기 때문입니다.  위에서 언급한 '완전한 집중'과 이점을 연결지어 생각해보면 개발(연구)을 위해 단련된 두뇌가 연구(개발)에 적응하는 데에는 상당한 시간과 노력이 필요하다는 점을 알 수 있습니다. 

마지막으로 개발과 연구 활동이 추구하는 목적 자체의 차이에서 기인하는 어려움도 있습니다. 보통의 개발은 그 결과물인 소프트웨어 자체가 목적이지만, 연구를 위한 개발에서 소프트웨어는 가설 검증을 위한 수단에 불과하기 때문입니다. 따라서 대부분의 연구 프로젝트에서 개발을 위한 시간과 노력은 그다지 높게 평가받지 못합니다. 연구를 하면서 개발에 대한 흥미가 떨어진 것은 연구자에게 개발이 갖는 우선순위가 낮기 때문인지도 모르겠습니다.

개발과 연구를 어떻게 병행해야 하는가?
이처럼 개발과 연구를 병행하는 것이 쉽지 않으니 어느 한가지에만 집중할 수 있다면 좋겠지만,  CS연구자에게 있어서 (계산이론 등의 순수 이론 분야를 제외하고는) 개발 능력은 상당히 중요한데, 연구의 생산성과 품질이 상당 부분 자신이 작성한 코드의 질에 영향을 받기 때문입니다. 머신러닝 등의 알고리즘 연구자라도 실험에 쓸 수 있을 정도의 성능과 정확도를 가진 프로그램을 작성해야 하며, 실제 사용자를 대상으로 실험을 해야 하는 검색이나 HCI등의 분야에서는 오랜 기간 사용가능한 견고한 프로그램을 만들어야 한다는 조건까지 붙습니다.

이처럼 피할 수 없는 개발, 어떻게 해야 연구와 병행할 수 있을까요. 가장 먼저 자신이 풀타임 개발자가 아니라는 사실을 인식해야 할 것입니다. 연구자의 본업은 연구이기에, 개발자로서는 파트타임입니다. 주어진 시간과 에너지를 온전히 개발에 투자할 수 있는 상황이 아니라면 머리에 항상 자신의 프로그램을 넣어둘 수 있는 사치는 허용되지 않으며, 프로젝트에 관한 사항을 모두 잊은 상태에서도 신속하게 다시 개발에 착수할 수 있어야 할 것입니다.

이런 이유에서 최근에 다시 깨닫고 있는 것이 문서화와 테스트의 중요성입니다. 잘 쓰인 문서를 읽고 테스트를 돌려보면 자신의 코드가 어떤 기능을 하는지 알고, 해당 기능의 동작을 확인할 수 있기 때문입니다. 문서가 없어 개발에 다시 착수할 때마다 소스코드를 다 훑어야 한다면, 그리고 테스트가 없어 코드를 수정하고도 제대로 동작하는지 확인할 길이 없다면 생산성이 떨어질 것은 불을 보듯 뻔한 일입니다. 물론 가능하면 애자일(agile)한 언어를 사용하고, 잘 모듈화된 코드를 작성하는 것은 기본입니다. (좀더 구체적인 개발 툴 및 방법론은 따로 포스팅하겠습니다.)

이외에도 건강한 코드 유지를 위해 필수적이라고 생각하는 것이 코드 리뷰(code review)입니다. 즉, 정기적으로 자신이 짠 코드를 훑어보고 문제점을 찾아내고, 테스트 및 문서를 추가로 작성하는 등의 유지보수 활동을 (주로 한가할 때) 해야 한다는 겁니다. 평소에 기능을 구현하거나 문제를 수정할 때에는 보통 시간이 부족하기 때문에 일단 돌아가는 코드를 만들고 끝내는 경우가 많은데, 이렇게 코드 리뷰을 통해서 전체 설계에 어긋나는 부분을 찾아서 개선하고 코드를 항상 최상의 상태로 유지할 수 있습니다. (기업의 코드리뷰 프로세스에 대해서는 고감자님의 글을 참고하세요.)

이런 준비를 하더라도 역시 머리가 개발 모드에서 연구 모드로 넘어가는 것은 쉬운 일이 아닙니다. 저같은 경우에는 개발에 착수한 후에 제대로 생산성을 내기까지 최소 이틀 정도가 걸리는 것 같습니다. 따라서 일정 조정을 통해 개발이 필요한 일을 한번에 모아서 처리하려고 노력하고 있습니다. 하루의 특정 시간에 특정 활동을 한다는 규칙을 세우는 것도 두뇌가 준비되는 데 도움이 됩니다. 저같은 경우에는 오전에 연구 관련된 활동을, 오후에는 개발을, 저녁에는 블로깅 등 기타 활동을 하기로 정하였습니다.

마치며
최근 개발 프로젝트가 문제에 봉착했을 때,  '개발을 전혀 하지 않고 살 수 있을까' 하고 생각해 보았습니다만 역시 불가능이라는 결론에 도달했습니다. 물론 회사에서나 학교에서나 나이가 들수록 실제로 코딩을 하는 빈도는 줄어드는 게 보통이지만, 스스로 개발을 하지 않더라도 관리자로서 개발 프로젝트에 관한 중요한 의사결정을 하거나 문제를 해결해야 하는 더 큰 책임이 주어질 것이기 때문입니다. 

하지만 개발자로서의 '감'을 잃은 관리자가 이런 상황을 효과적으로 대처할 수 있으리라고 상상하기는 매우 힘듭니다.  어쩌면 우리나라 소프트웨어 산업의 정체에는 개발에 대해 무지한 관리자들의 책임도 있지 않을까요? 아직도 제게는 쉽지 않지만, 위 사항을 지키기로 노력하면서부터 개발과 연구를 병행하는 일이 많이 쉬워진 느낌입니다. 어렸을 때 찰흙놀이를 하면서 느꼈던 희열, 처음 짠 프로그램을 실행시켰을때의 흥분을 머리가 희끗해질때 까지 간직하고 싶습니다.