2016년 2월 13일 토요일

어려운 것을 쉽게 배우는 방법 : 슈퍼 파워를 장착하기 위한 3단계 학습법

이번 포스팅에서는 노르웨이의 개발자인 Per Harald Borgen (미디엄, 페이스북, 트위터, 깃헙, 링크드인)이 미디엄에 공개한 "The Easy Way To Learn Hard Stuff :Three steps to gain a new superpower. (어려운 것을 쉽게 배우는 방법 : 슈퍼 파워를 장착하기 위한 3단계 학습법)이란 글을 번역하여 소개하고자 한다. 그의  미디엄에는 다른 멋진 글들이 가득하므로 꼭 한번 들러보길 추천한다.

글을 시작하기에 앞서 이 멋진 글의 번역을 흔쾌히 허락해준 Borgen씨에게 감사의 말을 전한다.


어려운 것을 쉽게 배우는 방법

슈퍼 파워를 장착하기 위한 3단계 학습법


지난 몇 년 동안 저는 많은 시간을 웹 개발과 머신 러닝을 독학하는데 많은 시간을 써 왔습니다.
학습의 테마는 자바스크립트, NodeJS, React에서 Python, Scikit-learn 그리고 신경망 프로그래밍에 이르기까지 다양했지만 이 모든것을 저는 일관된 방식으로 공부해 왔습니다.

제가 사용한 이 공부법은 3단계로 진행이 되는데 진부하다고 말해도 될 정도로 단순합니다. 하지만 웹 개발에 완전히 문외한 이었던 제가 단 5개월만에 스스로 프로라고 느끼는 것이 가능할 정도가 된 것은 이 공부법의 효과 덕분이라고 생각합니다.

저는 이 학습법이 다른 사람에게도 도움이 될지 모른다고 생각하여 이 기사를 써 보기로 마음먹었습니다.

이 기사는 아무 것도 모른채 무작정 도전을 시작한 2012년 당시의 제 자신을 가르친다는 마음가짐으로 작성하였습니다.

1단계: 배우기전에 익숙해져라

새로운 기술을 배우기 위해서 가장 먼저 실행하는 첫 단계는, 머리로 이론을 학습 하려 하지 말고 어찌되었든 손을 움직여서 사용해 보는 것 입니다. 이러한 방식이야 말로 이론부터 머리속에 넣는 방법보다 훨씬 뛰어납니다.

그렇다고는 해도 배우고자 하는 테마에 대해서 아무 것도 모르는 상태 이므로 자력으로는 뭘 어찌 해 볼 도리가 없습니다.


Justine Michel의 Django 강좌는 완벽하게 "배우기전에 익숙해져라"라는 방식으로 진행이 됩니다.


그래서 우리가 맨 먼저 할 일은 작은 뭔가를 더미로서 만드는 과정을 개략적으로 설명해주는 튜토리얼 영상을 찾는것 입니다. 저자가 설치부터 한 줄 한 줄 끝까지 코드를 설명해 주는 튜토리얼을 찾아 비디오를 보며 여러분도 똑같이 코딩해 보세요. 그 연습용 프로젝트가 제대로 작동하는 것을 확인하며 한줄 한줄 쫓아가는 겁니다.

10분정도의 영상이라고 한다면 여러분이 그것을 끝까지 쫓아 하는데에는 1시간정도 걸린다고 생각해 두세요.

또한 MOOC 코스보다는 숙련된 아마추어가 YouTube에 올린 영상쪽이 오히려 공부하기가 쉬울지도 모릅니다. MOOC를 지금 단계에서 보기엔 너무 부담스러운 경우도 있기 때문입니다.

이 방법의 정 반대되는 접근방법은 그 주제에 대한 책을 읽고 이론부터 배워 나가는 것 입니다. 다만, 그 방법은 제게는 잘 맞지 않았습니다. 다 읽기도 전에 질려버리기 때문입니다. 초보자를 위한 책 조차도 대게는 너무 자세하기 때문입니다. 그래서 저는 책이나 문서를 처음 단계에서는 절대 보지 않으려고 합니다.
튜토리얼 비디오를 따라하는 과정속에서, 자신이 지금 무얼 하고 있는지 알 수가 없어 불안하게 느낄 수도 있습니다. 하지만 그런건 신경쓰지 마세요. 이해 할 수 없는 것은 일단 메모를 해 두고 2단계에서 다시 살펴 봅니다.

이 단계의 핵심은 혼란 스럽거나 지식이 부족하더라도 일단 끝까지 튜토리얼을 한번은 쫓아가는것 입니다.

이러한 방식의 단점을 넘어서는 장점은 다음과 같습니다.

1. 첫날부터 일단 뭔가 만들어 본다

첫날부터 실제로 뭔가를 만들기 때문에, 이론만 읽고 공부만 하는것 보다 만족감을 맛볼 수 있습니다. 그리고 이러한 만족감은 학습을 계속하려고 하는 의욕으로 연결됩니다.

제가 맨 처음 만든 Node.js서버 입니다. 두고두고 많은 참고가 되어 주었습니다.

2. 샘플코드를 얻을 수 있다


게다가 학습과정에서 언제든지 참고할 수 있는 샘플코드들이 여러분의 수중에 남게 됩니다. 이 단계에서 만들어진 샘플 코드들은 이후 단계에서 매우 유용하게 쓰여지게 됩니다.

저는 배우고자 하는 테마에 대한 이해가 깊어졌다고 실감 할 때마다 과거에 만들어둔 예제 코드를 여러번 반복해서 살펴 봄으로서 기억을 새롭게 하고 있습니다.

3. 자신이 무엇을 모르는지 파악 할 수 있게된다


또한, 제 자신은 스스로 공부해 나가는 중에 특히 어느 부분을 신경써서 공부해야 하는지를 발견하는데 있어서 이 방법이 가장 빠르다는것을 깨달았습니다.

학습을 시작하기 전에는 무엇을 아는지 모르는지도 알 수 없는 상태이기 때문에, 배우고자 하는 기술의 어떤 부분에 신경을 써야 하는지, 어느 부분이 까다로운 지를 알 방법이 없습니다. 그렇기 때문에 특히 주의가 필요합니다. 이러한 부분은 가능한 한 빨리 파악해 두는것이 필요 합니다만 이것이 하나의 장벽이 되지 않도록 이해하는 것은 나중에 천천히 해도 됩니다.



아래의 목록은 제가 다양한 테마를 배우기 시작하는데 있어서 많은 도움을 받은 튜토리얼들 입니다.



2단계: 난관에 도전하라


1단계에서 언급한 교제를 적어도 한번 끝까지 마치고 나면 배우고자 하는 기술의 전체적인 구조에 대한 감을 잡을 수 있게 됩니다. 하지만 분명 아직까지는 머리속이 뒤죽박죽일 껍니다. 그래서 다음 단계는 이러한 혼란을 해소하는 것 입니다.

React.js를 배우고 있다면, 그것은 상태와 속성의 차이가 무엇인지를 제대로 파악하는 것 일 겁니다. (참고로 여기를 읽어보시면 이해하실 수 있을것으로 생각합니다.)

이 단계에서는 사실 구체적으로 추천할 수 있는 무언가가 없습니다. 기본적으로는 상황에 맞춰서 책, 공식문서, 스텍오버플로등 어떤 것이라도 살펴볼 필요가 있습니다.

지난번 제가 이것을 경험한 것은 신경망의 코딩 방법을 공부 할 때 였습니다. 코세라 과정을 수강하고 알았지만 신경망의 전체를 이해할 수 있으려면 로지스틱 회귀를 이해할 필요가 있었던 겁니다. 그래서 로지스틱 회귀에 대한 기본적인 공부를 우선 마친 후에 다시 신경망에 대한 학습에 임한 결과 이번에는 훨씬 더 쉽게 이해할 수 있었습니다.

3단계: 뭔가 만들어 본다

1단계와 2단계는 절대 건너 뛸 수 없는것 이지만 사실은 3단계를 위한 디딤돌에 지나지 않습니다. 새로운 기술을 배우고 싶다는 것은 그 기술로 뭔가를 만든다는 것 입니다. 드디어 이번 단계에서 이러한 목적을 실행에 옮깁니다.

스스로 새로운 뭔가를 만들 수 있게 되었다면 즉시 있는 힘껏 부딧쳐 봅시다.

왜냐구요? 실제로 무언가를 만드는 것이야 말로 진정한 의미에서의 배움의 완성이기 때문입니다.

기술을 배우고 나서도 무언가를 만들지 않는다면 그건 진정한 배움이라 할 수 없습니다.

1단계와 2단계는 대충 넘길 수 있지만 3단계는 그럴 수가 없습니다. (여기서 말하는 만들기는 단순히 코드를 복사하고 붙여넣기가 아닙니다)

만들것은 평소에 관심을 가지고 있는것과 연결 시키는 것이 좋습니다. 예를들면, HTML과 CSS를 배우는 와인 애호가라면 와인 시음에 대한 웹사이트의 프로토 타입을 만들어보면 좋을겁니다. 머신러닝에 대해 배우고자 하는 의사라면 건강관련 데이터세트부터 시작해 보는것이 어떨까요?

제가 초기에 수행한 프로젝트에서는 다음과 같은 것을 만들었습니다.
어디가서 자랑할 수준은 아니지만 저에게는 많은 공부가 되었습니다.



제가 만든 최초의 Ajax프로젝트 입니다. 2014년 초순경에 Founders&Coders 팀으로서 구축에 참여하였습니다.

마지막으로 말씀드리고 싶은것은, 위에서 언급한 3단계는 때때로 얽혀 있기도 하여, 이 기사에서 적은것 처럼 순차적으로 진행되기만 하는것은 아니라는 점 입니다.

저는 반드시 1단계부터 시작해 3단계로 마무리를 하지만, 학습 도중 이전 단계로 돌아가는 일도 자주 있습니다.

중요한것은 이 세 단계가 각각 새로운 기술을 배우는 것 만큼이나 중요한 요소라는 사실 입니다.

여러분의 성공을 기원합니다!

역주: 혹시 이 기사가 마음에 드신다면 원문으로 가셔서 하트(미디엄의 좋아요)를 꼭 눌러 주시기 바랍니다. 그리고 영어가 되신다면 댓글도 남겨주신다면 고맙겠습니다. ^_^

2016년 1월 18일 월요일

고성능 비동기 처리 구현을 위한 Java web 프레임워크 - Ratpack

스마트 기기로의 권력 이양이 순조롭게 진행되고 있는 지금, 시대는 바야흐로 Single-page Application(SPA)의 전성시대이다.
필자가 속한 엔터프라이즈 어플리케이션 개발 영역에서도 반응형 웹앱 개발에 대한 요구가 점차 강해지는 가운데 안정성이 검증된 자바 생태계 위에 SPA를 도입하려는 움직임이 점차 본격화 되고 있다.

이번 포스팅에서는 SPA의 구현에 있어서 본좌라고 할 수 있는 node.js와 유사한 처리모델과 고성능 비동기 처리의 실현, 그리고 심플한 구현을 특징으로 하는 자바 웹 프레임워크인 Ratpack을 소개해 보고자 한다.

포스트의 내용은 Ratpack의 메뉴얼, infoq의 기사인 Ratpack 1.0 Launches Aiming to make Asynchronous Programming Easier on the JVM 그리고 역시 infoq의 기사인 Build High Performance JVM Microservices with Ratpack & Spring Boot에 기반하여 작성되었다.



Ratpack이란?

Ratpack의 핵심 기능들은 Java8으로 작성되어 있고 빌드 시스템은 Gradle 2.6을 채용하고 있다. 처리 베이스는 non-blocking형 이벤트 구동 네트워크 엔진인 Netty를 사용하여 비동기처리를 구현하고 있다.

Ratpack은 마이크로서비스의 개발을 특별히 의식하여 디자인이 되어 있다. 대표적으로 JSON과 같이 특정 언어에 비 종속적인 프로토콜을 최 우선적으로 서포트하고 있으며, 옵션으로 넷플릭스의 서킷 브레이커 라이브러리인 Hystrix나 레포팅을 위한 Dropwizard Matrics를 지원하고 있다. 설정정보관리는 YAML과 JSON 그리고 Java프로퍼티가 사용 가능하다.
Ratpack은 오픈소스 프로젝트로서 개발이 진행되고 있으며, 아파치 라이센스를 사용하고 있다.

Ratpack은 2015년 9월에 1.0이 발표되었으나 사실은 제법 긴 스토리를 가지고 있다. 2010년 Groovy의 DLS구현체로서 출발하여 얼마 후에는 JVM상의 Sinatra 클론으로 프로젝트의 성격이 바뀌었고 2012년부터는 NIO를 이용한 고성능 비동기/non-blocking 어플리케이션 구현을 위한 프레임워크로 변경되어 오늘날에 이르렀다. 


Ratpack의 개발 목표

매뉴얼에 기재된 Ratpack이 표방하는 개발 목표는 다음과 같다.
  1. 빠르고, 확장가능하며, 고효율이어야 한다.
  2. 응용프로그램을 성능저하 없이 복잡하게 발전시킬 수 있어야 한다.
  3. non-blocking 프로그래밍의 장점을 활용하면서도 비용을 절감시킬 수 있어야 한다.
  4. 다른 툴과 라이브러리들과 통합함에 있어서 유연하고 개방적이어야 한다.
  5. 응요 프로그램을 쉽고 완벽하게 테스트 할 수 있어야 한다.
반면 다음의 사항들에 대해서는 지양하고 있음을 밝히고 있다.
  1. 완벽하게 통합된 "풀스텍" 솔루션
  2. 필요한 모든 기능을 제공하는 "만능 칼"
  3. "비즈니스 로직"을 위한 프레임웍 혹은 아키텍처

심플한 비동기 처리의 구현

Ratpack의 가장 큰 특징은 뭐니뭐니해도 심플한 비동기 처리의 구현이다. JVM위에서 비동기 처리라는 과제에 도전하고 있다는 점 에서 자주 Akka와 비교되곤 하는데, 코딩스타일에 있어서 자바8을 기반으로 한 만큼 모나딕을 전면적으로 도입하고 있는것이 메뉴얼에서 잘 드러난다.

아래 예제는 Ratpack의 메뉴얼에 실려있는 RESTful HTTP API 헨들러 체인의 구현이다.

package springpack;

import ratpack.server.RatpackServer;

public class Main {

  public static void main(String[] args) throws Exception {
    RatpackServer.start(spec -> spec
      .handlers(chain -> chain (1)
          .prefix("api", pchain -> pchain (2)
            .all(ctx -> ctx (3)
              .byMethod(method -> method (4)
                .get(() -> ctx.render("Received GET request"))
                .post(() -> ctx.render("Received POST request"))
                .put(() -> ctx.render("Received PUT request"))
                .delete(() -> ctx.render("Received DELETE request"))
              )
            )
          )
      )
    );
  }
}

처리모델

Ratpack의 처리 모델은 node.js의 그것과 닮아 있다. 다음 그림은 4코어 시스템에서 동작하는 Ratpack의 처리 모델의 개요를 나타내고 있다.


Ratpack은 기동과 함께 지정한 코어 수 만큼의 이벤트 루프가 바인딩 된다. Ratpack은 Netty를 이용해 "이벤트 루프 그룹"을 생성하고 사용 가능한 CPU코어에 각각의 단일 스레드로 동작하는 이벤트 루프를 바인딩 한다. 각각의 이벤트 루프는 응용 프로그램에서 도착하는 non-blocking 네트워크 요청을 처리한다. 즉, 하나의 비동기처리 요구에 대하여 하나의 CPU에 바인딩 되도록 하는 처리 방식을 통해 고성능 비동기 처리를 실현하려 하고 있는데, 최근 실시한 벤치마크에서는 단순 Hello World의 경우 32코어 머신에서 초당 1억 리퀘스트를 단일 JVM인스턴스로 처리 할 수 있는 것으로 알려져 있다.
비동기 & non-blocking에 대한 보다 상세한 내용은 Ratpack의 메뉴얼을 참고하기 바란다.

2016년 1월 17일 일요일

TDD, BDD를 넘어서 - 검증 주도 개발(Verification-Driven Development,VDD)에 대하여

최근 진행한 나는 프로그래머다 녹음에서는 서울대학교 컴퓨터 공학부의 이광근 교수님을 모시고 최근 저술하신 책 - 컴퓨터과학이 여는 세계와 학문으로서의 컴퓨터 과학을 주제로 방송을 진행하였다. 임작가님이 3연휴를 희생하여 편집에 의욕을 보여 주신 덕분에 빠르게 공유될 수 있지 않을까 기대해 본다. (블로그 글을 작성하고 있는 도중에 편집본이 도착했다 ^^)

방송 말미에 앞으로 교수님께서 주목하고 있는 언어 관련 최신 동향에 대해서 소개를 부탁드려 봤는데 그때 말씀해 주신것이 지금부터 소개하려 하는 정확한 검증(formal verification)이다. 아직은 학문적 영역에 머물러 있지만 조만간(이교수님 말씀으로는 5년) 우리 앞에 모습을 드러 낼 수 있을것으로 보이기에 어떠한 것인지를 현업 개발자의 시선에서 설명해 보고자 한다.

정확한 검증(formal verification) 과 정확한 사양(formal specification)


정확한 검증이란,  하드웨어 및 소프트웨어 시스템에서 정형기법과 같은 수학 논리를 이용하여 어떤 정확한 사양 기술 및 속성에 비추어 시스템이 올바른지를 증명 하거나 반대로 잘못된 것을 증명하는 것을 말한다. 구현하고자 하는 대상을 정확한 검증이 가능하도록 기술하는 것을 명세 언어(Specification language)라 하는데 대표적인 명세언어는 우리가 개발에서 흔히 사용하는 UML이 있다.

정확한 검증이 도입되면 대상 시스템이 명세 언어로 작성된 사양에 비추어 올바른지 여부를 자동으로 판정하는 것이 가능해진다. 이를 통해 개발 과정에서 구현과 동시에 사양에 대한 검증을 실시하는것이 가능해 진다. 

정확한 검증의 필요성은 설계 (또는 구현)의 '정당성'은 그 자체만으로 확인할 수 없다는 점에서 출발한다. 정당성은 주어진 사양과의 검증을 통해 처음으로 확인 가능하며, 정확한 사양의 표기가 해결해야 할 문제를 제대로 설명 할 수 있는지 여부는 또 다른 문제이다. 이것 또한 어려운 문제이며, 비 형식적인 실제 문제를 추상화 된 형식적인 사양 기술에서 제대로 설명해야 하는 문제에 귀착한다. 이러한 요약(abstraction)은 증명이 불가능하다. 그러나 사양에 대한 정리 를 증명할 수 있다면, 사양의 무결성을 검증하는 것은 가능하다. 

 검증에 대한 개요. 구현과 사양의 개발이 함께 진행되고 최종적으로는 툴에 의한 검증이 이루어 진다는 점에 주목하자.  이미지 출처: OS Verification -- Now! 


현재 현업 개발현장에서 사용되고 있는 일반적인 자동화 검증 기법은 다음과 같은 것 들이 있다.

  • 단위 테스트(Unit test) : 함수(또는 메소드)단위로 테스트 코드를 작성하여 실시하는 자동화 테스트. 반복개발 프로세스 안에서 단위 테스트를 구현과 묶어서 개발 하는 방법론을 테스트 주도 개발(Test-Driven Development,TDD)이라 부른다.
  • 행위 테스트(Behavior test) : 테스트 범위를 함수 단위에서 기능단위로 확장시킨 테스트형태를 말하며 테스트가 사양 명세(Specification) 그 자체가 되는것을 목표로 하기때문에 테스트 코드의 작성에는 자연 언어에 가까운 도메인 고유 언어(DSL)가 선호된다.  TDD와 마찬가지로 개발 프로세스에 행위 테스트 작성을 프로세스의 일부로서 도입한 개발 형태를 행위 주도 개발(Behavior-Driven Development,BDD)이라 부른다.
  • End-To-End 테스트(e2e test): 독립적으로 작동하고 Mock와 Stub를 사용하는 BDD 나 단위 테스트와는 반대로,  End-to-End 테스트는 가능한 한 실제 시스템의 사용자에 가깝게 에뮬레이션하려고한다. 대표적인 툴 로는 Selenium 이 있다.

자동화 테스트와의 차이

 위에서 소개한 자동화 테스트들이 정해진 숫자의 테스트 케이스만을 소화해 내는 형태인데 비해 정확한 검증은 구현된 로직 자체가 사양과 일치 하는지를 검증해 내고자 한다. 실제로 TDD를 이용해 개발을 해 본 개발자라면 사람이 예상한 테스트 케이스와 실제 동작에서 발생하는 경우의 수 사이에 늘 차이가 존재 할 수 밖에 없다는 사실에 동의할 것이다. 설사 많은 노력을 투입하여 모든 경우의 수를 커버하는 테스트 케이스를 작성한다 할 지라도 그것이 애초에 구현하고자 한 대상과 동일한 것이라는 사실을 보장해 주지 못한다. 이상적인 정확한 검증의 구현은 사양 자체가 검증과 일체화 되기 때문에 구현에 대한 버그가 발생하게 될 여지가 존재하지 않는다. 이러한 점은 BDD가 이루고자 하는 목표와도 일치한다.

정확한 검증 방법

정확한 검증은 크게 두 가지로 분류된다.


모델 검사

첫 번째 방법인 모델 검사는 수학적 모델을 통해 체계적이고 철저하게 검증하는 것을 말한다. 여기서 말하는 모델은 유한 상태 모델을 지칭 하지만 무한의 상태를 가지는 모델도 추상화를 통해 유한 표현으로 전환이 가능하다면 확인 가능한 모델로 취급한다. 일반적으로 모델의 전체 상대와 전체 상태 전환의 검증을 포함하며, 연산 시간을 줄이기 위해 영역고유의 추상화 기법을 이용하여 효율화를 도모한다.

다만, 모델 검사는 하드웨어 설계에 적용되는 경우가 많고 소트웨어에 대한 모델 검사는 결정 불능이므로 알고리즘적인 방법만으로는 완전하지 않고, 증명도 반증도 할 수 없는 경우가 있다. 모델검사에 사용되는 방법으로는 선형시상논리(Linear Temporal Logic,LTL)나 계산 트리 논리(Computational Tree Logic, CTL)가 있다. (솔직히 나 자신은 이 글을 작성 하면서도 위의 링크를 눌러 볼 엄두가 안난다.)

논리적 추론

두 번째 방법은 논리적 추론이다. 일반적으로 엄밀한 논리 추론을 돕는 자동도구(Automated Theorem Proving, ATP) 소프트웨어를 사용하여 시스템에 관한 정확한 추론을 실시한다. 이 기술은 완전 자동화 되어있지 않은것이 일반적이었으나 최근들어 Perfect Developer와 Escher C Verifier와 같은 도구가 등장하여 증명에 대한 완전 자동화를 시도하고 있다. 

Java Modeling Language(JML)과 Spec#

학교와 연구소에서 벗어난 정확한 검증이 우리 앞에 어떠한 모습으로 나타날까? Java Modeling Language(JML)과 Spec#은 논리적 추론을 통해 정확한 검증을 구현하려는 프로젝트이다. 어노테이션에 검증을 위한 사양을 JMS 사양 이라는 표기법으로 기술한다.

이해를 돕기 위해 위키사전에 실려 있는 JML 의 예제를 살펴보자.

public class BankingExample
 {
 
    public static final int MAX_BALANCE = 1000; 
    private /*@ spec_public @*/ int balance;
    private /*@ spec_public @*/ boolean isLocked = false; 
 
    //@ public invariant balance >= 0 && balance <= MAX_BALANCE;
 
    //@ assignable balance;
    //@ ensures balance == 0;
    public BankingExample()
    {
        this.balance = 0;
    }
 
    //@ requires 0 < amount && amount + balance < MAX_BALANCE;
    //@ assignable balance;
    //@ ensures balance == \old(balance) + amount;
    public void credit(final int amount)
    {
        this.balance += amount;
    }
 
    //@ requires 0 < amount && amount <= balance;
    //@ assignable balance;
    //@ ensures balance == \old(balance) - amount;
    public void debit(final int amount)
    {
        this.balance -= amount;
    }
 
    //@ ensures isLocked == true;
    public void lockAccount()
    {
        this.isLocked = true;
    }
 
    //@   requires !isLocked;
    //@   ensures \result == balance;
    //@ also
    //@   requires isLocked;
    //@   signals_only BankingException;
    public /*@ pure @*/ int getBalance() throws BankingException
    {
        if (!this.isLocked)
        {
                return this.balance;
        }
        else
        {
                throw new BankingException();
        }
    }
 }

cucumber나 RSpec을 접해본 독자라면 위와 같은 표기법이 낮설지 않을것이다.

이번에는 마이크로소프트의 연구소에서 연구중인 Spec#의 예제를 살펴보자. 아래 예제는 C#에 기술된 Spec#이다.

static void Main(string![] args)
        requires args.Length > 0;
    {
        foreach(string arg in args)
        {
            Console.WriteLine(arg);
        }
    }

'requires args.Length > 0;'이 Spec#의 구문으로 자바에서 흔히보는 Assertion과 흡사하다. 위 예제는 설명을 위해 단순한 값에 대한 검증만을 기술하고 있지만 API레벨에서 이뤄지는 복잡한 동기화에 대한 기술도 가능하다.
Spec#에 대해 좀 더 자세히 알고 싶으신분은 공식 사이트를 방문해 보시길 권한다.

멀티코어,비동기, 동시성, 함수형 그리고 검증 주도 개발(Verification-Driven Development,VDD)

필자가 정확한 검증에 주목하는 이유는 유닛테스트나 e2e테스트와 같은 기존의 테스트 패러다임으로는 동시성과 관련하여 발생하는 오류를 찾아내기가 힘들기 때문이다. 오늘날의 컴퓨팅 한경은 멀티코어가 일반화 됨에 따라 이에 대응하기 위한 비동기, 동시성 프로그래밍 패러다임이 출연하였다. 그리고 이를 보다 효과적으로 구현하기 위한 함수형 프로그래밍은 본격적으로 하나의 큰 흐름을 시작하고 있는 단계이다. 비동기 프로그래밍의 가장 큰 난관으로 꼽히는 것은 테스트의 어려움이다. 발생할 수 있는 경우의 수에 대한 파악도 어렵고 재현도 어렵기 때문이다. 이제 막 보급되기 시작한 이러한 새로운 개발 패러다임 에는 테스트의 복잡도 제어와 효율적인 검증이라는 큰 숙제가 여전히 남겨져 있는 상태인 것이다.
하지만 만약에 코드 자체가 스스로의 완전성을 보장해 준다면 어떨까?
정확한 검증이 그 대안이 되어 줄 수 있지 않을까? 꿈같은 이야기로 들릴지 모르지만 어차피 지금 우리들이 사용하는 기술들은 과거엔 마법같이 여겨지던 것들이다.
이교수님의 말씀처럼 가까운 실일내에 정확한 검증 기술이 상용 코드에 적용 가능한 수준으로 성숙된다면 BDD를 넘어서서 검증 주도 개발(VDD)이라는 패러다임이 등장할 수도 있다는 것이 필자의 생각이다.

필자의 의견으로는 지금 현업에 있는 대부분의 프로그래머에게 있어 당장 정확한 검증을 익혀두거나 도입을 서두를 필요는 없을것이라 본다. 다만, Cucumber와 같이 트레이드 오프에 대한 검증이 끝난 BDD 프레임웍의 도입은 DevOps시대를 맞이하여 효율적인 품질관리와 생산성 증대를 위해서라도 살펴봐 두는 자세가 필요할 것이다.


참고 문헌 & 관련 링크


※이광근 교수님의 피드백을 받아 학술 용어의 번역에 대해서 수정을 하였습니다.(2016.1.17)


2015년 12월 18일 금요일

Terraform과 Consul을 이용한 DevOps


오늘은 InfoQ에 올라온 기사를 번역해 소개해 보고자 한다.

Automating the Modern Datacenter with Terraform and Consul


이 기사에는 DevOps와 관련해서 중요한 개념들을 알기 쉽게 설명하고 있다. 영어에 어느정도 자신이 있고Terraform과  Consul에 대해서 좀 더 깊이있게 알아보고자 한다면 아래 링크를 통해 Hashimoto의 강연을 직접 보시길 권한다.

Mitchell Hashimoto (HashiCorp) - Automating the Modern Datacenter, Development to Production


CraftConf 2015 에서 Mitchell Hashimoto 는 대중적으로 사용되고 있는 프로비저닝 및 구성 도구에 대해 '현재의 데이터 센터'를 관리하기에는 적합하지 않은 것이라고 평했다. 오늘날의 데이터 센터에는 민첩하고 탄력성이 요구된다. 그리고 컴퓨팅리소스나 DNS, CDN 등 응용 프로그램의 배포에 필요한 '서비스'는 다양한 공급 업체가 제공하는 이기종 플랫폼이 조합될 가능성이 있다. 이러한 과제를 안고 있는 오늘날의 비즈니스 환경에서 자동화를 제공하는 방법으로 그는 Hashicorp의 Terraform 과 Consul 두 가지 도구를 소개했다.

Hashimoto는 Hashicorp 의 창업자이며, Vagrant 와 Packer 의 프로젝트 리더이기도하다. 그의 강연은 데이터 센터 기술의 역사를 설명하는 것으로부터 시작되었다. 기업의 관점에서 데이터 센터의 이용은 하나의 물리적 서버에서 발전하여 여러 베어 메탈 서버로 옮겨 결국 여러 가상화 인스턴스에 도달하고있다. 그리고 이 진화의 최신 트렌드가 바로 컨테이너화 의 움직임이다. 이러한 진화에 따라 프로비저닝 및 배포, 유지 보수 등의 작업은 복잡해지고 자동화에 요구는 급박한 과제가되었다. 초기에 이러한 요구 사항을 충족하기 위해 나타난 것이 CFEngine 과 Chef , Puppet , Ansible 과 같은 툴들이다.

공용 및 사설 클라우드 기술의 보급으로 우리는 지금 새로운 도전을 안고 '모던 데이터 센터'를 운영하고 계속하고 있다고 Hashimoto 는 설명했다. 일단 핵심 인프라 스택에 통합 된 DNS와 CDN 또는 데이터베이스와 같은 기술이 현재는 서버 기반 제품으로 전환하고있다. 또한 기업 측에서도 서로 다른 벤더를 사용하여 인프라 플랫폼을 개발하는 것이 많아졌다. 이러한 두 가지 변화에 따라 기존의 프로비저닝은 새로운 복잡한 레이어를 추가하고있다. 이러한 요구에 대해 앞에서 언급한 툴들로는 요구를 충족시킬수 없다는 것이 Hashimoto 의 주장이다.

설치하고자하는 응용 프로그램의 하나 하나에 Chef 나 Puppet의 자동화를 제공 할 수는 있을 것입니다. 그렇지만 만약 필요한 서비스 모든 설정을 자동화하는 방법이 없다고한다면 무슨 일이 벌어질까요? 즉, 응용 프로그램이 동작하지 않는 상황이 발생하는 겁니다 ...

데이터 센터에서 벌어지는 활동의 중심은 서버와 데이터 저장소,로드 밸런서 등 자원의 취득(acquisition), 제공(provision), 업데이트(update), 폐기(destruction) 등의 작업으로 구성되는 경우가 많다. 일단 이러한 과정은 느리고, 그 결과 또한 어느쪽인가 하면 정적이라 할 수 있었지만, 현재는 이러한 활동이 점차 빨라지고 출력도 탄력적으로 확장 가능하게 되는 추세이다. 이러한 예는 컴퓨팅 리소스의 프로비저닝이라 볼 수 있을것이다. 기존의 데이터 센터라면 서버를 구입하고 물리적 랙에 담아 프로비저닝 한 후 고정적인 단위로 배치하는 것이었다. 그러나 현대적 데이터 센터에서 컴퓨팅 인스턴스는 API 호출을 통해 획득 도고 기동시에 구성이 지정된다. 인스턴스를 그 자리에서 수평적으로 확장하거나 혹은 수평적 확장을 위해 인스턴스를 추가하는 것도 매우 간단하다.

오늘날의 데이터 센터에서 제공하는 작업 속도와 유연성은 수작업으로는 불가능한 것이라고 Hashimoto는 말하고 있다. 즉, 자동화는 필수인 것이다. 현대 데이터 센터를 자동화하기위한 요건으로서 그는 다음과 같은 요소를 꼽았다.

  • 제로상태로부터 단 하나의 명령으로 모든 자원의 배치가 가능
  • 분산 시스템에 의한 고장내성
  • 자동 확장 및 자동 복구
  • 체계화 된 지식에 의한 팀워크 향상

Hashimoto는 여러 데이터 센터 나 서로 다른 벤더에 걸쳐저 있는 인프라를 효율적으로 구축, 조합, 출시한다는 요구 사항을 충족 할 수있는 도구로 Hashicorp의 Terraform 을 소개했다. 예를 들어, Amazon Web Service (AWS)의 EC2 컴퓨팅 인스턴스와 DigitalOcean 의 Droplet 컴퓨팅 인스턴스를 구성하고, Dyn DNS 서비스를 통해 그들에게 접근을 설정하는 작업이 Terraform에서 가능하다. 또한 Terraform는 인간 친화적 인 텍스트 형식으로 인프라의 선언으로 정의 할 수있다. 특정한  저수준의 설정 작업을 수행하는 Terraform 모듈을 생성하는 것도 가능하다.



Terraform은 'terraform apply'명령 하나로 시작한다. 'terraform plan'명령으로 apply가 할 활동을 미리 볼 수도 있다. plan 명령을 실행하면 현재의 인프라 상태에서 요구 된 선언적 정의에 대해 실행될 변경 내용이 정렬 된 목록으로 출력된다. 변경이 즉시 실행 가능한 것인가, 파괴적인 성격의 것인가 (서버 재부팅처럼)도 그 안에서 나타나고있다. 어떠한 조작을 수행한다고 가정했을때, 이러한 정보가 메인터넌스 윈도우에 표시됨으로서 적절한 판단을 내리는데 도움을 준다.

plan 명령의 출력을 파일에 저장하여 후이있을 인프라의 변경에 고정적으로 적용시키는것도 가능하다. 인프라의 변화를 미리 볼 수있는 것은 Terraform의 가장 중요한 기능 중 하나 다라고 Hashimoto 는 한다. 인프라 코드의 변경과 그 결과로 인한 프로비저닝 계획의 조합은 개발워크플로(역자주:아마도 Git-Flow와 같은 형태의)에 대해 Pull-Request에 대한 변경사항을 차등으로 검토하고 변경을 수용할 것인지 등에 사용할 수있다.

Terraform 등장 이전에는, 운영팀은 프로덕션 시스템의 스택 관리에 대해 믿을 수 없을 정도로 과중한 책음을 지고 있었다 라고 Hashimoto는 말한다. 서비스중인 여러종류의 클라우드 플랫폼을 깊이 이해 한 후에 인프라 상태를 확인하고 상태 전환 결과를 계산해야했던 것이다. 오래전 많은 개발자가 어셈블리 언어 에서 제 3 세대 프로그래밍 언어 로 전환한 사례와 같이, 운용 담당자와 DevOps기술자들 가운데에는 '스택을 위쪽으로 이동'시키고 Terraform 같은 도구를 이용해 목표를 달성하기를 원하고 있을지도 모른다고 그는 강연에서 말하고 있다.
코어 운영자 및 애플리케이션 운영자의 차이점은 여기에 있다고 나는 생각합니다. 어떤 기업도 고가용성 데이터베이스 클러스터를 구축하는 방법을 이해하는 운영자와 이해하지 못했지만, 고 가용성 데이터베이스 클러스터를 원하는 운영자가있는 것입니다. 그들을 교육하고 이해시키는것은 가능하며, (Terraform처럼) 추상화하여 제공하는것도 가능합니다.
프레젠테이션의 2부에서는 Hashicorp의 Consul 도구가 소개되었다. 서비스 검색 및 구성 오케스트레이션 등의 기능을 데이터 센터에 걸쳐 가용성이 높은 방식으로 제공하는 도구이다. 기업 인프라의 '서비스X는 어디에 있는가', '서비스Y의 상태는 어떤가', '현재 실행중인 것은 무엇인가', '사비스Z의 구성은 어떻게되어 있는지', 또는 '나의 플랫폼에서 작업 A를 실행하는 사람이 있는지'등의 질문에 Consul를 사용하여 대답 할 수있다고 Hashimoto 는 말한다.



Consul은 DNS 또는 HTTP API를 통해 복수의 데이터 센터에서 복합적으로 동작하는 서비스 감지가 가능한 서비스 검색기능을 제공한다. 쉘 스크립트로 구현 된 상태 점검 기능은 자신의 서비스 검증 프로토콜을 구현할 수있다. 또한 고 가용성의 kwy-value 타입의 데이터 저장소도 제공하고 있어, 일관성을 갖춘 정보를 배포 할 수 있는 능력을 갖추고있다. 이것을 이용하면, 구성 관리 도구를 실행할 필요 없이 구성 매개 변수의 '튜닝'을 할 수있다. 조정 가능한 예로는 서비스 위치 지정 및 시스템 유지 보수 모드 공지 및, 서비스의 QoS 파라미터 설정 등이있다.

Cosul의 또 다른 기능으로서 그는 오케스트레이션과 관련된 기능의 제공뿐만 아니라, UDP를 통해 데이터 센터 전체에 비동기로 브로드 캐스트를 하는 'event'와 TCP를 사용하여 특정 컴퓨터에서 동시에 작업을 수행하는 ' exec ', 그리고 event와 exec의 장기적인 폴링 처리를 가능하게 한 'watch '를 언급했다.

Mitchell Hashimoto의 CraftConf 강연 ' Automating the Modern Datacenter, Development to Production '에 대한 영상 등 더 자세한 자료는 컨퍼런스의 Web 사이트에서 확인 가능하다. Terraform v0.5 은 Terraform.io 웹 사이트에서 Consul v5.0은 Consul.io 웹 사이트에서 각각 다운로드 할 수있다.











2015년 12월 14일 월요일

일본경제신문 자체개발 전환사례 소개

 오늘날 모든 기업활동과 사회활동에서 IT는 이미 핵심 영역으로 자리를 잡은지 오래이다. 특히 2010년대에 들어서며 등장한 스마트폰은 IT를 생활과 완전히 한 묶음으로 만들어 버렸다. 그 결과, 과거의 IT가 기업활동이나 공공서비스의 핵심영역을 보조해주는 역할에 불과했다면, 오늘날에는 비즈니스 핵심영역과 결합되거나 아예 핵심영역 그 자체가 되어버린 경우도 쉽게 찾아볼 수 있다.

 특히 TV와 라디오, 신문, 잡지, 출판과 같은 미디어 영역은 스마트폰이나 타블렛과 같은 인터넷과 결합된 스마트 기기가 빠르게 생활속에 자리잡아감에 따라 플랫폼 자체를 변화 시켜야만 하는 선택의 기로에 놓여있다.

 이러한 가운데 주목받고 있는 흐름이 바로 인하우스 개발(=자체개발)로의 회귀이다.
 초창기 기업들의 IT시스템은 자체개발로 시작한 곳이 많았으나 점차 전문 IT서비스 기업들이 등장함에 따라 비 IT기업들은 비용과 전문성, 지속성의 문제로 시스템 개발을 외주에 의존하여 개발하는것이 서서히 일반화 되었다. 하지만 최근들어서 속도와 품질, 그리고 비용이라는 측면에서 IT부서의 규모를 확대하고 개발자를 사원으로 채용하려 하는 움직임이 표면화 되기 시작한 것이다.

 이번 포스팅에서는 일본의 대표적인 경제전문 미디어인 일본경제신문사(이하 닛케이)의 디지털 편성국에서 근무하는 스즈키 요스케씨가 2015년 8월 15일 BPStudy에서 발표한  인하우스 개발 전환 사례를 통해 자체개발로의 전환에 필요한 요소들과 주의해야 할 위험 요소들에 대해 살펴보고자 한다. 포스팅의 내용은 Speaker Deck에 올라온 슬라이드에 기반하고 있으며, 한국내 개발자들이 이해하기 쉽도록 약간의 해설을 가미하였다.

 본격적으로 이야기에 들어가기 앞서 번역을 허락해 주신 닛케이의 스즈키 요스케씨께 감사의 말씀을 전한다.


닛케이전자판의 자체개발화에의 도전

원문: 日経電子版 開発内製化の取り組み


  • 자기소개

    • 스즈키 요스케(鈴木陽介)
    • 일본경제신문사 디지털편성국 소속
    • 2001년 입사
    • NIKKEINET의 컨텐츠 운영, 산업부기자, 인터넷판 컬럼의 편집자등을 거쳐 2009년경 부터 디지털판 기획/개발 담당
    • Python을 중심으로, JavaScript(Coffee), Go등을 일과 개인적인 용도로 사용하고 있습니다. Pebble로도 즐기고 있습니다.

  • 앱 자체개발에 대한 이야기를 공개했었습니다.


  • 일본경제신문(닛케이)에 대해서

    • 1876년 설립, 2016년으로 140주년을 맞이하는 미디어 전문회사
    • 1000명 이상의 기자와 편집자가 근무
    • (역자주) 특히 인터넷과 IT에 관련한 신문,잡지,서적등의 출판을 활발히 펼치는 미디어로서 일본내에서 독보적인 위치에 있음.

  • 닛케이디지털판에 대해서

    • 40만명이 넘는 유료회원
    • 유료 뉴스서비스로서 세계4위
    • 아이폰과 안드로이드에 대응하는 모바일 서비스를 강화
    • 서비스계의 개발부문은 약 40명 정도가 근무

  • 닛케이의 시스템개발 역사

    • 1972년 세계최초의 신문제작 시스템을 개발
    • 1984년 데이터베이스 서비스 '닛케이텔레콘' 개시
    • 1996년 인터넷 서비스인 NIKKEINET개시
    • 2010년 닛케이전자판 창간

  • NIKKEINET시절에는 내부개발이 주로 이뤄졌었습니다

    • 영문기자출신이신분이 비주얼 베이직으로 만든 CMS가 애용되고 있었습니다
    • Perl로 억세스로그의 집계,분석 툴을 개발
    • CloudFusion으로 서비스용 서버어플리케이션 제작
      • PHP와 비슷한 녀석입니다
      • 의외로 성능이 좋았습니다
    • 결국 사람에 의존한 개발 체제였기 때문에 점차 외주개발로 바뀌어가게 됩니다
      • (역자주) 사내의 개발에 열정을 지닌 사람들이 시작한 프로젝트였으나 퇴사나 근무처 이동등에 의해 지속성을 지니기 힘든 구조였을듯 합니다.

  • 닛케이전자판의 개발(창간무렵까지)

    • 초거대SI업체가 대거 참여하여 개발
    • 성능(레스폰스)는 좋았음
    • 변경 비용이 증대
      • 테스트는 기본적으로 수동, 테스트 비용의 증가로 예산이 오버되어 계획이 실현 되지 않았던 경우도 있었음

  • 내부개발화로의 흐름

    • 2010년 당시
    • 자그마한 변경에도 꾀나 번거롭고 시간과 돈이 들어가는 구조
버튼 하나 추가에 2주의 기간과 수십만엔의 비용이 발생하는 비효율적인 구조 
    • 기획을 올려도 아주 작은부분만이 실제 구현되었음 
    • 이대로 괜찮은건가? 라고 초보처럼 생각했다
      (이러저러한 이유가 있었으나 당시엔 알지 못했음)


  • 거의 맘대로 두사람으로 개발을 시작해 보았다

    • 처음에는 PHP+Ruby+MySQL로 사내 서버를 만들었다
      • 2010년 여름경
      • 성능은 그저그랬음
    • PC판의 일부 페이지ㅡ를 구현함
      • 1개월 반정도 소요
      • UI는 바꿔 보았다
    • 결국 이 버전은 창고행으로...

  • 스마트폰 브라우저 버전(베타)의 개발

    • 창고에 넣어 두었던 버전은 존재의미가 그다지 없었다
    • 2011년 당시, 스마트폰 브라우저 버전이 없었던 관계로 그것을 만들어 보기로 함
    • Google App Engin(이하GAE)을 사용해서 인프라를 포함해 단 두명이 만들었음
    • HTML5의 기능을 풍성하게 집어넣은 엣지있는 서비스가 만들어졌다


  • 자체개발한 서비스가 정식으로 서비스됨

    • 2012년에 윈도우8용 앱을 자체 개발
    • 2013년에 인프라, 프론트엔드 모두 새로만든 모바일 브라우저 버전을 공개
      • 프론트엔드의 자바스크립트는 당시 신입사원이 자체 개발했다
      • 지금은 다른 신입사원이 개발중
    • 도급형이 아닌, 외부 개발자가 사내에 상주하며 개발하는 스타일도 늘었다
    • 아직 주류는 아니지만 자체 개발에 대한 분위기가 슬슬 나오기 시작함

  • 좀 더 모던한 개발이 하고싶다!

    • 자체 개발을 좀 더 발전시켜보고 싶었음
    • 2013년 12월경 한 스터디 모임에서 naoya씨(역자주:일본의 유명 개발자로 AB테스트 플랫폼인 Kaizen platform의 개발자로 유명)에게 기술고문을 부탁했더니 OK해 주셨습니다!
    • 이걸로 삐까뻔쩍모던한 개발이 바로 시작될줄 알았으나...

  • 하지만, 기술이 문제가 아니었다!

    • 우선 개발팀의 체제를 변경
      • 눈이 튀어나올것 같은 엑셀 어사인표에 직면
      • 여러 업무에 대한 겸임을 가능한 해소함
    • 자체 개발의 범위를 좁힘
      • 우선은 프론트엔드를 중심으로
    • 개선팀을 만들어 적극적으로 활동
    • 정보를 공유함
    • 회의 아젠다를 시간을 들여 작성함
    • 회의 참석 인원은 최소한으로
    • 맴버들의 자기 주장이 부족함
    • 등등, 나오야씨에게는 기본적인것에서 많이 꾸중을 듣기도 했습니다만
    • 내부의 인원만으로는 타성에 젖기 쉬웠으므로 감사한 마음으로 받아들였습니다

  • 개선팀의 운영에 도전한 결과

    • 정보공유
    • 엔지니어 채용
    • GitHub&Pull Request도입
    • 프로퍼티 자동화
    • 자동 테스트
    • 내부적으로는 문제에 대처해 나가면서, 매번 테마를 정해 naoya씨와 토론을 진행해 나갔습니다

  • 커뮤니케이션 툴의 도입

    • 슬랙
      • 사내외 맴버를 포함해 270명이 넘는 인원이 사용
    • Qiita:Team(역자주: 일본에서 인기있는 개발자대상 정보공유 플랫폼인 Qiita의 기업용 버전. Markdown을 지원하며 코드를 손쉽게 글 안에 포함시킬 수 있는것이 특징임. 아틀라시안의 컨풀루언스와 마찬가지로 KM플랫폼으로 주로 사용되고 있음)
      • 사내외의 100명이 넘는 인원이 참가
      • 회의에서 'Qiita에 적혀져 있습까?'라고 말해지는 경우가 늘어났다
      • 1000개가 넘는 게시물이 등록!
    • 처음에는 좀체로 사용해 주시지 않았습니다만 끈질기게 침투시켰습니다

  • 합숙 워크샵을 개시

    • 3~4개월에 한번씩 합숙워크샵을 개최
    • 로드맵등을 공유
몰입적 사고를 위한 진지한 워크샾을 통해 성공에 대한 이미지를 공유

  • GitHub

    • 자체개발을 진행하고 있는 팀과 프론트엔드 주변 팀의 도입은 거의 완료
    • 모바일앱, 인프라의 Ansible Playbook, Django의 API개발은 Pull Request로 개발
    • 디자이너도 Pull Request를 이용하고 있음

  • CI와 테스트자동화

    • GitHub에 대한 push를CircleCI와 연동
    • 모바일 앱의 유닛&e2e테스트 실시
    • 인프라의serverspec실행

  • 채용 블랜딩

    • 스터디 모임에서 발표한다
      • 지금 이 자료
      • iOS 자체 개발담
    • 스터디 모임의 회장 포스트를 이용
      • Gocon(Go언어 개발자 컨퍼런스)
      • Rebuild Meetup
      • Ansible Meetup
    • 해커톤
      • Cookpad와 공동으로 개최

    • 돌이켜 보니 중요했던 부분들
      • 비전을 내걸고 그곳을 향해 팀을 개혁한다
        • 특히 오래된 조직은 움직임이 느리고 방해가 끼어들기 쉬움
        • 하지만 모두들 효율이 나쁜것을 하고싶다고 생각하지는 않음
        • 열의를 가지고 이상을 향해 노력한다
      • 생각하는 방식은 모두 다를 수 밖에 없다. 반복해서 정보를 발신한다
        • Qiita등을 이용해 이러저러한 내용을 적으면, 제대로 읽고 건설적으로 코맨트를 해 주는 사람도 많았음
        • 모던 기술의 도입도 중요하지만, 그것을 모두를 위해 실시하는것이 중요함 

    • 일단 시작해 본다!

      • 생각만 하고 있으면 앞으로 나갈 수 없다
        • 타사의 사례같은것을 모아도 그것만으로는 진행 할 수 없다
        • 어떻게 하면 가능한가? 가아니라 일단 시작 해 보자
      • 우선은 손을 움직여서 실적을 만들어 내는것도 중요
        • 무언가 만들어 자체개발이 가능한것을 증명했다
        • 두사람만 있어도 의외로 가능하다
        • 코드는 엉망이어도 우선 가능하다는것을 보여준다
          • 사내 체제가 자체개발이 가능하게 되면 그때부터 코드리뷰를 도입한다
      • 오히려 세세한걸 모르는 덕에 가능한것도 있다

    • 왜 자체개발을 하려는지 제대로 설명한다

      • 목적과 수단은 거꾸로되기 쉽다
      • PDCA사이클을 고속으로 반복할 수 있는것이 자체개발의 강점임!
        • 외주작업으로는 이것이 가장 어려움
        • 사양검토->견적->발주작업등등
        • 엔드유저의 의견이 다이렉트로 오는 프론트엔드를 우선적으로 자체개발 대상으로
      • 사내에 노하우가 쌓인다
      • 비용이 줄어든다
        • 쓸데없는 회의가 줄어듦
        • 낮시간에는 회의만 줄창 하다 저녁이 되어서야 작업하는 상황이 사라짐

    • 맨토를 부른다

      • 노하우가 없는 상태에서 자력으로 모든것을 개발하는것은 무리임
        • 하지만, 통채로 외주를 해 버리면 사원에게는 노하우가 쌓이지 않음
      • naoya씨의 '외부인의 의견을 듣는다'에서
        • 외부인의 시각을 통해 무의식적으로 해 왔던 것들에 대해 수정/개선하는것이 가능해짐
      • UI나기술에 대해서도
        • 앱의 UI에 대해서는 fladdict씨
        • 파이선의 개발에 대해서는 hirokiky씨
        • 그외, 과거에 몇번인가 멘토를 불렀었음

    • 어쨋거나 진흙탕은 피할 수 없다!

      • 프론트엔드부터 한다
        • 특히 모바일쪽
      • 새로운것 부터 한다
        • 새로운API군
      • 뜯어 고치는 것 부터 한다
        • 인프라의 AWS 이행시에 Ansible을 도입
      • 운용을 강화
        • 내부개발화에는 역시 우수한 엔지니어가 필요함
        • 엔지니어 대상의 브랜드이미지를 개선한다
      • 상층부와 이미지를 공유

    • 닛케이전자판((닛케이본사)는 엔지니어 채용중!

      • 편안한 마음으로 사내 견학도 OK!
      • dg_lab@nex.nikkei.co.jp 으로 연락 주세요.
      • 학생분들은 hack.nikkei.com으로 인턴 응모도 가능합니다.

    • 닛케이전자판팀의 좋은점은?







    2015년 12월 10일 목요일

    모던 자바의 역습(5) 섹시한 자바 개발자로 거듭나기

    이번 포스팅은 김대우 님(http://lekdw.blogspot.kr/)과 함께 진행한 동명의 웨비너의 발표 내용에 바탕을 두고 작성되었습니다. 세상에 나온지 어느덧 20년. 오랜동안 프로그래밍 언어의 절대 강자로서 세상을 호령하던 자바를 둘러싼 진실 혹은 거짓말 그리고 과거와 미래에 대하여 알아봅니다.



    스크롤의 압박을 피하기 위해 이번 포스팅은 다섯 파트로 나누어 연재합니다.


    모던 자바의 역습 

    5. 섹시한 자바 개발자로 거듭나기


    결론에 이르기 전에 다시 한 번 자바 8의 장점을 정리해봅시다.
    • 함수형 프로그래밍 패러다임 지원 : 손쉬워진 병렬 프로그래밍
    • 더 간결해진 문법(그루비, 스칼라 같은 모던 언어에 더욱 가까운 형태의 코드 구현 가능)
    • 주요 라이브러리와 프레임워크들의 자바 8 지원 완료
    • 잘 정비된 개발 환경
    • 20년간 조성된 거대한 자바 생태계를 그대로 이용 가능

    자바의 단점을 보완하는 전략 - 폴리그랏 프로그래밍

    자바 8에 이르러서는 행사코드가 많이 줄어든 것은 사실이나 아직도 다른 모던 언어에 비해 부족한 것이 사실입니다. 여기에는 하위버전 코드들에 대한 호환성을 유지하기 위해 어쩔 수 없는 부분들도 있습니다. 더 높은 생산성과 함수형 프로그래밍을 원한다면 JVM 언어를 만나보는 것은 어떨까요? JVM 언어는 자바 가상 머신에서 동작하는 언어들로 대표적으로 스칼라,그루비, 클로저, JRuby, JPython 그리고 젯브레인즈가 만든 코틀린(Kotlin)을 들 수 있습니다. 이들 JVM 언어들은 자바와 API 레벨에서 호환성을 지니고 있을 뿐만 아니라 자바와 함께 코드를 작성할 수도 있어 자바와 적절하게 섞어쓴다면 생산성이나 품질 향상에 크게 기여할 수 있습니다.

    더 빠른 성능을 원한다면 C나 C++와 함께 섞어쓰는 방법도 있습니다. 이들 언어는 자바 자체가 원래 C/C++ 언어와 문법적으로 닮은 부분이 많은 만큼 자바 개발자가 익히기 쉽습니다. 포인터나 메모리 관리 등 몇몇 익히기 까다로운 개념이 있기는 하지만 요즘은 개발 환경도 상당히 세련되어졌고 오랜시간 프로그래머들에게 사랑받은 언어인 만큼 풍부한 라이브러리와 레퍼런스를 자랑합니다. 자바 개발자로서 C나 C++ 언어를 익히고 이를 자바와 연결시키는 JNI까지 구현 가능하다면 그야말로 영화 메트릭스에서 메트릭스의 본질을 볼 수 있게 된 네오와도 같이 엄청난 힘을 손에 넣는다고 할 수 있습니다.

    요런 느낌?

    자바 8의 도입, 더 미룰 이유가 없다!

    자바 8의 최초 구현인 OpenJDK 8이 공개된 시점은 2012년 4월이었습니다. 벌써 햇수로 3년이 지났고 오라클에서 자바 8을 발표한 지도 1년이 지났습니다. 대부분의 라이브러리들은 자바 8의 지원을 완료한 상태이며 특히 웹 프레임워크로 인기가 높은 스프링이나 아카 라이브러리 최신 버전은 이미 자바 8의 지원을 마친 상태입니다.

    일단 자바 8을 도입하는 데 있어서 JavaEE 기반의 애플리케이션을 개발하는 경우가 아니라면 더 이상 도입을 미룰 이유는 딱히 찾아보기 어렵습니다. 하지만 호환성 문제 이외에도 자바 8은 문법적으로 이전 자바와는 크게 이질적인 부분이 있어 개발자들의 진입이 그리 쉽지만은 않을 전망입니다.

    특히 문법보다도 함수형 프로그래밍이라는 패러다임은 앞으로 상당 기간 프로그래머를 나누는 한 가지 기준으로 작용할 것으로 보입니다.

    기본적으로는 자바 8을 도입하는 전략도 부록 A.3절에서 설명한 ‘새로운 코딩 스타일에 적응하기’와 크게 다르지 않습니다. 단지 코딩 스타일뿐만이 아니라 제대로 함수형 프로그래밍 패러다임을 이해하고 사용하기 위해서는 사내 워크숍이나 웨비너를 통해 새로운 패러다임을 맞이할 준비를 해야만 합니다.

    자바 개발자에서 모던 자바 개발자로

    일각에서는 자바 8의 함수형 패러다임 도입이 너무 늦어 그 시기를 놓친 것이 아닌가 하는 우려의 목소리도 있습니다. 이미 함수형 프로그래밍이 필요한 분야에서는 자바 8보다는 스칼라나 얼랭(ErLang)과 같은 함수형 언어를 도입했다는 소문도 들려옵니다.

    하지만 멀티프로세싱 시대는 이제 막 시작했을 뿐입니다. 앞으로 더 많은 수의 코어들로 동작하는 기기들이 속속 우리 앞에 모습을 드러낼 것이고 그러한 기기에서 제대로 성능을 뽑아내는 프로그램을 만들기 위해서 함수형 프로그래밍은 선택이 아닌 필수 요소로 자리 잡을 것입니다.

    아직 자바 8에 대해서 유보적인 입장을 취하는 개발자께 이 글이 조금이라도 보탬이 되었으면 하는 바램으로, 모던 자바라는 단어를 처음으로 필자에게 제안한 구글의 소프트웨어 엔지니어 염재현 님의 말을 소개하는 것으로 글을 마치고자 합니다.




    “흔히들 이력서에 자바 엔지니어라고만 적어넣습니다. 버전까지 명기하는 경우는 없지요. 하지만 이제부터는 Java 8 이후의 함수형 프로그래밍과 그 이전의 자바를 구분하여 부를 필요가 있지 않을까요? C++를 C++11 이후 모던 C++라고 부르는 것과 마찬가지로요.”




    모던자바의 역습

    1. 프로그래밍 언어 자바
    2. 자바를 둘러싼 진실 혹은 거짓말
    3. 자바 코딩 스타일 변천사
    4. 모던 자바의 등장 - Java8
    5. 섹시한 자바 개발자로 거듭나기

     

    모던 자바의 역습(4) 모던 자바의 등장 - Java8

    이번 포스팅은 김대우 님(http://lekdw.blogspot.kr/)과 함께 진행한 동명의 웨비너의 발표 내용에 바탕을 두고 작성되었습니다. 세상에 나온지 어느덧 20년. 오랜동안 프로그래밍 언어의 절대 강자로서 세상을 호령하던 자바를 둘러싼 진실 혹은 거짓말 그리고 과거와 미래에 대하여 알아봅니다.



    스크롤의 압박을 피하기 위해 이번 포스팅은 다섯 파트로 나누어 연재합니다.


    모던 자바의 역습 

    4. 모던 자바의 등장 - Java 8


    제네릭과 메타데이터 프로그래밍 패러다임이 도입된 자바 5 이후 거의 10년 만에 함수형 프로그래밍 패러다임을 들고 등장한 자바 8! C와 C++의 관계처럼 완전히 다른 언어는 아니지만 이전 버전과는 분명하게 선이 그어지는 프로그래밍 패러다임을 지닌 자바 8에 대해서 살펴보겠습니다.

    함수형 프로그래밍은 왜 필요한가?

    오랜 세월 대학원 연구실에서나 볼 수 있었던 함수형 프로그래밍 패러다임이 이처럼 주목 받게 된 것은 CPU의 멀티코어화가 일반화됨에 따라 더 간편하게 병렬처리를 구현할 수 있는 프로그래밍 방식이 필요해졌기 때문입니다.

    함수형 프로그래밍 패러다임은 간단히 말해 처리 자체를 데이터와 완전히 분리하는 것으로, 함수를 다른 함수의 인자값으로 넘겨줌으로써 병렬 처리 구현이 매우 손쉽게 이루어 집니다. 이때, 병렬처리를 위해서 값은 스트리밍으로 처리될 필요성이 있으며, 이 스트리밍 처리와 관련된 API야 말로 자바 8의 핵심이라 할 수 있습니다.

     
    아래 예제는 Collection.parallelStram()을 이용해 숫자 배열 중 짝수의 합을 구하는 프로그램 입니다.

    List<Integer> integerList = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
    int sum = integerList
     .parallelStream()
     .filter(i -> i % 2 == 0)
     .mapToInt(i -> i)
     .sum();

    만약 자바 8 이전 버전의 자바로 병렬 처리를 구현하려면 ExecutorService나 Fork/Join 프레임워크를 사용해야만 하는데, 이 경우 적어야 하는 코드양이 최소 네다섯 배는 많아집니다.

    패러럴 스트림을 이용할 경우 이점은 코딩의 편리함 이외에, 속도에 있어서도 이득을 보는 경우가 있습니다. 아래 벤치마크 결과는 8코어 머신으로 세 가지 병렬 처리 모델을 실행 시켰을 때 속도를 측정한 것으로 16스레드로 움직였을 때 전체 테스트 중 가장 좋은 결과를 내고 있습니다.
    ExecutorService vs. Fork/Join Framework vs. Parallel Streams
    출처: http://blog.takipi.com/forkjoin-framework-vs-parallel-streams-vs-executorservice-the-ultimate-benchmark/

    자바 8의 주요 신 기능

    아래 내용은 캘리포니아에 있는 소프트웨어 개발사인 TechEmpower의 블로그에 올라온 ‘Everything about Java 8’의 일부를 발췌하여 정리한 것입니다.


    인터페이스 개선

    인터페이스에 static 메소드를 정의하는 것이 가능해졌습니다. java.util.Comparator에 추가된 static naturalOrder 메소드를 살펴봅시다.
      public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
           return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
       }
    default 지시자를 이용해 기본 메소드의 정의가 가능하게 되어 인터페이스를 구현하는 기존 코드의 변경 없이 새 메소드의 추가가 가능해졌습니다. 예를 들어 java.lang.Iterable에는 forEach 메소드가 default로 정의되어 있습니다.
      public default void forEach(Consumer<? super T> action) {
           Objects.requireNonNull(action);
           for (T t : this) {
               action.accept(t);
           }
       }
    처리해야 할 데이터인 Customer와 처리 내용인 action이 메소드의 인자값으로 전달 가능하게 되어 Iterable Collection에 대한 반복처리를매우 간단히 구현 할 수 있게 되었습니다.

    여기서 한 가지 주의해야 할 점은 예외적으로 Object 클래스의 메소드에 대해서 default 구현은 정의할 수 없다는 점입니다.

    함수형 인터페이스

    함수 인터페이스(functional interface)는 단 하나의 추상 메소드가 정의 가능한 인터페이스입니다. 인터페이스가 함수형 인터페이스임을 나타내는 수단으로서 FunctionalInterface 어노테이션이 도입되었습니다. 예를 들어, java.lang.Runnable은 다음과 같은 함수 인터페이스를 지닙니다.
      @FunctionalInterface
       public interface Runnable {
           public abstract void run();
       }
    하지만, 어노테이션을 통해 명시적으로 지정하지 않더라도 함수 인터페이스의 정의를 만족하는 인터페이스라면 자바 컴파일러가 주석의 유무에 상관없이 함수 인터페이스로서 취급합니다.

    람다식

    함수형 인터페이스의 중요한 특성으로 람다식(lambda expression)을 사용한 인스턴스 생성이 있습니다.

    람다식을 이용하면 동작과 데이터를 모두 동적으로 설정하는 것이 가능합니다. 아래의 예제들은 모두 왼쪽이 입력값이 되고, 오른쪽이 동작에 대한 정의입니다. 입력값의 데이터 타입이  유추 가능하므로 생략되고 있다는 점에 주목해주세요.

      (int x, int y) -> { return x + y; }
      (x, y) -> x + y
      x -> x * x
      () -> x
      x -> { System.out.println(x); }

    예를들어 Runnable 함수 인터페이스를 인스턴스화하는 방법은 다음과 같습니다.
      Runnable r = () -> { System.out.println("Running!"); }

    메소드 참조

    메소드 참조는 이미 이름이 있는 메서드를 대상으로 한 람다식의 간략형이며, 메소드 참조를 나타내는 예약어로서 (::)를 사용합니다. 메소드 참조의 예와 그에 대응하는 람다식은 다음과 같습니다. 오른쪽이 메소드 참조, 왼쪽이 람다식입니다.
       String::valueOf     x -> String.valueOf(x)
       Object::toString    x -> x.toString()
       x::toString         () -> x.toString()
       ArrayList::new      () -> new ArrayList<>()

    캡처 vs 비캡처 람다식

    람다식의 외부에 정의된 static이 아닌 변수나 객체에 억세스하는 것을 람다가 객체를 ‘캡쳐’한다고 부릅니다. 예를 들면 다음은 람다 변수 x에 억세스하는 것입니다.
       int x = 5;
       return y -> x + y;
    람다식으로부터 억세스 가능한 것은 지역변수와 블록구의 파라미터 중에 final이거나 사실상 final 판정(effectively final)을 받은 것에 한정됩니다.

    java.util.function 패키지에는 많은 새로운 함수형 인터페이스가 추가되었습니다. 몇 가지를 예로 들자면 다음과 같습니다.

    • Function <T, R> - T를 입력으로 R을 출력으로 반환
    • Predicate <T> - T를 입력으로 boolean을 출력으로 반환
    • Consumer <T> - T를 입력으로 아무것도 반환하지 않음
    • Supplier <T> - 입력을 취하지 않고 T를 반환
    • BinaryOperator <T> - 2 개의 T를 입력으로 하나의 T를 출력으로 반환

    java.util.stream

    자바 8의 중요한 패러다임의 하나로 새로운 java.util.stream 패키지는 스트림에 대한 함수형 조작을 제공합니다. 즉 배열이나 리스트, 맵으로 대표되는 컬랙션을 스트림으로 다룰 수 있게 되었다는 것입니다. 다음은 컬랙션에 대한 스트림화의 예입니다.
       Stream <T> stream = collection.stream ();
    이것이 함수형 프로그래밍과 결합하면 다음과 같은 형태가 된다.
       int sumOfWeights = blocks.stream () filter (b -> b.getColor () == RED)
                                         . mapToInt (b -> b.getWeight ())
                                         . sum ();
    위의 샘플코드는 stream 패키지의 Javadoc에 실린 예로서, stream의 소스로서 blocks라는 Collection을 사용하고 있습니다. 그 스트림에 대해 filter-map-reduce를 실행하여 붉은색(RED) 블록에 대한 무게(weight)의 합(sum)을 구하는 일련의 과정이 한 줄의 코드에 집약되어 표현되고 있습니다.

    제네릭 타입 인터페이스 개선

    이 개선은 자바 컴파일러가 형에 대한 추론 능력을 갖추는 것으로 제네릭 형식 메소드 호출 시 인수에 대한 형 정의를 생략할 수 있게 해줍니다. 예를 들어 자바 7의 코드가 다음과 같았다면
       foo(Utility.<Type>bar());
       Utility.<Type>foo().bar();
    자바 8에서는 인수와 호출에 대한 추론이 자동적으로 이루어져 다음과 같이 형태가 됩니다.
       foo(Utility.bar());
       Utility.foo().bar();

    java.time

    새로운 날짜/시간 관련 API가 java.time 패키지에 추가되고 있습니다. 클래스는 immutable이며 스레드에 대해 안전합니다. 날짜 및 시간 형식으로  Instant, LocalDate, LocalDateTime, ZonedDateTime이 추가되었으며 날짜와 시간 이외의 것으로서 Duration과 Period가 추가되었습니다. 새로 추가된 값 형식은 Month, DayOfWeek, Year, Month YearMonth, MonthDay, OffsetTime, OffsetDateTime 등이 있습니다. 이런한 새로운 날짜/시간 클래스는 대부분이 JDBC에서 지원됨으로써 RDB 연동의 효율적인 구현이 가능합니다.

    Collections API 확장

    인터페이스가 default 메소드를 가질 수 있게 됨으로써 자바 8의 Collection API에는 다수의 메소드가 새롭게 추가되었습니다. 인터페이스는 모두 default 메소드가 구현되었으며 새로이 추가된 메소드의 일람은 다음과 같습니다.
    • Iterable.forEach(Consumer)
    • Iterator.forEachRemaining(Consumer)
    • Collection.removeIf(Predicate)
    • Collection.spliterator()
    • Collection.stream()
    • Collection.parallelStream()
    • List.sort(Comparator)
    • List.replaceAll(UnaryOperator)
    • Map.forEach(BiConsumer)
    • Map.replaceAll(BiFunction)
    • Map.putIfAbsent(K, V)
    • Map.remove(Object, Object)
    • Map.replace(K, V, V)
    • Map.replace(K, V)
    • Map.computeIfAbsent(K, Function)
    • Map.computeIfPresent(K, BiFunction)
    • Map.compute(K, BiFunction)
    • Map.merge(K, V, BiFunction)
    • Map.getOrDefault(Object, V)

    Concurrency API의 확장

    Concurrency API의 기능이 추가되었습니다. 몇 가지를 소개해보자면, ForkJoinPool.commonPool()은 모든 병렬 스트림 작업을 처리하는 구조입니다. ForkJoinTak는 명시적으로 특정 풀을 가지지 않고, 일반적인 풀을 사용하게 되었습니다. 말도 많고 탈도 많았던 ConcurrentHashMap은 완전히 재작성되었습니다. 또한 새로운 Locking 처리의 구현으로써 추가된 StampedLock은 ReentrantReadWriteLock의 대안으로 사용할 수 있습니다.
    Future 인터페이스의 구현인 CompletableFuture에서는 비동기 작업의 실행과 체이닝을 위한 방법이 제공됩니다.

    IO/NIO API의 확장

    IO/NIO에 메소드가 추가되어 파일이나 입력 스트림에서 java.util.stream.Stream을 직접 생성할 수 있게 되었습니다.
    • BufferedReader.lines ()
    • Files.list (Path)
    • Files.walk (Path, int FileVisitOption ...)
    • Files.walk (Path, FileVisitOption ...)
    • Files.find (Path, int BiPredicate, FileVisitOption ...)
    • Files.lines (Path, Charset)
    • DirectoryStream.stream ()
    새로운 클래스의 UncheckedIOException은 RuntimeException을 확장한 IOException입니다.
    클로징 가능한 CloseableStream이 추가된 것 또한 눈여겨볼 만합니다.

    리플렉션과 어노테이션의 변경

    어노테이션이 더 많은 곳에서 사용될 수 있게 되었습니다. 예를 들면 List<@Nullable String>과 같이 제네릭 형식 매개변수에 작성할 수도 있습니다. 따라서 정적 분석 도구에서 감지 가능한 오류의 범위가 확대되어 자바의 내장 자료형(built-in type) 시스템 또한 강화되고 정교해졌습니다.

    Nashorn 자바스크립트 엔진

    독일어로 코뿔소라는 뜻을 지닌 나스혼(Nashorn)은 새로 JDK에 통합된 경량 고성능 자바스크립트 구현 엔진입니다. 자바 7에 포함되었던 리노(Rhino)의 후속이며, 성능과 메모리 관리가 비약적으로 개선되었습니다. javax.script API를 지원하고 있지만, DOM/CSS와 브라우저 플러그인 API는 포함되어 있지 않습니다.

    아래 그래프는 자바 6부터 탑재된 자바스크립트 엔진과 구글의 V8 엔진의 성능에 대한 벤치마크 결과입니다.





    모던자바의 역습

    1. 프로그래밍 언어 자바
    2. 자바를 둘러싼 진실 혹은 거짓말
    3. 자바 코딩 스타일 변천사
    4. 모던 자바의 등장 - Java8
    5. 섹시한 자바 개발자로 거듭나기