Scala + Play Framework 2 Server 성능 향상 시키기

주변에서 Play Framework과 Scala에 대한 관심이 많아지고 있는 것 같다. 지난 2년간 이 조합으로 application 서버를 개발하면서 성능이나 개발 생산성에서 아주 만족하고는 있지만, 아직은 reference가 많지 않아서 중간에 어려움을 많이 겪었다. 오늘은 Scala + Play Framework2의 조합에서, thread를 활용해 성능 향상을 할 수 있는 부분에 대해서 공유해보려고 한다.

Scala 및 Play Framework에 대해서는 이전에 작성한 포스팅을 참고.

1. 접근 방향


일반적인 웹서비스는 보통 다음의 flow로 사용자의 request를 처리하는 것 같다.

  1. 사용자 request 발생
  2. DB나 Cache 서버에서 request의 처리에 필요한 값들을 조회
  3. business 로직 처리
  4. DB에 변경된 값 저장
  5. 사용자에게 response를 보내서 처리를 완료

규모가 있거나 좀더 복잡한 서비스의 경우에는 DB서버나 Cache 서버 외에 또 다른 application 서버를 이용하기도 한다. 이때 병목이 되는 부분은, 대개의 경우에는 외부의 서버와 통신하는 부분이다. 즉, DB, Cache, 다른 application 서버에 무언가를 요청하고 결과를 기다리는 작업에서 CPU 연산과는 order가 다른 수준으로 시간이 걸린다. 그래서, 어떻게 외부 서버와 효율적으로 통신을 하느냐가 application 서버의 성능을 결정 짓는 중요한 요소이다.

Thread가 있는 언어의 경우에는 다음과 같은 방법으로 성능을 향상 시킬 수 있는 것 같다.

  1. thread pool을 분리한다.

    응답성을 높이기 위해서, 사용자의 응답을 처리하는 thread pool과 외부 서버와 통신을 하느라 작업이 오래 걸리는 thread pool을 분리 시킬 수 있다. 이렇게 해놓은 다음, 외부 서버와 통신을 하는 thread pool의 개수를 넉넉하게 잡아두면 성능을 향상 시킬 수 있다.

  2. 반드시 serial하게 처리할 필요가 없는 작업은 parallel 하게 처리한다.

    예를 들어, DB 서버가 여러대로 분리되어 있고, 각각의 DB 서버에서 값을 조회한 뒤에 단순히 합쳐서 response를 주는 상황을 생각해 보자. 이때는 굳이 순차적으로 외부 DB 서버들과 통신할 필요 없이, 동시에 여러 DB 서버와 통신을 시작하면, 응답시간을 줄일 수 있다.

그럼 조금 구체적으로 들어가보겠다.

2. Play 2에서 Thread Pool 분리


Play Framework 2에서는 Akka라는 Asynchronous Library를 이용하여 thread pool을 처리한다. Akka를 이용해서 thread pool을 설정하기 위해서는 Play Framework 2 문서의 ‘Understanding Play thread pools’를 참고하면 된다.

Thread pool을 설정하고, Contexts object를 이용해 어떻게 소스코드에서 이용하는지에 대해서는 위의 문서에 간략히 설명되어 있다. 그런데, 설정에 있어서 매우 중요한 부분인데, Play Framework과 Akka 공식 문서 둘다에서 자세히 설명하고 있지 않은 부분이 있다.

2.1 Thread pool 설정

Akka에서 thread pool이 동작하는 방식이 fork-join-executor과 thread-pool-executor 2가지가 있는데 default는 fork-join-executor이고, 이것이 성능이 더 좋은 것으로 알려져있다.

fork-join-executor의 경우에 다음 3가지 값을 설정하면 된다.

  • parallelism-min

    동시에 활성화 되는 최소 thread 개수

  • parallelism-max

    동시에 활성화 되는 최대 thread 개수

  • parallelism-factor

    core 개수 대비 최대가 될수 있는 thread 비율. 서버의 core가 4개이고, 이값이 2인 경우에 thread는 8개까지 될 수 있다.

여기서 조심해야 할 것이, 이 3가지가 교집합이라는 것이다.

예를 들어, core가 4개인 서버에서

parallelism-max = 10
parallelism-facotr = 2

라고 설정을 한 경우에는, 최대 thread 개수는 10이 아니라 8이 된다.

만약 위의 값을 생략하면 어떻게 될까? Akka 문서에 따르면, 위의 값 값들의 default는 다음과 같기 때문에 다음 값으로 설정된다.

parallelism-min = 8
parallelism-max = 64
parallelism-factor = 3

그럼, core가 2개인 서버에서 다음과 같이 설정을 한 경우를 보자.

parallelism-max = 10
/* parallelism-factor의 설정은 생략 */

이때는, parallelism-factor 의 값 설정이 생략되어 있기 때문에, 이 값은 default인 3이 된다. 그래서, 최대 thread 개수는 10이 아니라, 2*3=6 이 되게 된다. 나의 경우에 이걸 모르는 바람에 한참을 고생한 기억이 있다.

3. 작업을 parallel하게 처리하기


3.1 Future.sequence 이용

Scala에서는 task를 비동기적으로 처리하기위해 Future로 만든 다음에, 모든 future가 동작이 끝날 때까지 기다리는 Future.sequence 함수를 호출하는 방식으로 처리할 수 있다.

다음과 같은 방식이다.

val future1 = Future { function1() } 
val future2 = Future { function2() }

Future.sequence(Seq(future1, future2)).map { _ => true}

이때 thread pool을 분리해 두었다면, 다음과 같이 처리하는 것도 가능하다.

val future1 = Future { function1() } (pool1)
val future2 = Future { function2() } (pool2)

Future.sequence(Seq(future1, future2)).map { _ => true} (pool3)

그런데, 실제로 application 서버를 구현하다보면, parallel 하게 처리해야 하는 것과 serial하게 처리해야 하는 것들이 섞여 나올 수 있다. 예를 들면, 다음과 같다.

val future1 = Future { function1() } 
val future2 = Future { function2() } 
val future3 = future1 flatMap { r1 => function3(x) }

Future.sequence(Seq(future2, future3)).map { _ => true}

위의 예에서는 future1의 결과를 얻은 후에, 이어서 function3을 호출하고 있다.

참고로, function1, function2, function3의 처리 시간을 각각 t1, t2, t3이라고 할 때, 이때 전체 처리시간은 다음과 같이 표현 할 수 있다.

max(sum(t1,t3), t2)

3.2 For 이용

위와 같이, serial하게 처리해야할 것과 parallel하게 처리할 것을 프로그래머가 구분해서 구현 할 수도 있지만, scala에서는 ‘for’ 문법을 이용해 이 부분을 컴파일러에게 넘길 수 있다.

참고로, Scala에서 어려우면서도 유용한 문법이 바로, ‘for’ 이다. 여기서의 future와 관련된 ‘for’의 용법은 Scala 공식 문서에 좀더 자세히 설명이 되어 있다. ‘for’는 여기서 사용하는 future의 처리 외에도, collection iteration과 Option을 처리할 때도 쓰인다.

‘for’를 이용해 앞서 코드를 변경하면 다음과 같다.

val future1 = Future { function1() } 
val future2 = Future { function2() } 

for {
  r1 <- future1
  r2 <- future2
  r3 <- Future { function3(r1) }
} yield true

위의 코드는, r1과 r2는 parallel하게 처리되고, r3는 r2가 처리된 이후에 처리가 된다.

마치며


Play Framework 2와 Scala 조합에서 Thread 관련해서 꼭 알아야 하지만, 잘 다루어지지 않아서 고생했던 부분들 중심으로 정리해 보았다. 이 외에도 성능 측면에서 다루고 싶은 몇가지 소소한 것들이 있는데, 다음에 기회가 되면 이어 갈 수 있도록 하겠다.

Updated 2014-1-27

for에서 future 처리 관련해서 제가 잘못 알고 있던 것이 있어서 수정했어요.

Amazon Web Service For Startups

최근에 모바일 서비스를 Amazon Web Service(AWS)를 이용해서 개발하고 운영해 보았다. 주변 분들에게 AWS를 이용한다고 하면, 첫 반응은 “비싸지 않나요?” 이다. 비슷한 사양의 서버를 직접 구매할 때와 비교해보면 비싸보이기는 하지만, 다른 측면에서 살펴볼 때 그렇지 않은 점들이 있어서, 간단히 내 생각을 정리해본다.

스타트업이 필요로 하는 것

AWS가 어떤 장점이 있는 지를 알기 위해서, IT 관련 비즈니스를 하는 스타트업은 어떤 어려움이 있는지를 짚어보아야 할 것 같다.

스타트업이 제품을 성공시키기 위해서는 여러 문제들을 극복해야 한다. 수없이 많은 문제들이 있지만, 이러한 문제들은 결국 다음 3가지로 귀결되는 것 같다.

  1. 부족한 인력
    • 언제나 할일에 비해 일할 사람은 턱없이 부족하다.
  2. 부족한 자금
    • 스타트업은 회사 매출이 없는 상황이기 때문에, 창업자가 여유가 되어서 자본을 많이 넣지 않은 이상 자금 사정은 힘들다.
  3. 수시로 변하는 시장상황
    • 좋은 아이디어로 멋진 제품을 들고 나왔는데, 시장 분위기가 완전히 바뀌기도 한다.

스타트업 뿐만 아니라 보통의 회사들 역시 위의 3가지 어려움에서 자유롭지 못하지만, 스타트업의 경우에는 이 3가지를 어떻게 극복하느냐가 초반에 ‘생존’을 결정 짓는 것 같다. 바꾸어 말하면, 스타트업은 살아남기 위해서, 제품을 ‘적은 인력’으로 ‘빠르게’ 개발해서 내놓고 운영할 수 있어야 한다. 이를 위해서는, 해결해야 할 문제를 정확히 정의하고, 그 문제만을 위해서 달려야 한다고 본다. 또, 이 문제를 해결함에 있어서도, 집중해야 할 부분과 그렇지 않은 부분을 잘 구분한 뒤에, 집중해야 할 부분에는 인력을 투입하고, 그렇지 않은 부분은 외부의 도움을 받아야만, ‘적은 인력’으로 ‘빠르게’가 가능하다고 생각한다.

AWS가 도움을 주는 것

AWS의 장점은 application 서버의 개발과 운영하는데에 도움을 받을 수 있는 부분이 생각보다 많다는 점이다. 일반적인 ‘Infrastructure’ 수준에서 virtual server를 제공하는 하는 것을 넘어서서, 개발과 운영에 필요한 여러 시스템을 ‘Platform’ 수준에서 제공한다. 실제로 AWS를 이용하면서, 내가 도움을 받는 것들은 다음과 같다. 괄호안은 AWS에서의 서비스 이름이다.

  • 실시간 서버 할당 (EC2)
  • 물리적으로 분리된 곳에 DB를 설치하고, 문제 발생시 자동 failover (RDS)
  • 대용량 데이터 sharding 처리 (DynamoDB)
  • Message Queue 서비스 설치 및 운영 관리 (SQS)
  • 대용량 데이터 분석을 위한 hadoop 설치 및 운용 (Elastic MapReduce)
  • 로드 밸런스 및 SSL 처리 (Elastic Load Balancer)
  • 서버 모니터링 및 알람(CloudWatch)

위 작업들은 시간이 꽤 드는 일이고, 어떤 것들은 전문적인 노하우가 필요한 것들도 있다. 예를 들어, DynamoDB를 보자. 최근에 대용량 데이터를 처리하기 위해 NoSQL을 사용하는 경우가 많다. 그런데, NoSQL의 하나인 HBase 같은 경우에 성능은 좋지만 설치부터가 꽤나 어렵다. 또, 실제로 운영에 들어가면, 운영 경험 없이는 알 수 없는 문제들이 발생해서, 서비스 장애로 연결되는 경우를 종종 본다. 설치가 쉬운 걸로 알려진 MongoDB의 경우에도 Lock 문제, 데이터 유실 문제 등이 지속적으로 제기되고 있어서, 장애없이 운영하기가 그리 녹녹치 않아 보인다. DynamoDB는 NoSQL을 아마존에서 직접 운영하고, 개발자는 API를 통해서 서비스를 이용할 수 있도록 해준다. 안정적으로 운영하는 역할과 책임은 아마존에서 가져가는 방식이다. NoSQL의 장점을 살려 Application 서버를 개발하되, 운영의 미숙함으로 생기는 위험요소(Risk)는 아마존에 넘길 수 있다.

Application 서버 개발시에, 처리 효율성을 높이기 위해 비동기적으로 처리할 수 있는 것들은 ActiveMQ, RabbitMQ등의 Message Queue(MQ) 솔루션을 이용하곤 하는데, 이러한 소프트웨어도 서버에 설치하고 문제없이 운용하려면 꽤 정성이 필요하다. 그런데, AWS의 서비스 중에 SQS라는 서비스를 이용하면, API를 통해서 바로 MQ 서비스를 이용할 수 있게 된다. DynamoDB와 마찬가지로 운영을 아마존에서 하는 방식이다.

이렇게 platform 레벨에서 제공되는 여러 서비스를 이용하면, 레고 블록을 쌓듯 꽤 빠른 시간 안에 적은 노력을 들여 고객이 원하는 제품을 만들어내고, 운영할 수 있다.

또한, AWS의 특성을 살려 직접적인 서버 비용을 많이 줄일 수 있는 경우도 있다. 대용량 데이터의 병렬 처리를 위해서 많이 사용하는 것이 Hadoop MapReduce이다. 데이터 분석은 보통 일정 주기로 처리가 되는데, AWS의 서비스 중의 하나인 Elastic MapReduce를 이용하면 서버를 항상 구비해둘 필요 없이 분석해야 할 시점에 바로 Map Reduce용 서버 instance를 만들어서 데이터를 처리하고 작업이 끝나면 instance를 삭제하는 것이 가능하다. 그리고, 이 모든 것이 자동화가 가능하다. 24시간 서버를 확보할 필요없이 10분정도만 서버를 사용하고, 사용한 시간에 대해서만 요금을 지불하면 된다.

예전에 FriendFeed의 창업자이고, 후에 회사를 Facebook에 매각해 Facebook의 CTO을 지냈던 Bret Taylor는, FriendFeed를 하면서 했던 가장 큰 실수는 무엇이냐는 질문에 클라우드 서비스를 쓰지 않은 것이라고 했다. 서버를 구매하고 설치하고 관리하느라 시간을 많이 뺐겼기 때문이라고 이유를 밝혔다.

비단 스타트업 뿐만 아니라 큰 회사 중에서도 클라우드를 도입한 사례는 많다. 특히, 미국 내에서 HTTP나 YouTube보다도 트래픽이 많은 Netflix의 경우 본래의 비즈니스에 집중하기 위해, 별도로 서버를 구축하지 않고 AWS를 적극 활용하고 있는 것으로 알려져 있다.

마치며

AWS를 이용해서 2개 서비스를 구축해보았고, 이제 1년 정도 된 것 같다. 그리고 아직 써보지 못하고 잘 알지 못하는 AWS의 기능도 꽤 많다. 발전 속도도 빨라서, 잠깐 신경을 못쓰면 놀라운 기능들이 들어가 있어서 깜짝 놀라곤 한다. 요즘은 AWS를 바라보면서, 기존 서버를 대체하는 정도가 아니라, AWS의 여러 기능을 이용해 예전에는 구현하기 매우 힘들던 것들도 가능하지 않을까 생각하게 된다. 앞으로 엔지니어, 특히 서버엔지니어의 역량은 알고리즘, 네트워크, DB 등을 잘 이해하고 있느냐를 넘어서, 얼마나 AWS를 비롯한 클라우드 서비스를 잘 이해하고 활용할 수 있느냐에 의해 결정되는 것이 아닐까 조심스레 예측해본다.

게임 중독법? Really?

게임 중독을 마약, 알코올 중독과 같은 수준으로 보고, 국가가 나서서 규제 하고 관리해야 한다는 게임 중독법이 제정될 분위기이다. 게임을 안해본 일부 정치인과 나이드신 분들의 상상으로 시작해서, 결국은 해프닝으로 끝날 줄 알았다. 그런데, 오늘 법 제정을 위한 공청회에 여당 대표까지 참석한 걸 보니, 정말 진지하다.

나는 이 법이 여러 관점에서 넌센스라고 생각한다.

먼저, 게임 중독은 법제화 하기가 어렵다. 규제를 하기 위해서는 객관적인 잣대가 필요하다. 그런데, 누군가가 게임 중독임을 판명하기 위한 객관적인 기준이 있는가? 알코올이나 마약과 달리 아직 게임 중독에 대해서 명쾌한 기준을 제시한 것을 보지 못했다. 그런데, 어떻게 규제 대상이 될 수 있는가?

두번째로, 설령 게임 중독이 있다고 하더라도, 이것이 과연 국가가 개입해서 개인을 계도할 성격의 문제인가? 여기에 있어서는 정치적인 견해에 따라 판단이 다를 수 있지만, 나는 그렇게 생각하지 않는다. 중독이 심각하지 않고, 사회적인 영향도 미미하다고 생각하기 때문이다. 적어도 내가 판단하기에는 게임이 중독의 대상이 된다면, 우리 사회에는 비슷한 수준의 문제들이 너무나 많다. TV 시청을 지나치게 하는지, 너무 일에 빠져 퇴근도 안하고 있는지도 비슷한 수준의 문제들이다. 바꾸어 말하면, 이건 ‘중독’이라는 딱지를 붙이기 보다, ‘기호’ 수준의 문제라고 본다. 개인의 자유를 보장하는 자유민주주의 사회에서는 개인의 선택의 영역에 해당하는 문제이다.

게임 중독법이 이렇게 진지하게 진행되는 데에는, 실제로 게임 중독법을 지지하는 세력이 많다는 것을 알게 되었다. 이들 중 많은 수가 어린 자녀를 둔 학부모인걸로 보인다. 게임 때문에 아이들이 말을 안듣고, 공부를 안하고 있다고 생각하나보다.

착각이라고 본다. 부모를 필요로 하는 아이를 방치해놓고, 그 아이가 게임을 했다고, 게임이 원인이라고 하는 건 아닌가? 고백하자면, 나 역시  가끔은 피곤하고 바쁠 때, 아이와 시간을 보내는 것을 피한 적이 있다. 그 때 내 아이가 하는 건, 아이패드를 가지고 노는 것이다. 이 친구에게서 아이패드를 뺐는다고, 무엇이 달라지겠는가?

얼마전 청소년들이 무엇을 하고 싶은지와 그리고 실제로 무엇을 하면서 시간을 보내는 지에 대한 설문조사를 보았다. 하고 싶은 것 1위는 압도적으로 ‘여행’이었다. 게임이 아니었다. 그러나 실제로는 많은 시간을 공부를 하고, 그리고 남는 시간에는 게임을 한다는 결과였다. 이것이 무엇을 의미하는가? 우리 청소년들은 꿈도 많고, 하고 싶은 것도 많다. 다만 우리 부모들이 아이들에게 충분한 기회를 주지 못해서, 그래서 쉽게 접할 수 있는 게임을 하고 있는 걸로 해석할 수밖에 없다. 참으로 슬프다.

누군가를 규제하고 통제하려고 하기 전에, 스스로 부끄럼이 없는지 돌아보자. 이런 식의 규제, 통제 모두 전근대적인 독재의 산물일 뿐이다.

멋진 동료를 구합니다.

대용량 트래픽 처리, 플랫폼, 클라우드, 빅데이터 분석, Scala, Ruby on Rails…

혹시 관심있는 주제들이신가요? 그렇다면, 저희 회사에서 개발자를 찾고 있는데, 한번 봐주시겠어요?

하는일

모바일 게임을 위한 플랫폼 개발 및 클라우드 서비스(PaaS)를 제공합니다. 이 서비스를 이용하면, 중소 규모의 모바일 게임사가 서버 개발자 없이 모바일 게임을 론칭하고 운영할 수 있습니다. 10월 오픈 예정으로 열심히 달리고 있습니다.

사용하는 기술

Scala, Playframework 2, Ruby on Rails, Amazon Web Service, MySQL, Unity

근무지

강남 또는 분당

저희가 찾는 동료

1) 프로그래밍을 좋아하시고, 새로운 것을 배우는 것을 즐기는 분
2) 누군가에게 관리 받기 보다는 스스로 일을 찾아 열정적으로 진행하고, 그 열정을 옆의 동료에게 나누어주실 수 있는 분
3) 서버 개발 경험이 있거나 게임 개발 경험이 있으면 더 좋아요 ^^
4) 주니어/시니어 포지션 모두 찾고 있습니다.

이력과 자기소개에 대해서 편하신 형태대로 보내주세요.
링크드인 주소, 홈페이지 주소, PDF 이력서 환영. HWP는 싫어요. 😦

최세윤
ppassa@gmail.com

Steve Jobs가 Larry Page에게 해준 이야기

2011년, 구글 CEO 자리로 복귀하게된 Larry Page가 Steve Jobs에게 만나고 싶다는 요청을 했다고 한다. 어떻게 하면 좋은 CEO가 될 수 있는지 ‘조언’을 듣고 싶다며. Jobs는 이 이야기를 듣고, 속으로는 바로 ‘Fuck you’를 했다고..

하지만, 자신 또한 젊은 시절, 많은 사람들로부터 도움을 받았기에 이것을 되돌려 주어야 한다는 생각에 만나서 진심을 담아 다음과 같이 조언해주었다고 한다.

(명문을 잘 번역할 자신이 없기에 원문 그대로 옮김)

We talked a lot about focus. And choosing people. How to know who to trust, and how to build a team of lieutenants he can count on. I described the blocking and tackling he would have to do to keep the company from getting flabby or being larded with B players. The main thing I stressed was focus. Figure out what Google wants to be when it grows up. It’s now all over the map. What are the five products you want to focus on? Get rid of the rest, because they’re dragging you down. They’re turning you into Microsoft. They’re causing you to turn out products that are adequate but not great. I tried to be as helpful as I could. I will continue to do that with people like Mark Zuckerberg too. That’s how I’m going to spend part of the time I have left. I can help the next generation remember the lineage of great companies here and how to continue the tradition. The VAlley has been very supportive of me. I should do my best to repay.

– Steve Jobs 자서전에서.

Java 개발자를 위한 Scala 소개

앞서 Scala 시작하기 포스팅을 쓰고나서, 주위로부터 Scala에 대한 관심이 커진 걸 조금씩 느낀다. 하지만, 아직도 Scala를 본격적으로 도입한 사례는 많지 않은 것 같다. 그래서, Scala의 장점과 실제 어떤 식으로 코딩을 하는 지에 대해서, 그동안 배운 것들을 공유해보려고 한다.

1. Java와 호환


Scala는 compile language이다. compile을 하면, Java Virtual Machine(JVM)상에서 동작하는 byte code가 만들어진다. 이미 검증된 VM이라 할 수 있는 JVM에서 동작하기 때문에, ruby나 python등 VM을 필요로 하는 다른 언어 등과 비교하면 안정적이다. 게다가 compile 언어이기 때문에 이러한 interpret 언어보다 빠르다.

Scala는 JVM에서 동작하면서, Java의 문법과 아주 유사하기 때문에 Java의 모든 라이브러리를 그대로 사용할 수 있다. 수많은 Java로 된 open source 라이브러리들이 모두 Scala의 라이브러리이기도 한 것이다!

2. 개발 생산성(productivity)


Scala는 object oriented language이면서 동시에 functional language이다. object oriented 방식으로 하다가도 필요한 경우, functional language적인 것들을 섞어 쓸 수 있다. 이것은 마치, 중국집에서 짜장면을 먹고나서 이태리 식당에나 어울릴 법한 티라미슈 케잌을 후식으로 먹는 것에 비유할 수 있겠다.

그러면, Scala에서 유용하게 쓰이는 functional language적인 feature 몇가지만 소개보겠다.

2.1 Loan Pattern

From Java
텍스트 파일을 읽어서 한줄씩 출력 해야 한다고 하면 Java로는 아래와 같이 만들게 될 것같다.

BufferedReader bufferedReader = null;
try {
  bufferedReader = new BufferedReader(new FileReader(filename));
  String line = null;
  while ((line = bufferedReader.readLine()) != null) {
    System.out.println(line);
  }
} catch (IOException ex) {
  ex.printStackTrace();
} finally {
if (bufferedReader != null)
  bufferedReader.close();
}

만약 위의 기능에 더해서, 텍스트 파일을 읽어서 한줄씩 읽어서 DB에 저장하는, 위와 유사한 코드를 만들고 싶다면 어떻게 해야 할까?

실질적으로는 위의 코드에서 System.out.println() 부분만 DB로 저장하는 걸로 바꾸면 되지만, 아쉽게도 앞뒤로 있는 코드들은 다시 써주어야 한다. 다시 말해 중복코드가 필연적으로 생긴다.

To Scala
Scala로는 다음과 같이 정리가 가능하다.

먼저 실제 line을 가지고 작업을 하는 것을 제외한, 앞뒤 부분에 해당하는 함수를 다음과 같이 만든다.

def withFile(filename:String)(work: String => Unit) {
  var bufferedReader = null
  try {
    bufferedReader = new BufferedReader(new FileReader(filename))
    String line = null;
    while ((line = bufferedReader.readLine()) != null) {
      work(line)
    }
  } catch {
    case ex:IOException => ex.printStackTrace()
  } finally {
    if (bufferedReader != null)
      bufferedReader.close()
  }
}

이 함수는 2개의 arguement를 받는다. 하나는 filename이고, 다른 하나는 work라는 이름의 함수이다. 7번째 줄에 보면 인자로 받은 work라는 함수를 호출하고 있는 모습이 보인다. 이것이 Object Oriented 프로그래머에게는 조금 어려운 개념인데, Scala는 Functional language이기 때문에 함수도 하나의 변수처럼 처리할 수 있다.

중요한 건 이렇게 앞뒤 귀찮은 작업을 하는 함수를 빼어(refactoring) 놓으면 다음과 같이 재사용할 수 있다.

– 한 줄씩 화면에 출력

withFile(filename) {
  line => System.out.println(line)
}

– 한 줄씩 DB에 저장 (storeToDb라는 함수가 있다는 가정하에)

withFile(filename) {
  line => storeToDb(line)
}

위와 같은 방법을 ‘loan pattern’이라고 한단다. 출처는 여기.

2.2 iteration

Scala에서는 collection의 iteration 관련해서 유용한 함수가 많다. 사실 내가 Java를 버리고 Scala를 쓰게 된 동기도, 빵꾸똥꾸 같은 Java의 iteration 때문이다. 한동안 C#, Ruby 등으로 개발하다가, 다시 Java를 써야했는데, 오랜만에 써보는 Java iteration은 C 코딩하다가 어셈블리어를 썼던 딱 그때를 생각나게 했다.

그럼 예제 코드를 잠시 보겠다. numbers라는 collection에서 짝수인 것들만 추려내야 하는 경우에, Java에서는 다음과 같이 한다.

for (Iterator iterator = numbers.iterator(); iterator.hasNext();) {
  Integer number = iterator.next();
  if (number % 2 == 0) {
    iterator.remove();
  }
}

위 코드의 출처는 여기.

Scala에서는 다음과 같이 엘레강트하게 처리한다.

numbers.filter { n => n % 2 == 0 }

이 외에도 Ruby 프로그래머의 경우에 익숙할 map, count등 iteration을 위한 유용한 함수들이 많이 존재한다.

2.3 기타

꼭 functional language 적인 것 말고도, Java에서 불편하던 것들을 문법적으로 개선한 부분이 많다. Singleton 지원, 변수의 lazy 초기화 지원 등등 여러가지가 있는데, 길어질 것 같으니 생략하도록 하겠다. ^^

3. 성능(performance)


기본적으로 Scala는 JVM에서 동작하기 때문에 Java 만큼의 성능이 나온다. 물론 C나 C++과 같이, compile 결과로 machine code가 나오는 언어에 비해서는 느리지만, Ruby, Python, JavaScript등의 interpret 언어보다는 월등히 빠르다.

여기에, Scala에서 제공하는 Actor를 이용해 message 방식의 프로그래밍을 하면 훨씬 빠를 수 있다.

3.1 Actor?

Actor는 Java로 치면 일종의 Thread이다. Scala에서는 Actor에게 어떤 작업을 하라고 message를 보내면, Actor는 작업을 해야할 것들을 자신의 queue(mailbox라고 불린다)에 넣어두고, 하나씩 꺼내서 처리한다. Actor에게 message를 보낸 쪽에서는 message의 결과를 꼭 기다려야 하는 상황이 아니면, 자신이 하던 작업을 그냥 쭈욱 한다. 다시 말해 비동기적(asynchronous)으로 처리한다. 좀더 자세한 설명은 여기를 참고.

Actor가 대용량 처리시 빠른 이유는,
1) 비동기적으로 프로그래밍할 수 있도록 하며
2) 각 Actor가 mailbox에 메시지를 queueing을 해가면서, 동시에 엄청나게 많은 메시지를 처리할 수 있기 때문이다.

사실 actor, message의 개념은 erlang에서 차용한 개념이다. 이전의 포스팅에서 잠시 언급한 적인 있는데, erlang은 대용량 처리에서 훌륭한 performance로 유명하다.

4. Actor로 두 마리 토끼(productivity, performance) 잡기

웹 서비스에서 그 규모가 커지면, 흔히 client로부터 최초의 request를 받는 frontend 서버와 좀더 세분화된 작업을 처리하는 backend 서버로 그 구조가 진화하게 된다. Twitter역시 초기에는 Ruby on Rails의 한 종류의 서버만 있었지만, traffic이 커가면서 frontend/backend 서버 방식으로 진화했다. 좀더 자세한 내용은 여기 참고.

– Twitter에서의 frontend/backend 서버 구조 (출처: Twitter Engineering Blog)

frontend 서버가 client로부터 최초의 request를 받아서 여러 backend 서버에 다시 작업을 지시하고, 결과를 받아 최종 response를 client에 보내는 경우를 생각해보자. 가급적 backend 서버의 호출은 비동기적으로 이루어저야 frontend 서버는 좀더 대용량을 처리할 수 있다.

4.1 가상 시나리오

Actor의 훌륭함(?)을 설명하기 위해 다음과 같은 트위터에서의 가상의 request를 생각해보았다.

  1. 어떤 사용자 A의 가장 최근에 등록된 follower B를 찾아서
  2. B 사용자의 트윗 목록 중 최신 트윗 하나를 얻어와
  3. 이 트윗의 RT 카운트를 얻는다.

물론 이 시나리오는 조금 억지스러운 면이 있지만, 서비스를 만들다 보면 이렇게 backend 서버와 3단 이상의 콤보를 해야하는 경우는 사실 비일비재하다.

서비스 구조는 다음과 같이 되어 있다고 가정하겠다.

  • Follower를 알려주는 backend 서버와의 연동은 followerActor에서 담당
  • 트윗 목록을 알려주는 backend 서버와의 연동은 tweetActor가 담당
  • RT 카운트를 알려주는 backend 서버와의 연동은 statsActor가 담당

4.2 구현

이것은 다음과 같이 구현될 수 있다.

val futureResult = for {
    follower <- (followerActor ? GetLatestFollower(userId)).mapTo[User]
    tweet <- (tweetActor ? GetLastestTweet(follower.id)).mapTo[Tweet]
    count <- (statsActor ? GetRetweetCount(tweet.id)).mapTo[Int]
} yield count

futureResult onSuccess {
  case n:Int => //처리
}

futureResult onFailure {
  case e:Exception => //처리
}

1~5줄을 보면, 각 backend 서비스에 대해서 하나씩 별도로 처리할 필요없이, for를 이용해 처리하고 있다. 2~4 줄에서 actor에 대한 호출은 비동기적으로 처리되고, 성공적인 결과가 나올 때만 ‘<-‘ 연산자 앞의 변수 이름으로 값이 저장된다.

성공적으로 모든 backend 서버에 대한 작업들이 끝나면 8줄 부분이 호출된다. 중간에 어떤 작업에서라도 exception이 일어나면, 12번 줄 부분이 호출된다.

참고로 아래 코드는 actor에게 메시지를 보내고 결과를 기다리기 위해 ‘?’라는 연산자를 사용했다. 또 onSuccess, onFailure 등을 통해 callback을 등록했는데, 이것은 scala 언어 자체에서 지원하는 것은 아니고, Akka라는 라이브러리를 이용하면 가능하다.

마치며


최근에 node.js가 각광받고 있다. 무엇보다 node.js의 장점은 비동기적으로 쉽게 코딩할 수 있도록 해주는 것이 아닐까 한다. 혹시 Java 개발자의 경우에, node.js의 장점에 끌린다면, 이웃사촌인 Scala를 먼저 검토해보라고 권유해보고 싶다. 안정적인 VM, 이미 풍부한 open source들, 거기에 생산성을 배가시켜주는 scala의 문법. 또, 최근에는 Eclipse나 IntelliJ 같은 IDE에서 Scala 지원이 잘되고 있다.

많이 부족한 글을 끝까지 읽어주신 분들께 진심으로, 정말로 감사한 마음을 전하고 싶다. 내용 중에 설명이 부족했거나 또는 틀린 내용있으면 꼭꼭꼭 코멘트를!

오픈소스 첫경험

인터넷/모바일 관련 업계로 자리를 옮기면서 최근에는 오픈소스를 많이 이용하고 있다. 그 품질도 좋고, 또 커뮤니티에 질문을 하면 개발자들(committer)이 바로바로 답변을 해주니, 아주 도움을 많이 받고 있다.

어제는 버그 같이 보이는 것을 발견하고, 해당 오픈소스커뮤니티(구글 그룹스)에 질문을 올렸다. committer들이 바쁜지, 평소와는 다르게 하루가 넘게 답을 안해줘서, 오늘은 어디가 문제인지 직접 소스를 살펴봤다.

웹프레임워크 소스라 동작 방식이 조금 복잡했는데, 여차여차 문제가 되는 부분을 찾았고, 어플리케이션 단계에서 회피하는 방법도 찾았다. 그리고, 내용을 잘 정리해서 커뮤니티에 올렸다.

원문: https://groups.google.com/d/msg/play-framework/9OP-tEAxKaM/y39pLR2A19EJ

글을 올리고 보니, 그 사이에 committer로부터 버그인 것 같으니 이슈로 등록해달라는 글이 먼저 올라와 있었다.

원문: https://groups.google.com/d/msg/play-framework/9OP-tEAxKaM/0eB7xuNiel4J

그동안 덕본 것도 있고해서, 귀찮지만 이슈 트래커 사이트에 회원가입부터 하고 이슈를 등록했다.

원문: https://play.lighthouseapp.com/projects/82401/tickets/375-globalonstop-is-not-invoked

여기까지 하고나니, 조금 욕심이 생겼다. 내가 직접 프레임워크의 소스를 수정해보기로 했다. 먼저 github에 올라와 있는 원래 소스에서 fork를 해서 내 개인 repository를 만들었다. 코드를 수정해서 내 repository에 올리고, 이것을 반영해 달라는 pull request를 했다. Git은 한 1년 정도 써봤지만 pull request는 처음 해보는 거였는데, 다행히 많이 어렵지는 않았다.

이 오픈소스의 전체 소스를 다 파악하고 있지 못하기 때문에, 받아들여지지 않을 수도 있겠거니 했다. 그런데 곧 committer 중에 한 사람이 코멘트를 남겼는데, 소소한 것 좀 수정해줄 수 있냐는 내용이었다. 요청에 따라, 소소한 부분을 수정하고 2번에 걸친 commit을 하나로 깔끔하게 합쳐서(squash) 다시 올렸다.

원문: https://github.com/playframework/Play20/pull/249

이제 내가 만든 아주 약간의 소스는, 이 오픈소스와 한몸이 되기를 조마조마 기다리고 있다. 사실 그렇게 대단한 것은 아니지만, 항상 도움을 받기만 하다가 조금이라도 기여를 한다고 생각하니 이렇게 뿌듯할 수가 없다.

문제를 발견해서 공유하고, 버그로 등록하고, 그리고 pull request를 하는 일련의 과정을 조금씩이나마 해보면서 오픈 소스에 참여하는 방법을 조금은 익힌 것 같다. 이제 앞으로는 더욱 열심히 참여하겠노라 다짐해본다. 아자!

updated at 2012-5-3
다행히 pull request가 받아들여졌습니다. 🙂

주인이 되자

책을 읽으면서 눈물이 주루룩 흘렀다.

나는 사실 우리 한국 현대사를 잘 몰랐던 것 같다. 대학 신입생 때 선배들을 따라 정치 학회에 가서, 박정희, 전두환 군사 정권의 탄압에 대한 이야기를 들었지만, 그저 먼나라 이야기 같았고, 가슴이 아닌 머리로만 이해했던 것 같다.

몇 해 전, 고 김대중 전 대통령의 ‘김대중 자서전’을, 베스트 셀러라는 이유로 샀다. 1400페이지에 이르는 분량에 압도되어, 한 보름 동안은 방치했던 것 같다. 어느 일요일 오전이었던가 무심코 책을 폈다. 어렸을 적 섬마을의 똘똘한 김대중 어린이의 이야기가 흥미로웠다. 사업가로서 성공하는 이야기도 참 신났다.

즐거운 이야기는 거기까지였다.

책을 읽다보니 김대중 선생의 입장에서, 6.25 전쟁 중에 공산군에 의해 감옥에 갇혀 언제 죽을 지 모르는 공포를 경험했고, 4.19 혁명으로 잠시나마 민주화된 대한민국을 경험했다. 또, 지역 감정이 없던 시절, 강원도 인제에서 국회의원으로 당선되고 젊은 나이에 당 대변인이되지만, 5.16 쿠테타로 국회에 입성하지 못해 억울해하기도 했다.

유신정권의 탄압을 피해 일본에서 활동하던  중에 중앙정보부 요원에 의해 납치되어 생사의 갈림길에서 겨우 탈출해서 살아 남았고, 트럭이 승용차를 덮치는 의문의 사고로 죽을 뻔한 위기를 넘었다. 박정희 독재 정권 하에서 온갖 죄목을 뒤집어 쓰고 차디찬 형무소에 몇년을 지냈다. 그리고, 전두환 군사정권이 들어서고 내란죄로 사형선고까지 받고서, 사형수로서 집행일만 기다리는 극한의 공포를, 나는 느꼈다.

그렇게 그렇게 우리 선배들은 민주화를 위해 투쟁을 했다. 내가 지금 아무렇지도 않게 누리는 민주주의는 그렇게 얻어진 것이다. 시간이 됐으니 하늘에서 뚝 떨어진 것이 아니라, 인간의 존엄성을 지키고자, 수많은 사람들이 목숨을 걸고 싸워서 얻어낸 것이다. 안타깝지만 많은 사람들이 민주화된 대한민국을 못본채 그렇게 눈을 감았다.

책을 읽으며, 이들이 겪었을 울분을 생각하니 눈물이 주루륵 흘렀다. 거대한 권력앞에 공포를 느끼면서도, 옳은 것을 행하는 용기에 눈물이 주루륵 흘렀다. 나는 과연 이런 상황에 이렇게 행동할 수 있었을까 생각하니 마냥 부끄럽고, 죄송스러운 마음이 들었다.

우리는 민주화를 위해 싸운 기성세대에 빚을 지고 있다. 갚아야 할 빚이다. 빚을 갚는 방법은 단순 명료하다. 민주주의를 지켜내고 후손에게 물려주는 것이다. 아직 우리 사회에 남아 있는, 독재 시대의 반 민주주의적 가치관을 가진 기득권 세력으로부터 민주주의를 지켜내야 한다. 그러나 이것은 기득권에 빌붙은 수구 언론과 양심을 버린 학자들 때문에 쉬운 일은 아니다. 하지만, 우리가 현대사를 공부하고, 시대 정신을 이해하려 노력하면 할 수 있다. 그리고, 최근에는 대안 매체를 통해 옳은 목소리를 내는 언론도 있다. 무엇이 옳은 것인지 깊은 고민을 해야하고, 단호하게 행동 해야 한다.

우리나라의 민주주의는 아직 진행형이다. 냉철한 판단과 뚝심있는 행동으로 스스로 주인이 되자. 우리 선배들이 힘들게 쌓아올린 민주주의를 지켜내서, 우리 후배 세대에게 당당할 수 있도록 역사에 기록되자. 내가 있고, 너가 있으니 우리는 할수있다, 친구야.

Scala 시작하기

요즘 들어서 Scala를 공부하고 있다. 아직 많이 부족하지만, 지금까지 배운 것들 기록해두고, 또 혹시 조금이라도 도움이 되는 분들이 있을 지 몰라 공유해보고자 한다.

1. 들어가며


뭘 또 배워야 한단 말인가? 이미 C++, Java, Python, Ruby, JavaScript 등 많은 프로그래밍 언어들이 있는데, 왜 자꾸 새로운 언어가 나오고 있냐? 기존 걸로 안되냐?

라는 의문을 가질 수 있다. 나 역시 처음에 그런 생각을 했었다. 하지만, Scala에 대해 공부를 하다 보니, 이제는 그런 의문들이 많이 없어졌다. 어떻게 의문을 해소했었는지, 그럼 조금 자세히 이야기 해보겠다.

2. Scala?


Scala는 다음과 같은 특징이 있다.

2.1 Fuctional language이며 또한 object-oriented language이다.

Ruby나 C#을 쓰다가 Java나 C++ 같은 언어를 쓸 때 조금 답답한 것이, lambda와 같은 functioncal language적인 syntax가 없다는 것이다. 이것을 안 쓸때는 몰랐는데, 일단 손에 익으면 생산성이 매우 높아진다. Scala는 lambda를 비롯하여 여러 functional language의 문법을 지원한다. 동시에, object-oriented적인 요소도 지원하기 때문에, objected-oriented language에 익숙한 프로그래머들이 functional language를 배우고자 할 때 쉽게 다가갈 수 있다.

나는 C++이 초기에 다른 object-oriented language들을 제치고 성공할 수 있었던 가장 큰 이유가, C++이 C 문법도 지원했기 때문이라고 생각한다. C++ 컴파일러를 이용하면, C에 익숙한 프로그래머들은 C로 코딩을 하면서도, 부분부분 쉽게 object-oriented적인 요소를 사용할 수 있었다. 마찬가지로 Scala는 기존의 Java나 C++등 object-oriented language에 익숙한 프로그래머들을 functional language로 쉽게 끌어 들일 수 있는 장점이 있다.

2.2 Java Virtual Machine에서 동작한다.

Java Virtual Machine(이하 JVM)은 Java를 컴파일해서 나오는 bytecode가 동작하는 virtual machine이다. Scala는 특이하게도 소스 코드를 컴파일하면 그 결과로 JVM에서 동작하는 bytecode가 결과물로 나온다. 다시 말해 Scala는 JVM상에서 동작한다.

이것은 두 가지 중요한 의미를 갖는다. 하나는 컴파일 된 Scala 코드는 이미 10년 이상 최적화가 되어 있는 JVM 상에서 동작하기 때문에, 성능과 안정성을 어느 정도 보장한다.

또, 기존에 Java로 작성된 소스와 호환이 되기 때문에, 엄청나게 많은 Java 라이브러리들을 Scala에서 그대로 사용할 수 있다. 야호!

3. Who uses Scala?


Scala를 누가 쓰기는 쓰는가? 생각보다 많이 쓰고 있고, 점차 더 도입되는 추세인 것 같다. 대표적으로 다음과 같은 회사들이 사용한다.

3.1 Twitter

Twitter 서비스는 초기에 Ruby on Rails를 이용하여 개발되었다. 그런데 Ruby on Rails를 이용해 빨리 개발할 수는 있었지만, 이후에 traffic이 많아 지면서 성능이 문제가 되었다. 이를 해결하기 위해 Scala를 도입하였다고 한다. 트위터 개발자들의 인터뷰 참고.

3.2 FourSquare

FourSquare 서비스는 초기 버전은 PHP로 작성되었다고 한다. 하지만 사용자가 급증하자 software stack에 변화가 필요했고, Harry Heymann이라는 엔지니어가 이 작업을 주도하면서 Scala로 전면적으로 다시 개발했다고 한다. 이 과정에서 생산성 향상과 성능 향상이 있었다는 이야기도 있다. Scala 공식 홈페이지에 관련된 글이 있으니 참고.

3.3 Tumblr

Tumblr 또한 부분적으로 Scala를 쓰고 있다고 한다. Back-end용으로 쓰이고 있고, Twitter에서 만든 Scala용 라이브러리인 Finagle을 이용해 사용한다고 알려져 있다. Tumblr의 개발 방식에 대해 정리된 페이지 참고.

4. Scala 시작하기


Scala에 대한 흥미가 조금은 생겼으리라 예상해본다. 그럼 다음과 같은 자료를 활용해서 공부를 시작해보자.

4.1 Scala for the impatient

프로그래밍 경험이 어느 정도 있는 분들에게 추천하는 책이다. 제목에서도 알 수 있듯이 빨리 문법을 익혀 코딩해보고자 한다면 좋은 선택이다. 중요한 문법에 대해서 간결하게 잘 설명되어 있다. 공짜다.

4.2 Twitter Scala School

Twitter에서 만든 교육 자료이다. 아마도, 자사의 엔지니어들을 위해 만들지 않았나 생각된다. 내용이 간결하고, 예제 위주로 되어 있어서 빨리 익히기에 좋다.

4.3 Programming Scala

Scala의 동작 원리부터 차근차근 잘 설명한 책이다. Scala에 대해 좀더 깊이 이해를 하고자 하는 경우나 또는  프로그래밍 경험이 많지 않은 분들에게 추천하고 싶다. 역시 공짜다.

Programming language들이 많이 나오면서, 요즘은 각 language community들이 적극적으로 확산에 나서고 있고, 그래서 무료 자료가 참 많다. Scala를 공부하기 위해서, 굳이 돈주고 종이책 살 필요는 없을 듯 하다.

5. 개발 환경


5.1 build

Scala는 컴파일 language이기 때문에, build를 해주어야 한다. 물론 소스 하나씩 compile해서 build하는 방법도 있겠지만, 이것보다는 별도의 build 툴을 쓰면 편하다. 많은 scala 오픈 소스 프로젝트들이 최근에 simple build tool(이하 sbt)를 사용하고 있다. 사용법이 길지 않으니 꼭 사용법을 읽어보는 것이 나중에 수고를 덜어줄 것이다.

5.2 IDE

개발툴로 많이 쓰이는 것이 Eclipse와 IntelliJ IDEA이다. 2개 모두 사용해봤는데, 둘 다 괜찮다. Eclipse는 Scala IDE for Eclispe라는 plugin을 설치해야 하고, IntelliJ IDEA도 JetBrains에서 제공하는 Scala plugin을 설치해야 한다. 둘다 Syntax highlighting, debugging 등의 기능이 있어서 Vim이나 Emacs같은 에디터 보다 낫지 않나 싶다.

6. Hello World


그럼 간단한 프로그램을 만들고, debugging까지 해보겠다. 기본적인 순서는 다음과 같다.

  1. Eclipse 설치
  2. Scala IDE for Eclipse Plug-in 설치
  3. sbt 설치
  4. sbt용 디렉토리 구성
  5. sbt를 이용해 Eclipse 프로젝트 생성
  6. 소스 코드 작성
  7. Debugging

6.1 Eclipse 설치

Eclipse는 3.6(Helios) 버전을 설치한다.

6.2 Scala IDE for Eclipse

Eclipse용 scala plugin인 Scala IDE for Eclipse를 설치한다.

6.3 sbt 설치

이 링크를 이용하여 sbt를 설치한다.

참고로, sbt를 설명하는 wiki 페이지가 길지 않으니, 반드시 읽어보고 sbt의 개념이나 사용 방법을 알아두는 것이 나중에 시간을 줄일 수 있는 방법이다.

6.4 sbt용 디렉토리 구성

프로젝트의 기본 정보 및 사용하는 이 프로젝트에서 사용하는 플러그인을 설정하여 sbt용 디렉토리 및 설정파일을 구성한다. 이 부분은 sbt 메뉴얼을 참고하도록 한다.

6.5 sbt를 이용해 Eclipse 프로젝트 생성

앞에서 만든 sbt용 디렉토리로 들어가서 다음과 같이 입력하면 Eclipse용 프로젝트 파일인 .project와 .classpath가 생긴다.

> sbt eclipse

Ecilpse의 메뉴에서 ‘File’ > ‘‘Import…’를 클릭하고, 앞에서 만든 디렉토리를 선택하면 프로젝트를 열 수 있다.

6.6 소스 코드 작성

Ecilpse에서 앞에서 생성한 프로젝트를 열어보면 이미 ‘src/main/scala’ package가 생성된 것을 확인 할 수 있다. 이 package 밑에 App.scala 파일을 만들고 다음과 같이 입력한다.

object App {
  def main(args: Array[String]) {
    println("Hello, world!")
  }
}

6.7 Debugging 하기

이제 거의 다 되었다. println에 breakpoint를 설정하고, 메뉴의 ‘Run’ > ‘Debug’를 선택한 후에 ‘Scala Application’을 선택하면 프로그램이 시작되고, debugger가 동작해서 breakpoint에서 멈추는 것을 확인할 수 있다. 위 소스 파일은 이 곳에서 다운로드 받을 수 있다.

7. Scala용 Framework


이제 Scala용 프로그램을 만들 준비는 끝났다. 지금부터는 웹서비스 개발을 위해 이용할 수 있는 Framework 중에 개인적으로 제일 괜찮다고 보이는 2가지를 소개하려고 한다.

7.1 Play Framework

Play Framework는 Ruby on Rails의 Java 버전이라고 보면 되겠다. MVC 패턴에 맞춰 개발할 수 있도록 해주고, 여러가지 편리한 library를 제공한다. 실제 대용량 서비스에서 많이 쓰이고 있는 framework이라 안정성에도 문제가 없다고 할 수 있겠다.

현재 stable한 1.x 버전에서는 scala를 부분적으로 지원해서 조금 아쉽다. 하지만, Play 2.0에서는 본격적으로 Scala를 지원한다. 2.0은 현재 RC버전이며, 곧 정식 버전을 release할 것으로 보인다.

7.2 Finagle

Finagle은 Twitter에서 back-end 서비스용으로 만든 framework이다. 서버 간의 통신을 지원하는데 특화 되어 있다. 무엇보다 Twitter에서 실제로 사용되기 때문에 주목 받고 있고, Tumblr등 다른 서비스에서도 이용되는 듯 하다. 기본적인 서버 간 통신 기능 외에 비동기 처리, 분산 처리, 그리고 Memchached, Redis 등을 지원한다. Twitter에서 어떤 식으로 Finagle을 사용하는 지에 대해서는 Twitter Engineering 블로그의 이 포스팅에 잘 설명이 되어 있다.

8. 마치며


당연하겠지만, 소프트웨어 개발에 있어 어떤 언어가 최고인지 정답은 없는 것 같다. 상황에 맞게 언어와 라이브러리 등을 선택해야 할 것이다. 성능과 확장성(scaling)이 매우 중요하고, 비교적 빠르게 개발해야 하는 경우 라면, 내가 생각하기에 Scala가 제일 적합한 선택인 것 같다. 단, Scala 개발자가 많지 않고 언어를 배우는데에 learning curve가 조금 있기 때문에, 개발자가 바뀌는 상황이 되었을 때 향후 유지보수는 조금 어려울 수도 있다는 점은 주의해야 한다.

무엇보다도 Scala의 장점은 succint한 syntax 덕에, 개발자가 프로그래밍 그 자체에 집중할 수 있고 이로 인해 프로그래밍이 재미있다는 점이다. 좀더 많은 개발자들이 Scala를 접해보았으면 하는 바램으로 두서없는 글을 마치겠다.

오픈(open)에 대하여

솔직하게 고백하면서 시작하겠다.

Linux를 비롯한 오픈 소스와 그 개발 방식이 유행하기 시작할 때, 일부 컴퓨터 긱(geek)들의 문화라 치부했고, 주류가 되지 못할 거라고 생각했다. Microsoft나 Oracle이 하는 것처럼 소프트웨어는 과금을 해야 하고, 이 수익을 다시 소프트웨어에 투자해야 제대로 된 소프트웨어가 나올 것이라고 생각했다.

하지만, 틀린 것 같다. 지금 세상을 움직이는 많은 소프트웨어들은 오픈소스 프로젝트이고, 그리고 점점 많은 회사들이 오픈된 개발 문화를 지향하고 있다.

오픈 소스와 오픈 소스 개발 방식 그리고 그 근저의 철학에 대해서 생각해 본 바를 정리하고자 한다. 잘못된 시각일 수도 있고, 편협한 시각일 수도 있다. 그러니 이 글을 읽으신 분께서는 어떤 내용이라도 좋으니 피드백을~

1. Open Source?

간단히 정의하면, 오픈 소스는 소프트웨어의 소스 코드를 공개해 다른 사람이 이용할 수 있도록 하는 것을 말한다. 건축으로 치면 설계도를 공개하는 것이고, 학교 생활로 비유해보면, 열심히 한 숙제를 공개해서 누구나 베낄 수 있게 하는 것이라고 할 수 있겠다.

아, 보통의 사고 방식이라면 참으로 이해할 수 없는 방식이다. 왜 나의 노하우와 노력의 결실을 공개하는 것인가? 왜 다른 사람들이 별다른 노력 없이 내가 만든 걸 쓸 수 있게 하는 것인가? 누가 이렇게 한단 말인가?

놀랍게도 지금의 인터넷 세상을 가능하게 하는 많은 기술들이 사실은 오픈 소스 프로젝트들이다. 서버 OS로 이용되는 Linux, Database 솔루션인 MySQL, 웹서버 솔루션인 Apache, 대용량 처리를 가능하게 해주는 Hadoop 등이 오픈소스다. 거꾸로 이러한 오픈소스가 없었다면 Facebook이나 Twitter, KakakoTalk등이 없었을 지도 모르겠다.

2. Open Source 개발 방식?

오픈 소스 프로젝트들은 소스를 공개하는 것과 더불어서, 자신들의 소스가 많이 쓰일 수 있도록 여러 적극적인 활동을 한다. 익명의 개발자가 코드에 기여(contribution)를 할 수 있도록 프로세스를 갖추고 있고, 소스의 내부 구조(architecture)와 사용 방법에 대해 블로그와 컨퍼런스 등을 통해 알린다. 이러한 활동을 열심히 하는 오픈 소스 프로젝트들이 더욱 많이 사용되고 살아남는다.

요즘은 소프트웨어 회사에서 소스를 꼭 공개하지 않더라도, 이러한 개발 방식을 도입한 사례를 종종 볼 수 있다. 자사가 사용한 오픈소스 솔루션에 대해 사용 경험(best practice)을 블로그나 컨퍼런스 등을 통해 공유하고 있다.

3. 누가하는가?

Facebook이나 Twitter와 같은 회사들이 아이디어를 잘 만들어 성공한 회사라고 생각하면 오산이다. 적어도 내가 아는 한 이 두 회사는 컴퓨터공학에 있어서, 구글과 어깨를 나란히 하는 세계 최고의 기술 회사이다. 많은 오픈 소스 프로젝트들의 스폰서이고, 그리고 이 이 회사들의 엔지니어들이 직접 오픈소스 프로젝트에 참여하고 있다. 그리고, 이 오픈 소스를 자사의 서비스에 이용하고 있다. 특히 최근의 대용량 서비스를 가능하게 해주는 솔루션인 Cassandra, Hadoop 등이 바로 그 예이다.  국내에서도 NHN, Daum, KTH와 같은 회사에서는 컨퍼런스나 블로그를 통해서 노하우를 공유하고, 이따금씩 자사의 솔루션을 오픈 소스화 하고 있다.

누구도 부인하지 못하는 점은, 이 회사들이 이렇게 자사의 엔지니어들이 만든 소스를 오픈하면서도 성공을 하고 있고, 또 그들의 서비스들이 유사한 서비스를 제치고 지속되고 있다는 점이다.

4. Why successful?

솔직히 아직도 잘 모르겠다. 그저 짧은 지식으로 나름 파악해본 바는 다음과 같다.

4.1 집단 지성이 발휘된다

오픈 소스들의 특징은 commitor라 불리는 소스를 직접 컨트롤 하는 사람들외에도 익명의 다수 사람들이 기여할 수 있다는 점이다. 물론 오픈 소스가 지향하는 큰 방향은 commitor들에 의해 결정이 되겠지만, 자잘한 버그들이나 성능 개선 등은 익명의 수많은 프로그래머들에 이루어 지는 듯 하다. 마치 Wikipedia가 수많은 사람들의 참여로 브리태니커(Britannica) 백과 사전보다 그 내용이 우수한 것과 같은 이유가 아닌가 생각 된다.

4.2 참여자의 자기 만족이 크다

오픈 소스 프로젝트들은 저마다 정의한 문제를 각각의 시각으로 풀어내고 있다. 때문에 비슷한 솔루션을 여기 저기서 만드는 것이 아니라, 각각 고유한 솔루션을 만들어 낸다. 프로그래머들 사이에서 많이 쓰이는 말 중에 ‘Don’t reinvent the wheel’이라는 말이 있다. 똑같은 작업을 다시 싫어하기 싫어하는 프로그래머들의 특성을 잘 보여주는 말이 있는데, 오픈 소스에서는 이럴 가능성이 적다. 이것이 참여자의 생산성을 높여주는 것이 아닌가 생각된다.

또, 오픈소스에 참여하는 개발자는 자신이 가치 있는 일에 기여하고 있고, 이것이 오픈 소스를 통해 알려지고 명예를 얻는 것에 만족감을 느끼는 것 같다.

개발자들이 오픈소스에 참여하는 이유에 대해서는 @sm_park님께서 잘 정리해주신 소프트웨어, 잉여와 공포를 참고하기를.

5. 기업 입장에서 Open이란?

그러면 개개의 기업들은 오픈 소스와 오픈 소스 개발 문화를 어떻게 보고 어떻게 접근해야 할까?

기업 입장에서 오픈 소스 솔루션 자체를 도입하는 것은 좋은 점, 나쁜 점 모두 있는 것 같다. 당연히 새로 개발을 안하고, 어느 정도 검증된 솔루션을 쓸 수 있다는 것은 장점이다.

하지만, 간과해서는 안되는 부분이, 기술 회사를 지향한다면 오픈 소스를 도입하는 것과 더불어 자사의 기술 역량을 높이는 것을 게을리 해서는 안되는 것 같다. 오픈 소스를 도입하는 것은 마치 어려운 수학 문제를 푸는 데에 있어서, 답안지를 펴놓고 하는 것과 비슷하다고 생각하기 때문이다. 한 문제의 답을 아는 것이 지금의 상황을 이겨나가기는 좋지만, 나중에 또 다른 어려움이 닥칠 것을 생각해보면 근본적으로 역량(capability)를 키워 놓는 것이 중요하지 않나 생각된다. 마치 숙제를 열심히 베끼다 보면 숙제는 빨리 할 수 있지만, 실력은 늘지 않는 것처럼.

이것을 좀 과장해 표현하자면, 오픈하는 쪽의 마수(?)에 걸리지 않도록 조심해야 한다. 그 방법 중에 하나는 오픈 소스를 도입함과 동시에 자신도 오픈하는 것이 아닌가 생각된다. 회사 입장에서 ‘오픈’은 그 의미가 여러가지 일 수 있는데, 넓은 의미로는 타사에 대한 오픈이고, 좁은 의미로는 개인과 팀의 성과물을 다른 팀에게 오픈하는 것이다. 그러면 이 두 가지 의미를 포괄해서, 회사 입장에서 ‘오픈’이 갖는 의미에 대해서 좀더 자세히 이야기해보겠다.

5.1 사내에서 갖는 의미

1) 품질이 올라간다.

누군가 내 코드를 보고 거기에 대해서 평가한다고 생각하면, 프로그래밍에 임하는 자세가 분명히 다를 것이다. 알면서도 무시했던 여러가지 프로그래밍 원칙들을 지키려고 노력할 것이다. 쪽팔리기 싫으니까.

많은 오픈 소스 코드들과 그동안 내가 회사에서 보았던 코드와 비교해보면, 품질에 있어서는 오픈 소스 코드들이 압도적이다. 프로그래밍의 기본 원칙부터, 그 구조에 있어서 디자인 패턴의 적용 등 모든 부분에 있어서 좋다. 나 스스로는 이런 오픈 소스의 소스를 보면서 많이 배우고 있다고 생각한다.

2) 장기적으로 도움이 된다.

예전에, 오픈 소스의 버그를 고치고, 이것을 오픈 소스 커뮤니티에 알려주지 않고 자기 회사에서만 쓰는 경우를 보았다. 단기적으로는, 이 오픈 소스를 사용하는 다른 제품에 비해 경쟁우위가 생겼을 지 몰라도, 장기적으로 보면 손해 보는 일이다. 오픈 소스 버전이 올라갈 때 마다 수동으로 이 버그의 패치를 따로 해줘야 하면서 생기는 관리 비용이 생기기 때문이다. 또, 결국 이런 버그들은 언젠가 패치가 될 텐데 그때 가서 이것을 반영(merge)하려면 별도의 수고가 들고, 이런 것들이 프로젝트의 위험요소(risk)가 될 수 있다.

5.2 사외적으로 갖는 의미

실력과 자신감을 바탕으로, 자사가 만든 소스를 오픈하거나 또는 자사의 경험을 공유하게 되면, 업계와 개발자 커뮤니티에서 주목을 받게 되고, 기술 리딩(leading)회사로서 입지를 다지게 되는 것 같다. 특히 국내의 경우에 이렇게 하는 회사가 많지 않아, 해외의 솔루션을 잘 이용한 경험을 공유 해도 단번에 주목 받는다.

이렇게 회사가 주목 받으면, 그 회사가 내놓는 서비스나 제품도 초기에 주목 받기가 쉽다. 또 이렇게 기술을 리딩하는 회사로 포지셔닝을 하면 훌륭한 인재를 모으기도 쉽다. 적어도 내 주변만 보아도, 여러 조건이 비슷하면 기술적으로 명망이 있는 회사로 지원하는 개발자들이 꽤 있었다.

5.3 도의적으로 갖는 의미

약간은 이상적인 측면에서도 조금 언급해보고 싶다. 간단히 말하면, 공짜로 받은 것이 있으면 공짜로 줄 줄도 알아야 하는 것이 아닌가 싶다. 매일 친구의 숙제를 베끼지 말고, 한번쯤은 나도 친구들에게 숙제의 소스(source)가 되어주자. 매번 친구들에게 신세만 지면 친구들이 하나 둘 없어질 것이 아닌가. 조금 고상하게 표현하자면, 이것이 회사의 사회적 역할인 것 같다.

마치며

이렇게 장황하게 open에 대해서 썼지만, open을 해야만 성공하는 것인 지에 대해서는 확신이 없다. 적어도 open을 하더라도 꼭 실패하는 것은 아니고,  성공을 할 수는 있다는 점은 이제 배운 것 같다.

아직 open에 대해 확신이 서지 않는 이유는, 여전히 오픈 소스 개발 문화와 정반대에 있으면서도 새롭게 성공하는 회사들이 많기 때문이다. 대표적으로 애플과 아마존이 있는데, 애플은 자사의 주요 프로젝트에 대해서는 사내 직원들도 모르게 진행하고 있고, 아마존도 자사의 소스를 오픈하는 경우는 드물다.

하지만, 적어도 내가 보기에 open을 하는 것이 성공 확률을 높일 수는 있는 것처럼 보인다. 무엇보다, 나는 오픈 소스와 오픈 소스 개발 문화가 더 멋지게 보인다. 그리고, 기업이 커지면 관료화 되고 회사가 재미없어지는, 조직 경영의 문제를 푸는 데에도 오픈 소스 개발 문화가 열쇠가 될 수 있지 않을까 생각하고 있다.