스토리 홈

인터뷰

피드

뉴스

조회수 2512

Next.js 튜토리얼 5편: 라우트 마스킹

* 이 글은 Next.js의 공식 튜토리얼을 번역한 글입니다.** 오역 및 오탈자가 있을 수 있습니다. 발견하시면 제보해주세요!목차1편: 시작하기 2편: 페이지 이동 3편: 공유 컴포넌트4편: 동적 페이지5편: 라우트 마스킹 - 현재 글6편: 서버 사이드7편: 데이터 가져오기8편: 컴포넌트 스타일링9편: 배포하기개요이전 편에서는 쿼리 문자열을 이용하여 동적 페이지를 생성하는 법을 배웠습니다. 생성한 블로그 게시물 중 하나에 대한 링크는 다음과 같습니다:http://localhost:3000/post?title=Hello Next.js하지만 이 URL은 구립니다.다음과 같은 URL를 가지면 어떨까요? http://localhost:3000/p/hello-nextjs더 낫지 않나요?이번 편에서 이것을 구현할 예정입니다.설치이번 장에서는 간단한 Next.js 애플리케이션이 필요합니다. 다음의 샘플 애플리케이션을 다운받아주세요:아래의 명령어로 실행시킬 수 있습니다:이제 http://localhost:3000로 이동하여 애플리케이션에 접근할 수 있습니다.라우트 마스킹라우트 마스킹이라 불리는 Next.js의 특별한 기능을 사용할 예정입니다.기본적으로 애플리케이션에서 표시되는 실제 URL와 다른 URL이 브라우저에 표시됩니다.블로그 포스트 URL에 라우트 마스크를 추가해봅시다.pages/index.js에 다음과 같은 코드를 작성해주세요:다음의 코드 블럭을 살펴봅시다:<Link> 엘리먼트에서 "as"라는 또다른 prop를 사용하였습니다. 이는 브라우저에서 보여질 URL입니다. 애플리케이션에 표시되는 URL은 "href" prop에 지정되어 있습니다.첫 번째 블로그 포스트를 클릭하면 블로그 포스트로 이동할 것입니다.그 다음에 뒤로가기 버튼을 클릭하고 앞으로가기 버튼을 클릭해보세요. 무슨 일이 일어날까요?- 에러가 발생할 것이다- 인덱스 페이지로 돌아가고 포스트 페이지로 다시 이동할 것이다- 인덱스 페이지로 이동하지만 그 후에는 아무런 일도 일어나지 않을 것이다- 인덱스 페이지로 돌아가고 에러가 발생할 것이다히스토리 인식본 것처럼 라우트 마스킹은 브라우저 히스토리를 활용하여 잘 작동합니다. 해야 할 일은 링크에 "as" prop를 추가하는 것뿐입니다.새로고침하기home 페이지로 돌아가세요: http://localhost:3000/첫 번째 포스트 제목을 클릭하면 post 페이지로 이동합니다.브라우저를 새로고침하면 무슨 일이 일어날까요?- 예상대로 페이지가 첫 번째 포스트를 랜더링 할것이다- 페이지가 로드되지 않고 계속 로딩 중일 것이다- 500 에러가 발생할 것이다- 404 에러가 발생할 것이다 404서버에 불러올 페이지가 없기 때문에 404가 에러가 발생합니다. 서버는 p/hello-nextjs 페이지를 불러오려고 시도하지만 우리는 index.js와 post.js 두 개의 페이지밖에 없습니다.이 방법으로는 프로덕션으로 이 애플리케이션을 실행할 수 없습니다. 이 문제를 고쳐야 합니다.Next.js의 커스텀 서버 API는 이 문제를 해결할 수 있는 방법입니다.다음 편에서 이것을 사용하는 방법을 배울 예정입니다.#트레바리 #개발자 #안드로이드 #앱개발 #Next.js #백엔드 #인사이트 #경험공유
조회수 1547

개발자 직군 파헤치기 3 | 블록체인 개발자

이번 포스팅은 블록체인 개발자!2017년 대한민국은 가상화폐의 광풍에 휩싸이게 된다. 남녀노소 가릴 것 없이 많은 사람들이 가상화폐에 투자를 했다. 전 세계에 유례가 없을 정도로 국내 가상화폐 투자 열기는 뜨거웠으며 해외의 가상화폐 투자자들은 국내 투자자들의 움직임에 예의주시하면서 투자할 정도였다.이와 동시에 가상화폐의 기술적 원천이 된 블록체인(Block Chain) 기술에 대한 관심도 증가했다. 제2의 인터넷이 될 거라는 찬사를 받으면서 가상화폐의 부상은 뜨거운 관심의 대상이었다. 정부의 가상화폐 규제가 있었지만 시장에서는 블록체인 기술의 잠재적 가능성에 주목을 하면서 이것을 가지고 어떻게 혁신적인 서비스를 제공할지 고심하고 있다. 이에 따라 일반 개발자는 물론이고 기업에서도 블록체인 개발자에 대한 수요와 관심이 늘고 있다.이러한 관심 때문에 개발자를 꿈꾸는 많은 분들이 블록체인 개발자는 무엇을 하고 어떻게 될 수 있는 것인지 궁금해하고 있다. 그래서 이번 포스팅에서는 블록체인 개발자가 되기 위해서는 어떻게 해야 하는지와 더불어, 블록체인 기술에 대한 전망 그리고 블록체인 개발자의 시장 수요에 대한 글을 써 볼 것이다.*이 글은 블록체인 기술에 대한 자세한 설명은 하지 않고 있습니다.*Photo by Andre Francois on Unsplash미래를 여는 신기술, 블록체인의 전망블록체인 기술이 뜨고 있다고 하지만 도대체 어떤 분야에서 적용될 수 있기에 이렇게 많은 관심을 받고 있는 것일까? '딱 이 분야가 유망합니다'라고 말하기가 어려울 정도로 블록체인은 폭넓은 분야에 걸쳐서 파괴적인 혁신성을 가지고 있다. 그중  몇 가지만 추려서 이야기하고자 한다.1. 금융, 은행블록체인의 기술의 특징은 탈 중앙화, 신뢰성, 보안성이다. 전문가들은 기존의 은행들이 하던 업무를 핀테크 기업들이 혁신적인 서비스와 가격으로 대체할 것으로 예상한다. 블록체인 기술이 가지고 있는 신뢰성과 보안성으로 인해 일반 기업들도 거대 은행이 보유하고 있는 보안성을 획득할 수 있는 것이다. 거래 과정에서 제3자를 거치지 않기 때문에 거래의 속도와 효율성 그리고 경제성이 크게 증가한다.핀테크 스타트업뿐만 아니라 거대 금융권의 은행들이나 기존의 대기업들도 블록체인 기술을 이용한 서비스를 발 빠르게 준비하고 있다. 마스터카드는 블록체인 기술을 통해 즉석 지불 시스템을 개발하고 있다. 또한 글로벌 기업 IBM은 서로 다른 국가에 위치한 금융 기관이 블록체인 기술을 이용해서 결제를 처리할 수 있도록 하는 뱅킹 솔루션을 개발했다.현재 이더리움이 선도하는 스마트 계약도 금융권에서 주목하는 분야다. 스마트 계약은 특정 조건이 충족되면 은행과 같은 제3자를 거치지 않고 계약을 이행하게끔 도와준다. 예를 들어, 납품 기업과 발주 기업이 스마트 계약을 맺었다. 납품 기업이 발주 기업의 창고에 물품을 보내고 물품이 도착을 하면(IOT 센서로 감지된다) 납품 기업은 자동으로 결제 대금을 자동으로 받게 된다.2. 물류위에서 블록체인 기술의 특징 중 신뢰성과 보안성을 언급했다. 정보의 신뢰성과 보안성은 물류 시스템에도 파급력을 미칠 것이다. 많은 전문가들이 블록체인으로 인해 물류 시스템에 혁신적인 변화가 가능하다고 말한다. 블록체인 기술이 어떻게 물류 시스템에 적용될 수 있는지 직접 예시로 살펴보자.영국의 소프트웨어 회사 프로비넌스는 블록체인 기술을 이용해서 소매업자와 식당들이 원래 계약했던 대로 재료가 들어오는지 확인할 수 있게 만들었다. 트래킹(tracking) 기술과 결합하여 만든 이 소프트웨어는 재료가 수확되는 과정부터 최종 소비자가 구매하는 단계까지 꼼꼼히 추적하고 관리한다. 공급망의 모든 단계에서 변경 불가능한 데이터가 블록에 추가된다. 이 소프트웨어를 통해 소비자들은 자신이 무엇을 먹는지, 기업이 불법 조업을 통해 재료를 조달한 것이 아닌지, 이 농작물에 대한 적절한 보상이 농부에게 돌아갔는지, 이 식재료가 유기농이 맞는지 명확하게 확인할 수 있다.한편, 중국의 월마트와 IBM이 협력해 중국에서 유통되는 돼지고기의 유통 전 과정을 블록체인 기술을 활용해 추적을 하기도 했다. 월마트는 더 나아가 농산물 공급망의 모든 단계를 추적하기 위한 프로젝트를 IBM과 진행하고 있다. 또한 영국의 신생기업 에버레저는 블록체인 기술을 이용해 다이아몬드와 같은 고부가 가치 상품들의 원산지 추적과 인증을 IBM 블록체인 기술을 활용하고 있다.3. 디지털 콘텐츠블록체인 기술로 디지털 콘텐츠에 대한 지적 재산권 보호를 더 확실하게 할 수 있다. 기존에는 불법적인 경로로 승인되지 않은 디지털 콘텐츠들이 유포가 됐다. 하지만 블록체인 기술로 온라인 콘텐츠에 대한 저작권, 권한, 결제를 관리할 수 있도록 작업할 수 있다. 블록체인 기술을 통해 콘텐츠 원저자의 증명을 더 쉽게 하고 해당 콘텐츠에 누가 접근을 했는지 추적할 수 있다.또한 항상 이슈가 되어 왔던 뮤지션들의 음반 판매 금액에 대해서도 블록체인 기술이 혁신을 가져다줄 것이다. 기존의 중간 단계의 서비스를 없애고 비용을 절감해서 음반 제작자들에게 더 많은 몫이 돌아갈 수 있다. 위에서 언급한 스마트 계약을 통해 라이선스 이슈의 문제들도 해결할 수 있다.블록체인 개발자, 얼마나 핫해?블록체인 기술에 대한 뜨거운 관심에 힘입어 블록체인 개발자에 대한 수요도 크게 증가하고 있다. 아직은 국내에서 가상화폐에 대한 비즈니스가 주를 이루고 있지만 정부의 정책과 시장의 기대와 맞물려 그 수요는 더욱더 커질 예정이다. 여기 블록체인 개발자의 수요에 대한 기사 있다.기사에 따르면 지난 1분기 취업사이트 잡코리아에 블록체인 키워드로 등록된 채용공고는 총 1500여 건이다. 이는 전년 동기 대비 9배 이상 늘어난 수치라고 한다. 또 잡코리아가 분석한 결과 지난해 하반기부터 암호화폐 개발자 수요가 급증했다고 한다. 지난해 1분기와 비교하면 올해 1분기 등록건수는 9배 이상이며 직전 분기와 비교해도 3배에 달한다.다른 아웃소싱 플랫폼 사이트도 비슷하다. 4만 7천 명의 유저를 보유한 위시캣에 따르면 2014년 8월부터 지난달까지 등록된 암호화폐 관련 프로젝트는 108건이다. 그리고 이 중에 절반인 55번이 올해 1분기에 등록이 되었다고 한다. 개발자 커뮤니티 OKKY에 올라온 구인 글에는 월 급여 900만 원을 제시하고 암호화폐 개발하는 개발자를 찾고 있었다. 또 구인 사이트에 올라온 암호화폐 거래소 프로젝트 중 개발비용이 45일 동안 2억 5천만 원에 이른 사례도 있었다.기사에 나온 것처럼 블록체인 개발자의 수요는 암호화폐에 집중되어 있기는 하지만 빠르게 증가하고 있다. 또 많은 기업들이 암호화폐가 아닌 다른 비즈니스의 모델을 찾으면서 블록체인 서비스를 준비하고 있다. 블록체인 개발자는 말 그대로 요즘 가장 핫하다고 할 수 있다.그래서 블록체인 개발자 되기 위해서는?이렇게 핫한 블록체인 개발자가 되기 위해서는 어떤 기술들을 공부해야 할까? 물론 어떤 분야의 개발자가 된다는 것이 특정 기술을 익힌다고 되는 것은 아니다. 웹 개발자가 된다고 해서 자바스크립트와 HTML, CSS를 익힌다고 되는 것이 아닌 것처럼 말이다. 회사마다 진행하는 프로젝트가 있고 그것에 맞춘 기술 스택들을 익혀야 한다. 하지만, 그럼에도 블록체인 개발에 있어서 주류가 되는 기술들은 있다. 이것들을 공부해 가면서 블록체인 개발자를 준비한다면 한층 더 수월해질 것이다.1.솔리디티(Solidity)솔리디티는 블록체인 플랫폼에서 스마트 계약을 만들기 위한 프로그래밍 언어다. 이더리움의 핵심인 스마트 계약을 만들기 위해서는 솔리디티를 배워야 한다. 솔리디티는 EVM(Ethereum Virtual Machine)에서 돌아가도록 설계되었고, 자바스크립트와 비슷한 문법 구조를 갖고 있다. 자바스크립트를 알고 있다면 배우기가 훨씬 수월할 것이다.블록체인은 다양한 분야가 존재하지만 그중 스마트 계약은 가장 대표적인 혁신 기술이다. 그 스마트 계약 기술을 선도하는 이더리움 프로젝트를 다루기 위해서는 솔리디티를 배우는 것이 필수적이다. 블록체인 개발에도 다양한 기술 스택들이 있겠지만 주류 기술을 배운다고 하면 솔리디티를 배워야 한다.솔리디티를 배우기 위해서는 다양한 방법이 있겠지만, 유데미의 강좌를 들으면서 공부하는 것을 추천한다. 저렴한 가격에 퀄리티 높은 강좌를 들을 수 있다. 자세한 사항은 이곳을 참고하면 된다.2.하이퍼레저(Hyperledger)블록체인이 개념이 퍼블릭 네트워크 기반의 시스템이기는 하지만 누구나 데이터를 볼 수 있기 때문에 기밀문서 관리에는 사용되기 힘들다. 특히 금융권이나 기업 문서 같은 경우는 더더욱 그러하다. 그래서 폐쇄적인 프라이빗 네트워크 내에서 블록체인을 활용할 수 있는 기술이 필요하다.하이퍼레저는 이러한 프라이빗 블록체인을 필요로 하는 기업들의 연합체라고 볼 수 있다. 이 기업들은 컨소시엄을 맺고 프라이빗 블록체인을 더 발전시키려고 다양한 분야에서 협업하고 있다. 하이퍼레저 프로젝트는 리눅스 재단에서 주도하며 금융, 은행, 제조, 기술 등 다양한 분야에 관여한다. 그리고 이 프로젝트는 스마트 계약, 분산 합의 네트워크에 목표를 두고 있다.지금까지 에어버스, 엑센츄어, 바이두, IBM, J.P 모건, 히타치, 삼성 SDS 등 다양한 기업이 하이퍼레저에 포함되어 있다. 그만큼 많은 기업들이 하이퍼레저 프로젝트에 관심을 가지고 있다. 하이퍼레저 역시 유데미의 강좌를 통해서 배울 수 있다. 자세한 사항은 이곳을 참고하면 된다.블록체인 개발자의 첫걸음블록체인 개발자가 되기 위해서는 위의 기술 스택뿐만 아니라 기본적으로 백엔드에 대한 지식과 최소한 암호 기법에 대한 기본 지식이 있어야 한다. 또한, 블록체인의 많은 API 및 SDK가 자바스크립트와 nod.js로 이루어져 있다. 무엇부터 시작해야 할지 모르는 분이라면 자바스크립트부터 시작하면서 첫걸음을 떼는 것을 추천한다.블록체인은 IT 기술의 최전선에 있는 기술이다. 그렇기 때문에 산업 동향을 항상 예의주시하면서 빠르게 움직여야 한다. 기업이 원하는 블록체인 기술 스택을 빠르게 습득하고 그에 맞는 실력을 갖추는 것이 중요하다.지금까지 블록체인 개발자에 대해 알아보았다. 많은 내용들을 다루다 보니 각각에 내용들에 깊이 있게 다루지는 못했다. 그래도 이 글을 통해 블록체인 개발자가 되기 위한 가닥은 잡을 수 있었으면 좋겠다.
조회수 1732

덕질도 신박하게! R을 활용한 텍스트 마이닝 도전기

Overview대학원에서 소프트웨어 공학을 전공하고 있습니다. 이번 학기엔 ‘빅데이터 분석’ 과 ‘대용량데이터베이스관리론’ 과목을 수강하면서 생애 처음으로 R Studio 프로그램을 설치해봤는데요. 머신 러닝을 다뤄본 적도, 자연언어처리 분야를 개발한 적도 없지만 어느 날 텍스트 마이닝 관련 강의에서 불현듯 이런 생각이 떠올랐습니다. “내가 좋아하는 가수로 텍스트 마이닝을 하면 어떤 결과가 나올까?”머릿속으로 생각하는 것과 내가 직접 구현을 해보는 것은 절대 다른 법! 일단 도전해보기로 했습니다. 개발 3년과 덕질 10년의 실력을 쏟아 부을 겁니다.지금까지 예쁜 디자인이라고만 알고 있었던 WordCloudStep1. 트위터 Developer 에서 인증키 받기트위터 Developer (Twitter Developer Platform — Twitter Developers) 에 접속해서 개인 계정으로 로그인하고, 오른쪽 위의 Apply를 클릭합니다.Twitter standard APIs > Get started with standard access를 클릭합니다.등록된 개발자 앱이 없으면 Create an app의 apps.twitter.com을 클릭합니다.Create New App을 클릭합니다.각 항목을 입력합니다. 저는 Website 가 없기 때문에 로컬 호스트를 기재했습니다.약관에 동의한 후 Create your Twitter application을 클릭합니다.만약 어플리케이션 이름이 중복된다면 위와 같은 에러 메세지가 나올 겁니다. 정상적으로 어플리케이션이 등록되면 위의 화면과 함께 API Key를 발급받을 수 있습니다. Consumer Key (API Key) 옆의 내용 (캡쳐화면에는 비공개)을 클릭하면 API Key 뿐만 아니라 API Secret, Access Token 등 세부 내용을 관리할 수도 있습니다.Step2. R Studio 설치하기 (Mac OS 기준)구글에서 R for macOS를 검색을 하면 맨 위에 설치 페이지가 보입니다. 1)먼저 R 패키지를 설치해야, 나중에 R Studio를 설치했을 때 실행이 가능합니다.R Studio 홈페이지에서 R Studio를 다운받습니다. 다운로드 링크는 여기를 클릭하세요.RStudio가 정상적으로 실행이 된다면, 이제 준비는 끝났습니다! Step 3. 필요한 패키지를 먼저 설치하기따로 설치가 필요한 패키지는 RStudio에서 명령어로 설치할 수 있습니다.—한 개씩 설치하는 법install.packages(“packageName”)—여러 개의 패키지를 한 번에 설치하고 싶을 땐 위와 같이 설치할 수 있습니다.—여러 개를 한꺼번에 설치하는 법install.packages(c(“package1”, “package2”,”package3”))—설치를 했다고 해서 바로 사용할 수는 없습니다. 이 패키지를 사용하겠다는 명령어를 다시 입력해야 합니다.—설치한 패키지를 사용하기library(“packageName”)—이번 글에서는 아래와 같은 패키지들이 필요합니다.twitteRROAuthbase64enchttpuvtmSnowballCwordcloudRColorBrewerStep 4. 트위터 api와 연동하여 WordCloud 생성하기먼저 각자 API 관련 Key 들로 객체를 생성해주고, setup_twitter_oauth() 메소드를 사용하여 Twitter API에 접근합니다.searchTwitter 4) 라는 함수를 사용하면, 트위터 API 를 통해 관련 트윗 내용을 추출할 수 있는데요. 좋아하는 일본 아이돌 가수인 “아라시”를 키워드로 추출하려고 첫 번째 파라미터에 “Arashi”를 넣었습니다. 그 뒤의 내용은 영문으로 작성된 최근(Recent) 트윗을 최대 1500개까지 리턴 받겠다는 의미입니다. resultType에는 popular를 넣으면 가장 인기있는 트윗을 받을 수도 있습니다.데이터를 가져오면, 위와 같이 데이터가 추출된 것을 확인할 수 있습니다.이제 matchTweets에 있는 내용으로 분석가가 되어 마음대로 데이터를 가공할 수 있습니다. class 등으로 구조와 클래스를 확인할 수 있을 뿐만 아니라, nchar() 를 이용해 트윗당 문자 수를 계산할 수도 있습니다. 이번 글에서는 위와 같이 트윗을 20개 추출했습니다.각각의 트윗을 보면, 이상한 코드나 슬래시 등 필요 없는 데이터들이 포함되어 내려온 것을 확인할 수 있습니다. 이 부분들을 제거해 깔끔한 데이터로 가공해보겠습니다. 그리고 텍스트 집합이라고 볼 수 있는 Corpus를 생성한 후, WordCloud 까지 생성해볼게요.데이터를 Corpus 로 만들 때는 Corpus() 를 사용하면 됩니다. 저는 VectorSource 라는 명령어를 사용해 단어들을 Vector로 바꿔주었고, 데이터가 잘 들어갔는지 확인하기 위해 inspect() 를 사용했습니다.사람이 읽기 불편한 단어들을 제거하는 건 tm_map 함수 하나면 충분합니다.위의 이미지를 보면, 각 행마다 특정 특수문자들을 제거하기 위한 명령어가 있습니다. 중간 부분엔 stopwords 라는 단어가 있는데, 영어 문장에 들어가는 i.e 나 etc 같은 표현들을 제거할 수 있는 겁니다. 그 외에도 대문자를 소문자로 바꾸거나 번호를 제거하는 등의 옵션들이 이미 R에서는 제공되고 있기 때문에, 우리는 입맛에 맞게 가져다 쓰기만 하면 됩니다.이제 대망의 WordCloud를 만들 차례입니다.max.words는 최대 N개의 단어를 고르는 옵션이며, min.freq는 최소 N번 이상 나온 단어, random.order = FALSE는 제일 많이 나온 단어가 먼저 나오도록 지정하는 옵션입니다. colors는 지정하지 않으면 검정색으로만 나오지만, 알록달록 예쁘게 표현하고 싶다면 여러 옵션을 지정해서 Frequency 에 따라 다른 색이 나오도록 할 수도 있습니다. 5) 첫 번째 이미지가 이번 글의 예제로 얻은 결과인데요. 추출 언어를 영어로만 한정했더니 일본어 발음을 영문으로 표현한 데이터가 많았습니다. 기타 설정을 변경하여 다시 추출한 게 바로 두 번째 이미지입니다. 큼직큼직하게 나온 단어들을 보면 DVD 나 블루레이 출시와 관련된 트윗이 대다수인 것을 볼 수 있는데요, 검색 결과 최근 2017-2018 라이브 투어 ‘Untitled’가 출시된 것을 확인할 수 있었습니다. 기타 작게 표현된 단어들을 보면 아라시의 노래 제목들도 확인 가능한데, 이 노래들이 인기있다는 것도 예측할 수 있습니다.Conclusion지금까지 R을 이용해 트위터 API 와 연동한 텍스트 마이닝을 했습니다. 데이터를 WordCloud로 생성하는 것도 해봤고요. 이번 글에서는 기본적인 예제를 다뤘지만 텍스트 마이닝의 세계는 아주 깊고 넓습니다. 만약 이 글로 텍스트 마이닝에 조금이라도 흥미가 생겼다면 일단 도전해보세요! 좋아하는 것과 연관 지어서 따라 하다 보면 꽤 즐거운 시간이 될 겁니다.참고1) 18년 6월 6일 기준이다.2) Twitter Sentiment Analysis Tutorial3) Text mining: Twitter extraction and stepwise guide to generate a word cloud4) R 함수 관련 설명은 R Documentation 사이트에서 확인할 수 있다. 5) 색상 옵션이 궁금하다면 여기에서 참고할 수 있다. 6) 머신러닝 언어처리 - R로 WordCloud 만들어보기 - 데이터 사이언스 랩글김우경 대리 | R&D 개발1팀kimwk@brandi.co.kr브랜디, 오직 예쁜 옷만#브랜디 #개발자 #개발팀 #인사이트 #경험공유 #R #텍스트마이닝
조회수 582

프로그래밍 교육에서 동료 평가(Peer Assessment)란 무엇일까요?

전 세계적으로 프로그래밍 교육 열풍이 불고 있습니다. 몇 년 전부터 시작된 이 열풍을 타고 프로그래밍을 가르치는 공개 온라인 강좌(MOOC; Massive Open Online Course)가 우후죽순으로 생겨났습니다. 이들 수업은 시간과 장소에 구애받지 않고 어디에서나 누구나 자유롭게 수업을 들을 수 있는 MOOC의 특성을 십분 활용하여 수천 수만 명의 학생을 효과적으로 모집하고, 프로그래밍의 기초부터 전문가가 되기 위한 직업 교육의 영역까지 다양한 교육을 진행하고 있습니다.그러나 비디오 강의와 프로그래밍 숙제를 위주로만 이루어지는 온라인 프로그래밍 강의들은 아직까지 소규모 오프라인 강의들이 제공하는 수준의 효과적인 학습 효과를 제공하는 데에는 어려움을 겪고 있습니다. 이러한 학습 효과의 열화가 일어나는 원인에 대해서는 수많은 연구자가 각기 다른 이론과 실험을 근거로 들고 있지만, 그중에서도 많은 사전 연구와 실험을 통해 밝혀진 원인 중 하나는 “학생과 강사 사이의 소통”이 기존에 교육 환경에 비해 부족하다는 점입니다.비디오로 이루어진 강의에서 어떻게 강의를 전달하는 것이 효과적일지에 대한 연구가 진행되었습니다. 논문: How Video Production Affects Student Engagement: An Empirical Study of MOOC Videos몇 가지 예시를 들어보자면, 기존의 소규모 오프라인 교육 환경에서는 학생이 궁금한 점이 있을 때 강사에게 즉석에서 질문하고 답변을 받을 수 있지만, 이미 녹화된 동영상을 보며 학습하는 온라인 비디오 강의에서는 이러한 간단한 소통마저 아직 완벽하게 이루어지지 못하고 있고, 이러한 한계점은 연구자들에게 새로운 연구의 대상이 되고 있습니다.Elice에서는 학생이 문제를 풀다 질문이 생기면 조교와 1:1로 대화를 할 수 있습니다.비슷하지만 다른 예시로, 수업 시간 이외의 시간에 일어날 수 있는 소통의 예를 들어보자면, 숙제의 채점과 피드백을 예로 들어볼 수 있습니다. 소규모 강의에서는 몇몇 조교가 학생들이 제출한 프로그래밍 숙제를 하나하나 검사하고, 채점한 뒤 개개인에게 필요한 피드백을 주는데에 큰 문제가 없습니다. 그러나 많아야 수십 명의 조교가 많게는 수만 명의 학생이 제출한 과제를 채점해야 하는 MOOC 환경이라면 이야기가 달라집니다.MOOC 환경에서 과제의 효과적인 채점에 대한 연구는 아직도 활발하게 연구되고 있는 매우 흥미로운 주제입니다. 서론이 조금 길었던 것 같기도 하지만, 이번 글에서는 온라인 프로그래밍 강의가 좀 더 효과적으로 되기 위해 넘어야 할 허들 중 하나인 “수많은 학생이 제출한 과제를 어떻게 하면 효과적으로 채점하고 피드백을 줄 수 있을까?”라는 문제에 대해 elice 팀에서 연구한 내용을 여러분들과 공유해보고자 합니다.동료 평가 (Peer Assessment)MOOC 환경에서 몇 명의 조교만으로 제출된 수만 개의 과제를 채점하는 것은 현실적으로 불가능하므로, 이미 프로그래밍을 가르치는 일부 MOOC들은 연구를 통해 학생들이 제출한 과제를 자동으로 채점해주는 프로그램을 개발하여 사용하고 있습니다.Elice의 자동 채점. 정해진 답이 있는 경우 자동 채점은 실시간으로 학생들이 받을 수 있는 새로운 피드백 채널이 됩니다.그러나, 프로그래밍 과목에서 자동 채점 프로그램은 한정적인 상황에서만 성공적으로 사용될 수 있으며, 특히나 과제의 내용이 명확한 답을 요구하지 않는 형태이거나 (예를 들어, 오늘 배운 명령어들을 이용하여 멋진 집을 3D로 그려주는 프로그램을 작성하시오!), 단순한 비교만으로 정답을 매길 수 없는 경우에는 사용될 수 없다는 명백한 한계점이 존재합니다. 그래서 프로그래밍 교육을 연구하는 연구자들은 자동 채점 프로그램도 아니고, 조교도 아닌 누가 학생들의 과제를 채점하고, 피드백을 줄 수 있을까를 고민하던 도중 이미 다른 교육 분야에서 연구되어 사용되던 “동료 평가 (peer assessment)”라는 방법에 눈을 돌리게 되었습니다.동료 평가란 간단하게 말하자면 학생들이 서로 간의 과제를 채점해주는 방식의 과제 채점 방법을 말합니다. 제출된 과제의 수 만큼 이것을 채점할 수 있는 학생 수가 존재하기 때문에, 동료 평가는 강의에 크기에 거의 무관하게 사용될 수 있다는 장점이 있습니다. 또한, 학생들은 다른 학생들이 제출한 과제를 채점하면서 자기가 생각하지 못했던 새로운 아이디어를 발견하거나, 자신이 했던 것과 유사한 실수를 하는 친구에게는 자신의 경험을 바탕으로 건설적이고 유용한 피드백을 줄 수 있는 등의 장점도 있습니다. 물론 학생 개개인의 실력은 숙련된 조교보다는 미숙하기 마련이지만, 조교가 한 개의 과제에 대해 한 개의 피드백만 남겨줄 수 있는 시간적 여력이 있었다면, 동료 평가에서는 한 개의 과제에 대해 열 명의 학생들이 서로 다른 열 개의 피드백을 주어 학생 개개인의 부족함을 보완할 수 있습니다. 다양한 선행 연구에 따르면, 하나의 과제를 다수의 학생이 채점하게 될 경우 통계적으로 조교와 비슷한 수준의 채점을 할 수 있다는 점이 증명된 바 있습니다.캔버스에 그림을 그리거나 애니메이션을 만드는 문제에서 동료 평가가 활용되고 있습니다.동료 평가는 프로그래밍 교육 환경에서 특히나 더욱더 빛을 발하고 있는데, 이는 프로그래밍 과목이 기초 과학이나 수학과 같은 과목과는 달리, 프로그램의 작동 원리에 대한 이론과 이를 실제로 구현하기 위한 기술 두 가지가 모두 숙련되어야만 효과적으로 활용될 수 있는 특징으로부터 기인합니다. 하나의 원리를 배우더라도 다양한 구현을 보고, 연습해보는 것이 좋고, 이는 동료 평가를 통해 다른 사람들이 제출한 과제를 검사하며 효과적으로 이루어질 수 있습니다. 그 이외에도 숙련된 프로그래머의 자질을 평가하는 기준 중 하나로 사용되는 “코드의 가독성(다른 사람이 보고 이해하기에 얼마나 좋게 작성되었는가)”과 같이 기계적으로는 채점하기 항목들은 동료 평가를 통해 쉽게 평가될 수 있는 등 프로그래밍 교육 환경에서 동료 평가가 가지는 장점은 전부 나열할 수 없을 정도입니다.그러나 동료 평가가 항상 만능인 것만은 아닙니다. 다음 포스트에서는 프로그래밍 동료 평가가 왜 어려운지, Elice 팀에서는 이 문제를 어떻게 해결했는지 소개해 드리도록 하겠습니다 :)#엘리스 #코딩교육 #교육기업 #기업문화 #조직문화 #서비스소개
조회수 370

금요일의 해커톤

안녕하세요. 엘리스입니다!지난 8월 말, 엘리스의 야심 찬 첫 해커톤이 있었습니다. 이번 해커톤은 매주 금요일 찾아가는 문제 ‘금요일에 코딩하는 토끼’에 대한 수강생 여러분의 성원에 힘입어 개최되었습니다.주제는 ‘코딩 문제의 A에서부터 Z까지 직접 설계하고 제작한다.’ 해커톤에서는 아이데이션 단계에서부터 문제 기획과 코딩, 채점을 위한 그레이더 제작까지 코딩 문제의 모든 것을 다루었습니다. 물론 실제 문제 동작을 위해 실행과 채점을 반복하며 디버깅하여 완벽한 실습 문제를 만드는 것 역시 이번 경연의 핵심이었는데요.이를 통해 모든 참가자 여러분들은 일일 엘리스 아카데미 실습 문제의 출제자가 되었습니다. 어떤 과정을 거친 어떤 결과물들이 있었을까요?해커톤 현장 스케치해커톤의 소개를 경청 중이신 참가자 여러분.지금까지 프로그래밍 문제를 많이 풀어보셨을 여러분이, 반대로 문제의 출제자가 되어 문제를 구성하는 관점에서 생각해보고 채점 방식까지 고민해본다면 프로그래밍에 대한 이해도를 더 높일 수 있을 것이라는 기대로 이와 같은 해커톤이 기획되었습니다. 교육자로서 엘리스 플랫폼의 다양한 기능을 직접 이용해볼 수 있는 것은 일석이조의 이점이었죠!경직된 분위기를 깨고 뇌를 말랑말랑하게 만들기 위한 아이스 브레이킹 시간은 팀 대항전으로 진행되었습니다.간단한 코딩 문제를 가장 먼저 맞히는 팀이 점수를 얻는 스피드 코딩 게임을 통해서 순발력을 높이고, 잠시 후 해커톤에서 본격적으로 사용하게 될 엘리스 플랫폼과 친해질 시간도 가질 수 있었습니다.'그림 그리기 게임'에서는 각 팀 디자이너들의 창의력이 폭발! 개발과 관련된 온갖 단어들을 1초 만에 그림으로 표현해야 하는 설명자의 재치와 크로키 실력(?)이 강조되었던 순간이었는데요. 승자는 '오즈'팀! 모두 오즈 팀 디자이너의 그림 실력에 입을 다물지 못했다고 합니다.게임을 하는 동안 어느새 어색했던 처음의 분위기가 파괴되었습니다. ^^ 1시간 동안 문제의 초안을 기획하는 시간이 주어지고, 이어 각 팀의 아이디어 발표 시간이 있었습니다.해커톤의 룰은 아래와 같았는데요.실행 가능한 프로그래밍 문제 1개 출제.동화를 모티브로 한 문제 스토리를 기획.채점 가능한 그레이더 제작.모든 팀들이 알고리즘 문제를 기획해주셨습니다. 동화의 서사구조를 논리적으로 단순화하거나 변형하여 알고리즘 문제에 녹여낸 과정이 인상적이었습니다.아이데이션 단계에서는 문제의 완성된 모습이 전부 그려지지는 않았지만 많은 고민의 흔적과 창의적인 생각들을 엿볼 수 있어 이로부터 탄생될 프로그래밍 실습을 기대할 수 있었습니다.밤샘 코딩 중...우승 문제 소개기획하고 코딩하고 디자인을 하다 보니(!) 어느새 날이 밝아왔습니다. 이제 남은 것은 팀별 결과물 발표와 우승팀 시상 뿐!'금코토'를 패러디하여 팀 명을 지어주신 어린 왕자 팀. /* prince */로고까지 깨알 섬세!모든 팀이 각기 다방면에서 강점을 부각하는 문제를 출제해주셨기 때문에 우열을 가리기 어려웠는데요. ‘금코토’배 해커톤이라는 이름에 걸맞게 금코토 과목의 취지와 가장 부합하는 문제를 출제한 팀에게 가산점을 주어 우승팀을 선발하였습니다. 그 결과 대망의 우승 문제는...거울나라의 앨리스팀의 ‘케이크와 병’ 단순한 명료한 문제 구성과 초등학생도 이해할 수 있는 쉽고 친절한 프레젠테이션으로 인상 깊었던 문제였습니다. 완성도, 문제 활용도 면에서 금코토 문제를 능가하며 단순하면서도 재미있게 풀 수 있는 문제라는 심사위원들의 평가가 있었습니다. 우승팀인 거울나라의 앨리스 팀 전원에게는 엘리스 굿즈를 선물로 보내드립니다. :)이밖에 겁쟁이 사자를 동물의 왕으로 만들기 위해 용기의 성을 짓는 알고리즘 문제를 낸 오즈의 마법사 팀의 문제는 스토리에 착안하여 자칫 복잡해질 수 있는 내용을 세세한 문제 설계로 극복하려 했던 점이 우수하게 평가받았습니다. 술주정뱅이 별에 사는 만취한 아저씨를 옮기는 알고리즘 문제를 낸 ‘목요일에 코딩하는 어린 왕자’ 팀은 참신성과 '넓이 우선 탐색', '깊이 우선 탐색', '다익스트라 알고리즘'을 모두 공부해볼 수 있도록 한 문제 구성 면에서 높은 평을 받았습니다.큰 상품도 내걸지 않았던 첫 해커톤이었는데도 참가자분들 모두가 열과 성을 다해 밤을 새워 문제를 만들어 주셨습니다. 모든 참가자 여러분들께 감사의 말씀 전합니다. :) 해커톤 이후 진행한 설문 조사에서 100%의 확률로 모든 분들이 다음 해커톤에 재참가 의사를 밝히셨는데요. 모두 첫 해커톤을 즐겨주셨던 것 같네요. 엘리스에서는 앞으로도 해커톤을 지속적으로 개최할 예정입니다. 코끝 시려질 때쯤 더욱 풍성하고 유익한 기획의 해커톤으로 찾아뵐 예정이니 많은 관심 가져주세요!*금코토 — ‘금요일에 코딩하는 토끼’라는 엘리스 아카데미 과목의 줄임말. 매주 금요일 저녁때쯤 업로드되는 문제로, 특정 루트로 토끼가 움직이도록 코딩해야 하는 콘셉트와 귀여운 휴보 래빗이 특징입니다. >>문제 풀어보기(무료)
조회수 2083

안드로이드와 자동화 툴

모바일은 플랫폼의 생태계와 규모에 비해 개발자들이 처리해야 할 것이 매우 많습니다.서버나 타 플랫폼들 또한 개발자들의 영역이 많지만 그 영역들이 세분화되고 전문화되어 가고 있습니다. 데이터베이스, 백엔드, 프론트웨어, 인프라, DevOps 와 같이 점점 분야별로 심화되고 독립성을 갖추어 가고 있습니다.하지만 모바일은 각 플랫폼의 개발자들이 전체적인 아키텍쳐, 프론트, 내부용 데이터베이스, 리소스 관리, 배포 등이 해당 플랫폼의 소수의 개발자들에게 광범위하게 공존합니다. 다양한 분야가 전문화되기엔 변화가 잦고 규모가 점 형태로 구성이 된 경우가 많기 때문입니다.그렇기 때문에 반복적이고 불필요하게 비용이 소모되는 작업일수록 자동화 해서 최대한 코드 작성 본연에 업무에 집중할 수 있도록 환경을 구성하는 것이 중요합니다.토스랩 안드로이드 팀은 2015년 초부터 조금씩 자동화 환경을 구성하여 현재는 아래와 같습니다.다국어 문자 관리 자동화이미지 관리 자동화CI다국어 문자 리소스 자동화1. 다국어 글로벌 담당자의 원본 문서토스랩은 다국어 지원을 위해 글로벌 번역 문서를 관리하고 있습니다. 문서는 Google Drive 를 통해서 관리되고 있으며 기획/개발 파트에서 다국어 지원을 위한 리소스를 기입하면 각 언어의 담당자들이 해당 언어를 번역하고 있습니다.구성은 아래와 같습니다ABCDEFGH영어한국어일본어중국어-간체중국어-번체웹키ios 키안드로이드 키2. 기존 작업기존에는 해당 언어의 번역 데이터를 추가하기 위해 개발 파트에서 수동으로 각 언어의 리소스 파일에 추가하는 형태로 진행하였습니다.이러한 작업의 단점은 언어별 리소스 파일에 키-값 형태의 문자 리소스를 추가하는 작업을 반복적으로 해야 한다는 것입니다. 또한 반영이 된 후에 수정된 문자에 대해서 반영하기가 매우 어렵고 실수도 빈번하게 발생합니다.이러한 가능성을 최소화 하기 위해 자동으로 문자 리소스를 갱신하는 작업을 진행하였습니다.3. 안드로이드 파트를 위한 별도 필터 파일 추가|A|B|C|D|E|F| |—-|—-|—-|—-|—-|—-| |영어|한국어|일본어|중국어-간체|중국어-번체|안드로이드 키|가급적 원본 파일에 대한 조작을 피하기 위해 안드로이드용으로 Read-Only SpreadSheet 를 별도로 생성하였습니다.해당 작업을 위해 Google SpreadSheet Script 를 사용하였습니다.4. 자동화 툴 작업자동화 툴의 역할은 크게 3가지였습니다.안드로이드용 필터 파일을 다운로드한다.Spread-sheet를 분석해서 다국어용 자료구조로 변환한다.다국어용 자료구조를 XML 파일로 변경한다.툴은 Python 스크립트로 작업하였습니다.5. Gradle Task 로 추가별도의 Python 파일을 실행해도 되지만 Gradle Task 로 추가하여 Android Studio 에서도 Task 를 실행할 수 있도록 하였습니다.개발팀에서 안드로이드 키를 원본 문서에 추가한 후 Gradle Task 실행하면 바로 반영되도록 하였습니다. 기존의 방식과 가장 큰 차이점은 Merge 시 충돌 이슈에 대해서 더이상 관여하지 않아도 된다는 것입니다. 가장 최근 시점을 기준으로 자동화 Task 를 실행하면 모든 리소스가 최신화되기 때문에 충돌이 난다하더라도 무시하고 새로 Task 를 실행함으로써 충돌에 의한 이슈를 완전히 배제하고 작업할 수 있다는 장점이 생겼습니다.더 나아가 현재는 Android 용 리소스 Key를 기획 팀에서 기획시 적용하도록 하기로 현재 논의되고 있습니다. 이러한 논의가 반영된다면 더이상 리소스 관리에 있어서 개발파트에서 관리 할 필요가 없어지므로 다국어 리소스에 반영해야할 리소스 또한 최소화 될 것이라 기대하고 있습니다.이미지 리소스 자동화1. 기존 작업앱에 사용되는 디자인 리소스는 이슈 트래커와 JANDI 의 디자인 토픽을 통해서 전달 받아 작업을 하였습니다.이런 작업 형태는 이미지 관리가 분산 될 뿐만 아니라 일관성 있는 전달 방식이 아니기 때문에 누락건이 언제든지 존재할 수 있습니다.그래서 디자인 리소스에 대한 관리를 디자인 팀이 주도적으로 하며 개발팀에서는 빠르고 편하게 이미지를 전달 받을 수 있도록 하기 위해 자동화 툴을 만들었습니다.2. 개선 작업토스랩의 디자인 팀에서 사용하는 저장소는 권한에 따라 접근이 가능하도록 API 를 제공하고 있습니다. Read-Only 권한을 부여받은 후 API 를 통하여 이미지를 다운로드하도록 툴을 구성하였습니다.툴은 Python 스크립트로 구성하였습니다.3. Gradle Task 로 추가문자 리소스와 마찬가지로 별도로 Gradle 로 툴을 이용할 수 있도록 하기 위해 별도의 Task 를 정의하여 사용하도록 하였습니다.자동화된 리소스의 관리문자와 이미지를 자동화로 관리한다 하더라도 개발자가 필요에 따라 임의로 추가/수정하는 리소스가 존재 할 수 있습니다.이를테면 다운로드한 이미지 리소스를 활용한 Selector-Drawable 과 같은 것들입니다.이에 따라 자동화 처리된 리소스들은 별도의 관리를 위해 추가적으로 ResourceSet 을 만들었습니다. android { // ...중략 sourceSets { main.res.srcDirs += ${별도의_리소스_경로} } } 이러한 방식을 통해서 자동화된 리소스와 추가적한 리소스를 분리하여 발생할 수 있는 문제를 최소화 하였습니다.지속적 통합 (Continuous Integration, CI)자동화와 관련되어서 결코 빠질 수 없는 내용입니다. 빌드, 테스트, 배포, 리포팅에 이르기까지 이 모든 과정에 있어서 자동화 되지 않았다면 상상하기 어려운 작업들입니다.토스랩에서는 Jenkins 를 활용하여 빌드-테스트-리포팅을 하고 있습니다.1. 빌드 대상빌드의 의미는 최소한 컴파일 오류가 발생하지 않는 코드들이 최종 상태로 관리되고 있음을 의미합니다. 그러기 때문에 언제나 중앙 저장소에 반영되었거나 반영될 예정의 소스들은 항상 빌드 대상이라고 볼 수 있습니다.안드로이드 팀은 내부적으로 빌드 대상이 되는 브랜치를 아래와 같이 정의하였습니다.개발된 이슈가 최종적으로 반영된 브랜치 (develop)Github 에서 코드에 변경이 발생하면 이를 Jenkins 로 통보하여 해당 브랜치를 빌드합니다.개발 브랜치에 반영을 위해 코드리뷰 중인 브랜치 (features, fixes)Github 에 새로운 Pull-Request 가 발생하면 Jenkins 로 통보하여 해당 브랜치를 빌드합니다.테스트와 리포팅은 이 시점부터 발생한다고 볼 수 있습니다.2. 빌드빌드를 하는 과정에 기본적인 정적 분석을 사용하고 있습니다. 코드의 Convention 이나 복잡도 등을 측정하고 이를 분석하여 수정할 부분을 파악하기 위해서입니다.3. 테스트안드로이드팀은 작년 중순까지 Robolectric 이라는 Test Framework 을 사용하였으나 여러가지 이슈로 인하여 현재는 Android Test Support Library 를 사용하고 있습니다. ATSL 은 에뮬레이터를 필요로 하기 때문에 Jenkins 서버에 에뮬레이터를 구동하여 Test-Bed 를 구성하였습니다.빌드 과정에서 정적 분석이 완료되면 테스트 코드를 동작 시킵니다.테스트 된 결과는 JUnit Test Report 와 Jacoco Coverage Report 를 받고 있습니다.4. 결과 리포트빌드, 테스트 결과는 Jenkins 에서 별도로 관리되고 있지만 모든 동작들은 자동화 되어 관리되기 때문에 별도의 장치가 없다면 알아채기 어렵습니다.좀 더 빠른 피드백을 받기 위해 JANDI-Webhook 기능을 이용하여 결과 리포팅을 바로 받아 확인 할 수 있도록 하였습니다. 또한 Github Pull-Request 화면에서 Build-Status 연동하여 코드리뷰 하는 과정에서 잠재적 오류를 찾을 수 있도록 하였습니다.※ 빌드된 결과물의 배포는 내부적인 정책으로 현재는 하지 않고 있습니다만, 현재 가용 가능한 리소스 안에서 해결 방안을 찾고 있습니다.총평자동화의 가장 큰 목적은 반복적이지만 시간을 소요하기엔 가치가 떨어지는 작업을 단순화 하기 위함이었습니다. 여기서 오는 가장 큰 의미는 관리에 소요되는 시간을 최소화함으로써 생산성을 향상 시켰다는 데에 있습니다.특히 다국어 리소스와 이미지 리소스를 자동화 하기 위한 작업은 소요된 시간이 극히 미미하지만 그 효과는 매우 긍정적이라 할 수 있습니다.CI 는 초기 설정뿐만 아니라 관리가 매우 어려운 작업입니다. 해당 시스템을 총체적으로 알고 있다는 가정에서 해야 하며 정책적으로 규정해야 하는 것들도 있습니다. 하지만 결과물 그 자체에 대한 관리를 위해서는 없어서는 안되는 도구이며 정적분석과 자동화 테스트 등 다양한 효과를 얻을 수 있기 때문에 많은 개발자들에게 권장하고 싶습니다.#토스랩 #잔디 #JANDI #개발 #효율 #자동화툴 #업무환경
조회수 3150

개발자 커리어 전환기 2 | 3시간 만의 퇴사 결정, 비전공자로 개발에 뛰어들다.

Q) 안녕하세요 Juan Carlos(환 까를로스)님 자기소개 부탁드려요.네 안녕하세요. 지금 immersive 6기에서 개발자가 되기 위해 열심히 공부하고 있는 환 까를로스라고 합니다. 어쩌다보니 immersive 6기에서 전문 네비게이터로 생활하고 있어요.(웃음) 네비게이터는 페어프로그래밍을 할 때 드라이버가 코딩을 할 수 있도록 큰 그림을 그려주는 거라고 생각하시면 되요. 페어와 같이 코딩을 하면서 Immersive를 헤쳐나가고 있습니다.Q) 코드스테이츠 오시기 전에는 어떤 일을 하셨었나요?해외영업을 했습니다. 이 일을 선택한 이유는 조금 특별해요. 제가 취준생이었을 때 회사를 여러 곳을 지원을 했었습니다. 지원한 기업에서 합격 통보를 받았죠. 근데 막상 그 기업에 입사하려고 보니까 지방에서 근무를 해야 하는 거예요. 그전까지는 이런 것들을 생각도 안 하고 있다가, 막상 닥치니까 곰곰이 생각하게 되었어요.'내가 서울을 떠나서 잘 살 수 있을까?' 지방에서 산다는 거에 대해서 크게 생각하고 있지 않았었는데, 막상 닥치니까 고민이 많이 되더라구요. 제가 서울 토박이인데, 고향을 떠나서 사는 거는 제가 너무 힘들 것 같아서 포기하고 지금 현 직장(지금은 퇴사를 했죠)에 다니게 된 거예요. 그리고 제가 공대 출신인데 공대 출신이 서울에서 직장을 잡으려면 영업 밖에 없더라구요. 그래서 영업직을 선택했었습니다.Q) 그럼 직장을 나오게 된 계기가 있으신가요?새로운 것을 수용할 생각이 없는 경직된 조직문화가 너무 안 맞았어요. 저는 신입을 뽑는 이유는 조직이 시장의 흐름이나 세대의 변화에 맞춰 변하기 위해서라고 생각해요. 근데, 전에 팀은 변할 생각을 안 하더라고요. 야근까지 해가면서 업무개선을 해도 기존 방식을 고수하자는 피드백이 계속되니 열정이 사라지는 것을 느꼈죠. 제가 4년 정도 다녔는데, 퇴사를 고민하고 3시간 만에 결정하고 사표를 내고 나왔어요.저는 뭔가 다양한 경험을 하고 제 스스로가 발전하는 걸 좋아하는데, 발전한다는 느낌이 없었죠. 부서를 여러 곳으로 옮긴 이유도 제가 정확히 뭘 좋아하는지 모르니까 이것저것 해보면 알지 않을까 생각했어요. 영업 파트에서 일하면서도 기획부터 경영지원까지 다양한 일을 맡았었죠.Q) 3시간이면 정말 짧네요! 보통은 여러 번 고민하기 마련인데요. 그럼 퇴사하시고 나서는 무엇을 하셨나요?음... 사실 퇴사하고 나서 제가 맡았던 고객들이 경쟁사로 이직할 수 있게 도와주겠다고 하셔서 고민을 많이 했어요.  근데, 이왕 퇴사했는데 새로운 걸 해보고 싶었어요. 한 군데 계속 있으면 뭐랄까.. 나태해지는 것 같아서요.- 다른 분야의 직장을 잡으신 건가요?일단은 여행 가야지라고 생각해서, 스페인으로 떠났어요.  첫 번째로는 스페인의 순례길을 가기로 했죠. 1000km 정도 되는 길을 걸었던 것 같아요. 순례길을 걸으면서 다양한 사람들을 만나고 생각도 정리도 좀 하고 그랬어요. 거기에는 전 세계 퇴사한 사람이 다 모이는 것 같아요. 숙소에서 만난 친구들에게 물어보면 죄다 회사를 퇴사하고 왔다고 하더라구요(웃음) 그리고 그곳에서 개발자가 돼야겠다는 마음을 먹었습니다.Q) 어떤 경험을 하셨길래 그곳에서 개발자가 돼야겠단 마음을 먹으셨나요?먼저 이 얘기를 해야 하겠네요. 사실 제가 여행경비가 이렇게 많이 들지 몰랐어요. 순례길을 여행하다가 돈도 떨어져 가는데 직업이 있는 채로 순례길을 도는 사람들을 만나게 된 거예요. 세 명을 만났는데, 세 명 다 소프트웨어 엔지니어였습니다. 처음에는 브라질 개발자를 만났어요. 그때까지만 해도 별생각이 없었죠. 다음으로는 러시아 개발자를 만났습니다. 러시아 개발자 친구를 보면서 아 이런 게 디지털 노마드구나라는 생각을 갖게 되었죠. 그리고 마지막으로 스페인 개발자 친구를 만나니까 정말 개발자라는 직업이 부럽게 느껴지더라구요. Q) 디지털 노마드를 보고 개발자가 돼야겠단 결정을 하신 거네요! 그럼 코드스테이츠를 선택해주신 이유가 있으신가요? 아까 제가 생각보다 여행 경비가 많이 드는지 몰랐다고 했잖아요. 순례길만 여행하는데도 여행 경비가 다 떨어진거에요(웃음) 그래서 어쩔 수 없이 세계 여행의 꿈을 접고 한국으로 오게 되었죠. 그리고 한국으로 돌아오는 비행기 안에서 개발자가 되기로 결심을 했습니다. 내가 여행을 다니고 하고 싶은 것을 하면서도 일도 하고 그게 너무 좋아 보이는 거에요. 물론 한국의 현실은 많이 다르겠지만 그래도 개발자라면 가능하지 않을까라고 생각을 했습니다. 그리고 그 비행기에서 핸드폰으로 코딩 관련해서 검색을 하다가 코드스테이츠를 알게 되었어요. 알아보니까 교육철학도 좋고 저에게도 괜찮은 방식을 것 같아서 그 비행기 안에서 바로 결정을 하게 되었습니다. 퇴사할 때와 마찬가지로 일사천리로 결정을 했습니다.- 비행기 안에서 모든 결정이 이루어졌네요! 3시간 만에 퇴사를 결정하신 것 같이요!뭐 망설일 이유가 있나요. 자신감과 결단력 그게 제 장점이니까요(웃음)Q) 그럼 이제 Immersive 얘기를 해볼게요. Immersive에서의 생활은 어떠세요?생각했던 것보다 여유가 있어서 좋아요. 그전에는 되게 불안하고 빡빡하고 그럴 것 같은데 막상 해보니까 할만하더라고요. 그리고 일단 사람들이 너무 좋아요. 같이 지내는 사람들이 좋으니까 Immersive도 할만한 것 같아요.Q) 그러면 지금 Immersive에서는 어떤 것을 배우고 있나요?서버를 배우고 있어요. 프론트 쪽 하구요. 프로젝트를 하고 적용을 해봐야 완전히 내 것으로 만들 수 있을 것 같아요. 역시 직접 적용을 해봐야 정확히 알 수 있을 것 같습니다.서버를 배우고 있어요. 프론트 쪽 하구요. 자바스크립트라는 언어의 다양한 문법을 매일 체험해보고 있어서, 매일매일이 새롭습니다. (뭔가 이해할 만 하면 다른걸 배워서..) 프로젝트를 해봐야 완전히 내것으로 만들 수 있을 것 같아요.Q) 앞으로 어떤 개발자가 되고 싶으세요?거창하게 세상을 바꾸는 개발자! 이런 건 제 스타일은 아니에요(웃음) 저는 제가 하고 싶은 것을 하는 개발자. 만들고 싶은 것을 만드는 개발자가 되고 싶어요. 세상을 바꾸는 개발자도 내가 좋아하는 것, 내가 하고 싶은 것, 내가 만들고 싶은 것을 만드는 개발자가 되었을 때 가능하지 않을까요?Q) 프로젝트를 곧 하게 될 텐데 어떤 프로젝트를 하고 싶으신가요?제 경험에 기반한 프로젝트에요. 우리는 회사에서 주는 돈 그냥 받잖아요. 제가 회사를 나오고 받았던 돈들을 확인해보니 제대로 받지 못했다는 것을 알았어요. 그래서 사람들이 노동의 정당한 보상을 알고 받을 수 있도록 도와주는 프로그램을 만들고 싶어요. 주변만 봐도 대부분의 사람들이 이런 문제로 인해 문제를 가지고 있다고 생각해요.Q) 1년 후에 개발자가 되었다고 생각하면 어떤 모습일까요?개발자가 될 수 있을까요?(웃음) 아마 1년 후엔 야근에 쩔어있지 않을까요? 저는 이게 내 일이다라는 생각을 하면 엄청 파고드는 스타일이거든요. 개발자로 처음 들어간 직장에 남아 있거나 이직을 하고 있을 것 같아요. 사실 저는 계획을 잘 안 세우거든요. 그러니까 아무 준비 없이 퇴사하고 개발을 배우고 있죠. 설마 굶어죽기야 하겠어요?Q) 마지막으로 하고 싶은 말이 있나요?제가 퇴사하면서 방 정리도 같이 하게 됐어요. 정리를 하다 보니까 우연찮게 제 학창시절 생활기록부를 보게 되었습니다. 생활기록부에 장래희망을 적는 칸이 있잖아요. 근데 제가 깜짝 놀란 게 거기에 중학교 때부터 고등학교 때까지 줄곧 프로그래머로 적혀있던 거에요. 그동안 까맣게 잊고 살았는데 신기했어요.그리고 또 생각을 해보니까 대학교 때도 제가 컴공과는 아니지만 공대라서 C++을 해야했는데 그 과목에서 처음으로 A+을 받은 기억이 나더라구요. 이런 생각이 들면서 결국 나는 프로그래머를 선택할 운명이었나? 이런 생각도 들고. 결국에는 돌아돌아 이 길로 온 것 같아요. 그래도 돌아왔다고 해서 늦었다거나 아쉽지는 않아요. 제가 지금까지 걸어온 길이 분명히 프로그래밍을 하는데 도움이 된다고 생각하고 있으니까요.네 지금까지 환 까를로스님과의 인터뷰를 진행했었는데요. 정말 비하인드스토리가 엄청나네요. Immersive 성공적으로 수료하시고 원하시는 개발자가 되기를 바랍니다. 앞으로도 다양한 스토리를 가진 Immersive 수강생분들의 이야기로 찾아뵙겠습니다.
조회수 2951

eventlet을 활용한 비동기 I/O 프로그래밍

안녕하세요. 스포카 크리에이터팀 문성원입니다. 현대적인 프로그래밍 환경에서 네트워크는 더는 특정 직군의 개발자만 접하는 분야가 아닙니다. 그런 만큼 대량의 요청을 네트워크를 통해 송수신하는 프로그램이 생각보다 성능이 나오지 않는 경우를 경험하신 분들도 많으실 겁니다. 물론 스포카 개발팀도 예외는 아니었습니다. 그래서 오늘은 저희의 이러한 경험과 그 해결책-eventlet을 통한 비동기 I/O(Asynchronous I/O)-에 대해 소개합니다.Why우선 스포카 개발팀에서 겪었던 문제부터 시작하죠. 얼마 전 페이스북(facebook)의 FQL(Facebook Query Language)를 통해 정보를 수집해서 이를 활용하는 기능을 작성해야 했습니다. 기존의 함수들은 필요할 때마다 FQL을 요청하는 방식이었고 당연히 이건 너무 느렸죠. 그래서 생각한 것이 “하루의 일정 시간마다 대량의 FQL 요청을 보내서 필요한 정보를 미리 갱신시켜놓자.”였습니다. 여기까진 좋았죠. 이때 제가 작성한 코드의 얼개를 살펴보면 대강 이렇습니다.# 페이스북 계정들을 가져와서 반복하면서for account in FacebookAccount.query:    account.update() #FQL을 보내자.view rawgistfile1.py hosted with ❤ by GitHub그런데 문제가 있었습니다. 기존의 FQL을 보내는 FacebookAccount.update()는 FQL요청이 완료될때까지 멈추고 기다립니다. 대부분의 FQL요청이 2, 3초 정도 걸린다고 했을 때 이러한 지연은 매우 치명적입니다. 대안이 필요했고 자연스레 떠오른 것이 서두에 소개한 비동기 I/O(Asynchronous I/O)였습니다.Asynchronous과거 일부 고급 서버 개발자만 알고 있는(혹은 알아야 하는) 기술로 치부되던 ‘비동기(Asynchronous)’란 개념은 2000년대 들어 등장한 Ajax(Asynchronous JavaScript and XML)의 성공 이후 많은 개발자에게 강한 인상을 줬습니다. 사용자는 HTTP 요청이 끝날 때까지 멈추어 있는 하얀 화면으로부터 해방되었고, 다양하고 많은 요청과 응답들이 자연스럽게 서버로 흘러들어 가서 나왔습니다. 개발자들의 이러한 경험과 통찰은 이후 node.js와 같은 플랫폼의 등장에도 많은 영향을 끼쳤습니다.다시 문제로 돌아가죠. 그렇다면 이러한 비동기에 관한 개념은 위의 상황을 어떻게 해결할 수 있을까요? 문제의 원인부터 다시 살펴봅시다. 2, 3초 정도씩 걸리는 FQL 요청이 문제일까요? 물론 요청이 매우 빨리 처리된다면 별도의 처리 없이도 저 코드는 문제없이 동작합니다. 하지만 현실적으로 이런 I/O의 속도를 빠르게 하는데에는 물리적으로 한계가 있습니다. 오히려 여기에서 주목해야 할 점은 ‘2, 3초’ 보다 ‘기다린다’라는 점입니다. FacebookAccount.update() 같은 경우, I/O가 처리되는 동안 CPU는 하던 일을 멈추고 문자 그대로 기다리게 됩니다. 만약 CPU가 멈추지 않고 다른 요청을 보낸다면 어떨까요? 이렇게 말이죠.비동기만으로는 부족하다?이러한 아이디어는 그동안 많은 개발자가 대량의 I/O를 다루는 올바른 방식으로 여겨왔습니다. 하지만 보통 이러한 비동기 I/O를 통한 구현은 동기식 I/O와는 좀 다른 형태를 띠게 됩니다. 이렇게 말이죠.# http://docs.python.org/library/asyncore.html#asyncore-example-basic-http-clientimport asyncore, socketclass HTTPClient(asyncore.dispatcher):    def __init__(self, host, path):        asyncore.dispatcher.__init__(self)        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)        self.connect( (host, 80) )        self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path    def handle_connect(self):        pass    def handle_close(self):        self.close()    def handle_read(self):        print self.recv(8192)    def writable(self):        return (len(self.buffer) > 0)    def handle_write(self):        sent = self.send(self.buffer)        self.buffer = self.buffer[sent:]client = HTTPClient('www.python.org', '/')asyncore.loop()view rawgistfile1.py hosted with ❤ by GitHub불행하게도, 이 경우 기존에 사용하던 urllib2대신 HTTP 요청을 처리하는 핸들러를 이처럼 재작성 해야합니다. 거기에 FacebookAccount.update()의 호출 방식마저 바뀔 수 있죠. 더군다나 콜백(Callback) 투성이의 코드는 유지보수가 쉬어 보이지도 않습니다. 여러모로 손이 많이 가는 상황이죠.결국, 기존 코드를 최대한 수정하지 않으면서도, 어느 정도 성능은 보장되는 그런 해결책이 필요했습니다. 그런 해결책이 있을까요? 다행히도 그렇습니다.What저희가 해결책으로 택한 eventlet은 Python(정확히는 CPython)에서 코루틴(Coroutine)을 지원하기 위해 만들어진 greenlet을 이용해 작성된 네트워크 관련 라이브러리입니다. 생소한 용어가 갑자기 튀어나와서 놀라셨을지도 모르니 우선 eventlet에 대해 설명하기 전에 앞에 나온 용어들을 찬찬히 한번 살펴보죠.코루틴과 greenlet먼저 코루틴(Coroutine)부터 살펴보죠. 전산학도라면 누구나 그 이름을 한번은 들어봤을 도널드 카누쓰(Donald Knuth)는 자신의 저서 The Art of Computer Programming에서 코루틴을 다음과 같이 설명합니다.Subroutines are special cases of more general program components, called “coroutines.” In contrast to the unsymmetric relationship between a main routine and a subroutine, there is complete symmetry between coroutines, which call on each other.코루틴은 우리가 잘 알고 있는 서브루틴(Subroutine)과 달리 진입점(Entry Point)이 여러 개일 수 있습니다. 쉽게 이야기하면 실행을 멈췄다가(Suspend) 재개(Resume)할 수 있다는 점인데요. 이 특성을 살리면 우리가 익히 아는 스레드(Thread)처럼 쓸 수 있게 됩니다. 다만 스레드와 달리 코루틴은 비선점적(Non-Preemptive)이기때문에 코드의 흐름을 전적으로 사용자가 제어할 수 있습니다.하지만 불행히도 모든 언어에서 이런 코루틴이 지원되진 않습니다. greenlet은 이런 코루틴을 CPython에서 지원하기 위해 작성된 라이브러리입니다.eventlet코루틴을 통해 스레드를 대체할 수 있다는 점에 주목한 사람들은 greenlet을 통해 유용한 네트워크 라이브러리를 만들어냈습니다. eventlet도 그 중 하나죠. 잠시 eventlet의 소갯글을 봅시다.Eventlet is a concurrent networking library for Python that allows you to change how you run your code, not how you write it.위에서 볼 수 있듯이 eventlet은 사용성에 중점을 두었습니다. 기존의 블로킹 I/O 스타일의 프로그래밍에 익숙한 개발자들도 쉽게 비동기 I/O의 장점을 얻을 수 있게끔 하는 게 목적이죠.특히 저희가 주목한 점은 eventlet의 멍키패치 기능입니다. 멍키패치는 본래 동적 언어에서 런타임에 코드를 고쳐서 별도의 파일 변경 없이 본래 소스의 기능을 변경하는 것을 말합니다. eventlet은 eventlet.monkey_patch 메서드를 통해 표준 라이브러리의 I/O 라이브러리를 논블러킹으로 동작하게끔 변경해서 코루틴에 적합하게 만듭니다.How앞서 소개한 eventlet.monkey_patch를 이용하면 실제로 고칠 부분은 정말로 적어집니다. 다음 코드가 eventlet을 이용해 변경한 전부입니다.import eventleteventlet.monkey_patch() #표준 라이브러리를 변환# 여러가지 import를 하고...pool = eventlet.GreenPool()# 페이스북 계정들을 가져와서 반복하면서for account in FacebookAccount.query:    # 코루틴들에게 떠넘기자.    pool.spawn_n(FacebookAccount.update, account)        pool.waitall()view rawgistfile1.py hosted with ❤ by GitHub정말 적죠? 조금만 구체적으로 살펴보죠. 우선 eventlet.monkey_patch는 socket이나 select등의 Python 표준 라이브러리를 eventlet.green 패키지안에 정의된 코루틴 친화적인 모듈들로 바꿔치기 합니다.# from eventlet/pathcer.pydef monkey_patch(**on):    """Globally patches certain system modules to be greenthread-friendly.    The keyword arguments afford some control over which modules are patched.    If no keyword arguments are supplied, all possible modules are patched.    If keywords are set to True, only the specified modules are patched.  E.g.,    ``monkey_patch(socket=True, select=True)`` patches only the select and     socket modules.  Most arguments patch the single module of the same name     (os, time, select).  The exceptions are socket, which also patches the ssl     module if present; and thread, which patches thread, threading, and Queue.    It's safe to call monkey_patch multiple times.    """        accepted_args = set(('os', 'select', 'socket',                          'thread', 'time', 'psycopg', 'MySQLdb'))    default_on = on.pop("all",None)    for k in on.iterkeys():        if k not in accepted_args:            raise TypeError("monkey_patch() got an unexpected "\                                "keyword argument %r" % k)    if default_on is None:        default_on = not (True in on.values())    for modname in accepted_args:        if modname == 'MySQLdb':            # MySQLdb is only on when explicitly patched for the moment            on.setdefault(modname, False)        on.setdefault(modname, default_on)            modules_to_patch = []    patched_thread = False    if on['os'] and not already_patched.get('os'):        modules_to_patch += _green_os_modules()        already_patched['os'] = True    if on['select'] and not already_patched.get('select'):        modules_to_patch += _green_select_modules()        already_patched['select'] = True    if on['socket'] and not already_patched.get('socket'):        modules_to_patch += _green_socket_modules()        already_patched['socket'] = True    if on['thread'] and not already_patched.get('thread'):        patched_thread = True        modules_to_patch += _green_thread_modules()        already_patched['thread'] = True    if on['time'] and not already_patched.get('time'):        modules_to_patch += _green_time_modules()        already_patched['time'] = True    if on.get('MySQLdb') and not already_patched.get('MySQLdb'):        modules_to_patch += _green_MySQLdb()        already_patched['MySQLdb'] = True    if on['psycopg'] and not already_patched.get('psycopg'):        try:            from eventlet.support import psycopg2_patcher            psycopg2_patcher.make_psycopg_green()            already_patched['psycopg'] = True        except ImportError:            # note that if we get an importerror from trying to            # monkeypatch psycopg, we will continually retry it            # whenever monkey_patch is called; this should not be a            # performance problem but it allows is_monkey_patched to            # tell us whether or not we succeeded            pass    imp.acquire_lock()    try:        for name, mod in modules_to_patch:            orig_mod = sys.modules.get(name)            if orig_mod is None:                orig_mod = __import__(name)            for attr_name in mod.__patched__:                patched_attr = getattr(mod, attr_name, None)                if patched_attr is not None:                    setattr(orig_mod, attr_name, patched_attr)        # hacks ahead; this is necessary to prevent a KeyError on program exit        if patched_thread:            _patch_main_thread(sys.modules['threading'])    finally:        imp.release_lock()view rawgistfile1.py hosted with ❤ by GitHub이렇게 바꿔치기된 eventlet.green안의 모듈들은 I/O에 의해 블럭되는 경우 다른 코루틴에 제어권을 넘기는 식으로 지연을 방지합니다.다른 대안들사실 이러한 목적으로 사용되는 라이브러리는 eventlet만 있는 것은 아닙니다. gevent는 eventlet에서 영향을 받았지만, libevent를 기반으로 하여 더욱 나은 성능과 성숙한 인터페이스를 갖추고 있습니다. 저희처럼 libevent의 설치에 제한이 있는 환경이 아니라면 이쪽을 살펴보셔도 좋습니다.만약 이벤트 주도적 프로그래밍(Event-Driven Programming)에 흥미가 있으신 분은 Twisted역시 좋은 대안이 될 수 있습니다.#스포카 #개발 #개발자 #인사이트 #꿀팁
조회수 669

HBase Meetup - 비트윈에서 HBase를 사용하는 방법

비트윈에서는 서비스 초기부터 HBase를 주요 데이터베이스로 사용하였으며 사용자 로그를 분석하는 데에도 HBase를 사용하고 있습니다. 지난 주 금요일(11월 15일)에 HBase를 만든 Michael Stack 씨가 한국을 방문하게 되어 ZDNet 송경석 팀장님의 주최 하에 HBase Meetup Seoul 모임을 가졌습니다. 그 자리에서 VCNC에서 비트윈을 운영하면서 HBase를 사용했던 경험들이나 HBase 트랜잭션 라이브러리인 Haeinsa에 대해 간단히 소개해 드리는 발표 기회를 가질 수 있었습니다. 이 글에서 발표한 내용에 대해 간단히 소개하고자 합니다.비트윈 서비스에 HBase를 사용하는 이유비트윈에서 가장 많이 사용되는 기능 중 하나가 채팅이며, 채팅은 상대적으로 복잡한 데이터 구조나 연산이 필요하지 않기 때문에 HBase 의 단순한 schema 구조가 큰 문제가 되지 않습니다. 특히 쓰기 연산이 다른 기능보다 많이 일어나기 때문에 높은 쓰기 연산 성능이 필요합니다. 그래서 메세징이 중심이 되는 서비스는 높은 확장성(Scalability)과 쓰기 성능을 가진 HBase가 유리하며 비슷한 이유로 라인이나 페이스북 메신저에서도 HBase를 사용하는 것이라고 짐작할 수 있습니다.로그 분석에도 HBase를 사용합니다비트윈은 사용자 로그 분석을 통해서 좀 더 나은 비트윈이 되기 위해서 노력하고 있습니다. 비트윈 사용자가 남기는 로그의 양이 하루에 3억건이 넘기 때문에 RDBMS에 저장하여 쿼리로 분석하기는 힘듭니다. 그래서 로그 분석을 위해 분산 데이터 처리 프레임워크인 Hadoop MapReduce를 이용하며 로그들은 MapReduce와 호환성이 좋은 HBase에 저장하고 있습니다. 또한 이렇게 MapReduce 작업들을 통해 정제된 분석 결과를 MySQL에 저장한 후에 다양한 쿼리와 시각화 도구들로 custom dashboard를 만들어 운영하고 있습니다. 이를 바탕으로 저희 Biz development팀(사업개발팀)이나 Data-driven팀(데이터 분석팀)이 손쉽게 insight를 얻어낼 수 있도록 돕고 있습니다.HBase를 사용하면서 삽질 했던 경험HBase를 사용하면서 처음에는 잘못 사용하고 있었던 점이 많았고 차근차근 고쳐나갔습니다. Region Split과 Major Compaction을 수동으로 직접 하는 등 다양한 최적화를 통해 처음보다 훨씬 잘 쓰고 있습니다. HBase 설정 최적화에 대한 이야기는 이전에 올렸던 블로그 글에서도 간단히 소개한 적이 있으니 확인해보시기 바랍니다.HBase 트랜잭션 라이브러리 해인사Haeinsa는 HBase에서 Multi-Row 트랜잭션을 제공하기 위한 라이브러리입니다. 오픈소스로 공개되어 있으며 Deview에서도 발표를 했었습니다. HBase에 아무런 변형도 가하지 않았기 때문에 기존에 사용하던 HBase 클러스터에 쉽게 적용할 수 있습니다. 비트윈에 실제로 적용되어 하루 3억 건 이상의 트랜잭션을 처리하고 있으며 다른 많은 NoSQL 기반 트랜잭션 라이브러리보다 높은 확장성과 좋은 성능을 가지고 있습니다.저희는 언제나 타다 및 비트윈 서비스를 함께 만들며 기술적인 문제를 함께 풀어나갈 능력있는 개발자를 모시고 있습니다. 언제든 부담없이 jobs@vcnc.co.kr로 이메일을 주시기 바랍니다!
조회수 42899

프론트엔드 개발자(Front-End Developer)에 대해 알려드립니다!!

안녕하세요 크몽 개발팀입니다. 오늘은 일상적인 'IT 이야기'가 아닌 제가 맡고 있는 직책인'프론트엔드 개발자(Front-End Developer)'에 대해 포스팅을 해보고자 합니다.여러분들은 혹시 'Front End'라는 용어에 대해 알고 있으신가요? 저도 제일 처음 이 단어를 들었을땐 이게 대체 무슨 단어인가 했습니다.이 용어 외에도 'Back End'라는 단어도 있는데요, 물론 처음만나는 단어가 두개인만큼 두배로 어려워보일 수 있겠지만.. 놀라셨을 가슴 한번 쓸어내려드리고 전~혀 어렵지않다는 것을 차차 설명해드리겠습니다.----------------------------------------------------------------------------------------'프론트엔드'란??우선, 'Front End'라는 단어는 어떤의미의 단어일까요? 'W사'의 사전을 통해 알아보겠습니다.   한마디로 말씀드려서 '프론트엔드'는 사용자들에게 보이는 영역을 책임을 지는 것이며 '백엔드'는 시스템적인것으로 눈으로 보이지는 않지만 말 그대로 뒤에서 전산 처리를 하는 것을 말합니다.즉, '프론트엔드'는 시스템적으로 멋지게 만들어진 아이맥의 내부를 감싸는 껍데기를소비자들이 사고 싶게 만드는 디자인으로 구현하는 작업을 말하는 것입니다.크몽의 '조너선 아이브'같은 존재(?)라고 말씀드릴 수가 있겠군요.. 하하하하 (자뻑 죄송합니다(__);;)  '프론트엔드 개발자'의 목표는?'프론트엔드 개발자'의 미션은 두가지라고 말씀드릴 수가 있습니다.    첫번째로, 사용자들이 홈페이지를 친숙하고, 직접적으로 보여지도록 개발하는 것인데 딱 두가지!! 개발스킬과 미적감각을 동반하여야 합니다.여기서 중요한점은!! 쿤이는 디자인을 좋아라하지만 영감이 떠올릴만한 미술관과는 거리가 있다는 점점점점점점...앞으로 열심히 다녀보겠습니다!다시 본문으로 돌아가서..두번째는, 끊임없이 변화하는 웹세상에서 어떤툴과 테크닉을 썼는지 알고 있어야 한다는 점입니다.이 부분은 변화를 사랑하는 쿤이에겐 식은죽 먹기보다 쉽다고 하는게 맞겠네요!! (제발 그렇다고 해줘요..ㅠㅠ) '프론트엔드 개발자'가 쓰는 툴은?'프론트엔드 개발자'가 쓰는 툴의 몇몇은 웹사이트의 UI를 개발하는 툴에서 구할 수 있습니다. 첫번째로, 'HyperText Markup language'라고 불리는 'HTML' 되겠습니다.이 마크업언어는 어떤 웹사이트에서 중추적인 역활을 하는 그런 녀석입니다. 이 녀석은 말이죠... 자신의 이름을 문서의 앞뒤에 안써주면 자신의 정체도 모르는 그런녀석이구요,이 녀석의 명령어(태그)를 쓸땐 말이죠 명령어 끝에 닫는태그를 안해주면 크게는 문서 전체를 뒤죽박죽으로 만드는 그런 녀석이에요.어떨때는 파트너('CSS')와 함께 어디 놀러갈땐 각 장소(인터넷 익스플로어, 크롬 등..)에 따라 다른 매력을 발산해줘서 양파같이 까도까도 속을 모르는 그런 녀석이에요.두번째는, 'Cascading Style Sheet'라고 불리는 'CSS'입니다이 스타일 시트는 프레젠테이션효과를 주며 우리의 웹사이트가 단 하나밖에 없다는 희귀성을 부여할 수 있습니다. 이 녀석은 아까 말씀드렸듯이 'HTML'의 파트너에요. 남자는 여자하기 나름이란 말과 같이 'HTML'은 'CSS'하기 나름이라고 말씀드릴수가 있을 것같네요. 직접적으로 말씀드리자면 'HTML'이 몸이라고 보시면 'CSS'는 옷입니다. 'CSS'가 어떻게 스타일을 주는가에 따라서 웹사이트가 최신스타일룩을 보여줄 수도 있으며 잘못 쓴다면 90's 힙! to the 합!스타일을 보여 줄 수도 있습니다. 그래서 많은 사이트들이 사용자들에게 직접적으로 보여지는 스타일에 대해 신경쓰는 것이 이러한 이유라고 말씀드릴 수가 있습니다.세번째는, 'Content Management System'인 'CMS'입니다우리 한글로 표현하자면 내용관리시스템이란 것인데 아마 생소하실 것이라고 생각 듭니다. (실은 저도 생소했습니다ㅎㅎ)이 녀석은 한마디로 웹 사이트의 내용을 관리하는 시스템인데요.내용 관리 애플리케이션('CMA')과 내용 배포 애플리케이션('CDA')이 있는데요,그냥 약자로만 봤을 때엔 저기 아무 증권사나가서 한번쯤은 가입해야 될 것같은 분위기죠? 단호하게.. 아닙니다!! 연이자 2%할 것같은 'CMA'가 하는 일은 'HTML'에 들어갈 내용, 변경, 제거 등의 관리 프로그램이고,왠지 아이들의 미래를 위해 들어야될 것같은 'CDA'는 웹 사이트의 모든 수치(현행화)를 보고 편집할 수 있는 정보편집 프로그램입니다.우리가 흔히 볼 수 있는 형태로는 웹 기반 편찬(마법사템플릿 등), 형식 관리, 계정 제어, 데이터의 색인,테이터 탐색, 키워드 검색 등이 있을 수 있겠습니다.프론트엔드 개발자가 유의할 점은?프론트엔드개발자는 다음 두가지의 사항에 대해 유의해야 합니다.첫번째는, 접근성입니다. 앞서 말씀드렸듯이 이용자들에게 친숙한 모습으로 다가가야합니다.한번도 보지도 듣지도 못한 그런 UI로 이용자들에게 다가간다면 과연 잘 사용할 수 있을지가 문제일 겁니다.그런 맥락에서 말씀드리자면 모든기기에서 항상 똑같은 모습으로 이용자들을 맞이한다면각 기기에서 최적화 되지못한 화면들이 나와 이용자들에게 혼란을 줄지도 모를 일입니다.그렇기때문에 동적인 사이트를 만들어야 된다는 생각을 프론트엔드 개발자는 생각하고 있어야합니다.두번째는, 사용 간편성입니다. 만약 접근성이 좋아졌다고 하더라도 검색엔진에 최적화되지않은 사이트라면전세계적 검색사이트인 G사에서 사이트안의 컨텐츠와 연관된 내용을 검색하더라도 상위에 랭크 안되는 경우가 많습니다.그렇게 된다면 검색사이트로 원하는 사이트를 찾아들어가는 지금으로는 많은 잠재이용자들의 유입을 막아 더 이상 서비스가 성장하지못하는 상황까지 갈 수 있습니다.---------------------------------------------------------------------------------------- 이렇게 제가 하는일에 대해 포스팅을 하다보니 제가 맡은 업무가 우리 크몽서비스에 얼마나 큰 영향을 주는지 알 수 있었는데요... 갑자기 제 어깨에 곰한마리가 앉은 것같은 느낌이 드네요ㅠㅠㅠㅠ (아~ 피로야가라~!!!) 지금까지 제가 공부한 내용들을 간략하게 포스팅해보았는데요.담번엔 배운것들을 쓰는 과정을 시간이 허락한다면 보여줄 수 있는 포스팅으로 찾아 뵙겠습니다. :)#크몽 #개발자 #개발팀 #프론트엔드 #인사이트 #팀원소개
조회수 1504

[Tech Blog] PhantomJS를 Headless Chrome(Puppeteer)로 전환하며

버즈빌에서는 모바일 잠금화면에 내보내기 위한 광고 및 컨텐츠 이미지를 생성하기 위한 PhantomJS 렌더링 서버를 다수 운영하고 있습니다. 일반적으로 PhantomJS는 웹페이지 캡쳐에 많이 쓰이지만, 기본적으로 headless하게 웹페이지를 렌더링하고 캡쳐할 수 있다는 특성 때문에 동적인 이미지 생성에도 많이 활용됩니다. 버즈빌의 렌더링 서버는 200개 이상의 컨텐츠 프로바이더로부터 실시간으로 잠금화면 컨텐츠 이미지를 생성하고 있어 분당 수백 건의 이미지를 안정적으로 생성하는 것이 가능해야 합니다.  렌더링 서버의 스케일링 이슈를 해결하기 위해 버즈빌에서는 여러 대의 렌더링 서버를 둬서 횡적으로 확장을 함과 동시에, 개별 서버 내에서도 리소스 사용률을 높이기 위해 Ghost Town이라는 라이브러리를 작성해 PhantomJS 프로세스 풀을 구성하여 사용하고 있었습니다(Scaling PhantomJS With Ghost Town ) 한편, 시간이 지나면서 잠금화면에서 렌더링하는 이미지 템플릿의 종류가 다양해지고, emoji 및 여러 특수문자를 표현하기 위해 렌더링 서버에 여러 폰트(대표적으로 Noto Sans CJK)를 설치해야 하는 요구사항이 추가됐는데, PhantomJS에서 폰트 렌더링이 일관적이지 않은 문제가 발생했습니다. 동일한 템플릿이지만 폰트가 비일관적으로 렌더링되고 있는 모습 이 문제의 정확한 원인은 결국 찾지 못했지만 PhantomJS의 이슈였거나 시스템 상에 폰트가 시간이 지나면서 추가 설치됨에 따라 font cache가 서버마다 일관되지 않은 상태가 되었기 때문인 것으로 짐작하고 있습니다. 다른 워크로드와 마찬가지로 렌더링 서버도 최초에는 packer를 이용해 일관되게 이미지를 빌드하고 업데이트하려고 했지만, 자주 기능이 추가되거나 배포되는 서비스가 아니기에 서버를 오래 띄워놓고 수동으로 유지보수를 한 케이스들이 누적되어 더 이상 packer를 이용해 시스템이나 폰트를 최신 상태로 유지하는 것이 어려운 상태였습니다. 모든 눈꽃송이가 자세히 보면 조금씩 다르게 생겼다는 것에서 비롯된 snowflake, 즉 배포된 서버들이 시간이 지남에 따라 조금씩 다른 상태가 된 것입니다. 평소에는 문제가 없어 보이지만, 추가적인 확장성이 필요해 scale out을 하거나 새로운 템플릿을 개발해 배포를 하면 문제가 발생하는 상황이었습니다. 사실 더 큰 문제는 PhantomJS 프로젝트가 더 이상 관리되지 않는다는 점이었습니다. 2017년 Google Chrome 59버전부터 Headless Chrome이 내장되기 시작하였고, 곧바로 Node API인 puppeteer가 릴리즈 되어, 현시점에서 가장 많이 쓰이는 렌더링 엔진을 손쉽게 headless로 사용할 수 있는 환경이 되었습니다. 때문에 PhantomJS 관리자가 사실상의 중단을 선언하였고, 2018년에는 최초 개발자에 의해 프로젝트가 아카이브 되었습니다. 프로젝트가 업데이트되지 않는 것은 템플릿에 최신 CSS 스펙을 사용하지 못한다는 것을 의미하고, 버그 수정도 되지 않기에 어플리케이션의 유지보수가 굉장히 어려워짐을 의미합니다. 현재까지의 문제점을 정리하면 아래와 같습니다.  자주 배포되지 않는 서비스 특성으로 인한 서버들이 snowflake화 되는 현상(특히 폰트) PhantomJS의 개발 중단으로 인해 버그 픽스 및 최신 CSS 속성 사용이 어렵게 되고, 향후 유지보수나 새로운 템플릿 개발이 어려워짐  해결방안은 명확했습니다. 첫번째 문제를 해결하기 위해서는 어플리케이션과 폰트가 설치된 시스템을 통째로 컨테이너로 만들고, CI/CD 파이프라인을 통해 지속적으로 빌드하여 snowflake화 되지 않도록 하면 됩니다. 사실 최초에 packer를 이용해 AMI 이미지를 생성하도록 구성이 되어있었기에, 매 배포마다 AMI를 새로 생성하고 지속적으로 렌더링 서버를 배포하는 환경이기만 했으면 snowflake를 방지할 수 있었을 것입니다. 하지만 자주 기능이 추가되거나 배포되는 서비스가 아닌데다, AMI를 빌드하는 과정이 CI/CD에 통합돼 있지 않고 어플리케이션만 지속적으로 배포하는 환경이었기에 편의상 서버를 종료하지 않고 장기간 관리를 해 오게 되었고, packer로 새로운 AMI 이미지를 빌드하는 것이 어려워 졌습니다. 때문에 AMI 빌드를 통한 배포 대신, 이미 운영 중인 kubernetes 클러스터에 도커 컨테이너를 빌드해 immutable한 형상으로 배포하기로 결정하였습니다. 두번째 문제의 간단한 해결책은 PhantomJS를 puppeteer로 변경하는 것입니다. 이 부분은 생각보다 간단했습니다. 의도했는지는 알 수 없으나 puppeteer의 api는 PhantomJS와 꽤나 비슷합니다. drop-in replacement까진 아니지만, PhantomJS api 호출하는 부분만 살짝 바꿔주는 정도로 교체가 가능하였습니다. 물론 교체만 하였다고 해서 기존에 개발된 템플릿이 의도된 대로 출력되는 것을 보장하지는 않기에, 렌더링 서버가 렌더링하는 수많은 템플릿들을 PhantomJS와 puppeteer로 각각 출력하여 일일히 비교하는 작업이 필요했습니다. 어떤 템플릿이 어떤 인자를 필요로하며 의도된 출력 결과가 무엇인지에 대한 정의가 남아있지 않았기에 템플릿마다 샘플 케이스들을 생성하는 작업이 필요했습니다. 아직까지는 수동으로 결과를 비교해야하는 문제점이 있지만 적어도 직접 확인할 수 있는 것은 큰 도움이 되었습니다. 향후에는 자동화된 테스트 케이스를 구성하여 기능 개발이 좀 더 용이하도록 보완할 계획입니다. 결과는 만족스러웠습니다. 많은 경우 기존과 출력 결과가 달랐지만, 최신의 크롬 웹킷이 사용되면서 오히려 템플릿을 개발할 때 의도했던대로 CSS를 더 정확하게 렌더링하게 된 것이었습니다.  FROM node:10-slim RUN apt-get update && \ apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \ libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \ libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \ libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \ fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst ttf-freefont \ ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget unzip && \ wget https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64.deb && \ dpkg -i dumb-init_*.deb && rm -f dumb-init_*.deb && \ apt-get clean && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* RUN yarn global add puppeteer@1.10.0 && yarn cache clean ENV NODE_PATH="/usr/local/share/.config/yarn/global/node_modules:${NODE_PATH}" RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser # Set language to UTF8 ENV LANG="C.UTF-8" RUN wget -P ~/fonttmp \ https://noto-website-2.storage.googleapis.com/pkgs/NotoSans-unhinted.zip \ https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip \ https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKkr-hinted.zip \ https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKtc-hinted.zip \ https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKsc-hinted.zip \ https://noto-website-2.storage.googleapis.com/pkgs/NotoColorEmoji-unhinted.zip \ && cd ~/fonttmp \ && unzip -o '*.zip' \ && mv *.*tf /usr/share/fonts \ && cd ~/ \ && rm -rf ~/fonttmp WORKDIR /app # Add user so we don't need --no-sandbox. RUN mkdir /screenshots && \ mkdir -p /home/pptruser/Downloads && \ mkdir -p /app/node_modules && \ chown -R pptruser:pptruser /home/pptruser && \ chown -R pptruser:pptruser /usr/local/share/.config/yarn/global/node_modules && \ chown -R pptruser:pptruser /screenshots && \ chown -R pptruser:pptruser /usr/share/fonts && \ chown -R pptruser:pptruser /app # Run everything after as non-privileged user. USER pptruser RUN fc-cache -f -v COPY --chown=pptruser:pptruser package*.json /app/ RUN npm install && \ npm cache clean --force COPY --chown=pptruser:pptruser . /app/ ENTRYPOINT ["dumb-init", "--"] CMD ["npm", "start"]  puppeteer를 사용하면서 약간의 권한 문제가 있어서 결과적으로 위와 같은 Dockerfile을 작성하게 되었는데, puppeteer 도커 이미지 작성에 관한 최신 정보는 여기서 확인할 수 있습니다. 컨테이너 오케스트레이션(K8s)을 사용하면 process 기반의 스케일링은 컨테이너를 여러대 띄워 로드밸런싱을 손쉽게 할 수 있지만, 개별 컨테이너의 throughput을 향상시키기 위해 기존에 Ghost town을 작성해 PhantomJS 프로세스 풀을 만든 것처럼 크롬 프로세스 풀을 구성하기로 하였습니다. 프로세스 풀 구성에는 generic-pool 라이브러리를 사용하였으며 아래처럼 구성하였습니다.  const puppeteer = require("puppeteer"); const genericPool = require("generic-pool"); const puppeteerArgs = ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"]; const createPuppeteerPool = ({ max = 5, min = 2, maxUses = 50, initialUseCountRand = 5, testOnBorrow = true, validator = () => Promise.resolve(true), idleTimeoutMillis = 30000, ...otherConfig } = {}) => { const factory = { create: async () => { const browser = await puppeteer.launch({ headless: true, args: puppeteerArgs }); browser.useCount = parseInt(Math.random() * initialUseCountRand); return browser; }, destroy: (browser) => { browser.close(); }, validate: (browser) => { return validator(browser) .then(valid => Promise.resolve(valid && (maxUses <= 0 || browser.useCount < maxUses xss=removed xss=removed xss=removed> genericAcquire().then(browser => { browser.useCount += 1; return browser; }); pool.use = (fn) => { let resource; return pool.acquire() .then(r => { resource = r; return resource; }) .then(fn) .then((result) => { pool.release(resource); return result; }, (err) => { pool.release(resource); throw err; }); }; return pool; }; module.exports = createPuppeteerPool;  Caveats PhantomJS에서 puppeteer로 전환함에 있어서 몇가지 주의해야 할 점이 있었는데요. 첫째는 기존에 사용하던 템플릿의 html에 이미지 소스를 file:// url 프로토콜을 이용해 로드하는 경우가 있었는데, PhantomJS에서는 정상적으로 로드가 되지만 Headless Chrome에서는 보안 정책으로 인해 로컬 파일을 로드할 수 없었습니다(관련 이슈). 때문에 로컬 이미지가 필요한 템플릿은 Express 서버에서 static file serving을 하도록 하고 http:// 프로토콜로 변경하였습니다. 다음으로 발생한 문제는 PhantomJS을 이용한 기존 구현에서는 jade template을 compile한 후 page 객체의 setContent 메소드를 이용해 html을 로드하였는데, puppeteer에서는 page#setContent API 호출 시 외부 이미지가 로드될 때까지 기다리지 않는다는 점입니다. puppeteer 에 올라온 관련 이슈에서는 `=setContent`= 대신 아래와 같이 html content를 data URI로 표현하고 page#goto의 인자로 넘기면서 waitUntil 옵션을 주는 방식을 해결방법으로 권하고 있습니다.  await page.goto(`data:text/html,${html}`, { waitUntil: 'networkidle0' });  이 때 주의해야 할 점은 waitUntil의 옵션으로 networkidle0이나 networkidle2 등을 사용하면 외부 이미지가 충분히 로드될 때 까지 기다리는 것은 맞지만, 500ms 이내에 추가적인 네트워크 커넥션이 발생하지 않을 때까지 기다리는 옵션이기 때문에 외부 이미지가 로드되더라도 추가적으로 500ms를 기다리게 됩니다. 때문에 SPA 웹페이지를 캡쳐하는 경우가 아니라 정적인 html을 로드하는 경우라면 `load` 이벤트로 지정하면 됩니다. 이외에도 향후에 프로젝트의 유지관리나 운영 중인 서비스의 모니터링을 위해 Metrics API 엔드포인트를 만들어 prometheus에서 메트릭을 수집할 수 있도록 하고 grafana 대시보드를 구성하였습니다. 이 대시보드는 어떤 템플릿이 실제로 사용되고 있는지, 템플릿 렌더링에 시간이 얼마나 소요되는지 등을 모니터링할 수 있도록 구성하여 사용되지 않고 있는 템플릿을 판단하거나 서비스 지표를 모니터링 하는 데 이용하고 있습니다. grafana와 prometheus를 이용해 구현한 렌더링 서버 모니터링 대시보드. 마치며 최근에 들어서는 PhantomJS를 사용하던 많은 곳에서 puppeteer로의 전환을 해오고 있어 본 포스팅에서 다루고 있는 내용이 크게 새로운 내용은 아닐 수 있습니다. 하지만 버즈빌에서는 렌더링 서버가 과거에 이미 PhantomJS를 사용하는 것을 전제로 상당한 최적화가 진행되어 왔고, 꽤나 높은 동시 처리량이 요구되는 상황에서 puppeteer로 교체를 해버리기에는 여러 불확실한 요소들이 존재하는 상황이었습니다. 버즈빌의 핵심 비즈니스 중 하나인 잠금화면에 사용되는 이미지를 렌더링하는 서비스가 레거시(개발이 중단된 PhantomJS)에 의존하는 코드베이스 때문에 변경이 어려워지는 것은 향후 꽤나 큰 기술부채로 작용할 것이라 판단하였습니다. 이번 마이그레이션을 진행하면서는 이 부분을 염두에 두고 컨테이너를 사용해 CI/CD 파이프라인을 구축해 지속적으로 컨테이너 기반의 이미지를 생성하도록 변경하였고, 그 결과는 꽤나 만족스러웠습니다. 마이그레이션 이후 그간 밀려 있던 신규 템플릿 개발이나 신규 컨텐츠 프로바이더를 추가하는 과정이 수월해졌기 때문입니다. 빠르게 변화하는 비즈니스 요구사항에 대응하다보면 기술부채는 필연적으로 쌓일 수밖에 없습니다. 개발자에게는 당연히 눈에 보이는 모든 기술부채들을 청산하고 싶은 욕구가 있지만 늘 빚 갚는데 시간을 쓰고 있을 수만은 없는 노릇입니다. 리소스에는 한계가 있으니까요. 어떤 기술부채를 지금 당장 해결해야하는지 의사결정을 하는데 있어 고민이 된다면 일단 “측정”을 해보는 것을 권장합니다. 수치화된 지표가 있다면 당장 의사결정권자나 팀을 설득하는 데 사용할 수도 있지만, 서비스의 핵심 지표들을 하나 둘씩 모니터링 해나가다 보면 서비스에 대한 가시성이 높아지고 미래에 정말로 병목이 되는 지점을 찾아내기 쉬워질 것입니다. 참고 자료  https://docs.browserless.io/blog/2018/06/04/puppeteer-best-practices.html https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md Icons made by Freepik from Flaticon is licensed by Creative Commons BY 3.0    *버즈빌에서 개발자를 채용 중입니다. (전문연구요원 포함)작가소개 Liam Hwang, Software Engineer 버즈빌에서 DevOps를 담당하고 있습니다. Cloud Native 인프라를 구현하기 위해 여러 노력을 기울이고 있으며 새로운 기술들을 공부하는 것을 좋아합니다.
조회수 1149

MySQL에서 RDS(Aurora) 로 이관하기

안녕하세요. 스티비팀 서버 개발자 이학진 입니다. 저희는 최근 서비스에서 사용 중이던 MySQL DB를 RDS로 이관하는 작업을 진행하였습니다. 무엇 때문에 이관을 결정하게 되었는지와 어떻게 이관을 진행하였는지에 대해 글을 써보도록 하겠습니다.배경stibee.com은 작년 11월에 정식 오픈한 새내기 이메일 마케팅 서비스 입니다. 사실 오픈 초기부터 얼마전까지만 해도 AWS EC2의 m4.large 인스턴스 하나로 운영되던 서비스였습니다.(사실 웹+API 서버 1대, 메일발송서버 1대)그리고 이 싱글 인스턴스에 무려 6개의 서버, mysql 1개, kafka 1개, redis 1개가 돌고 있었습니다. 그럼에도 불구하고 cpu사용률은 20%를 넘지 않았습니다.하지만 최근 사용자도 점점 늘어났고, 네이버에서 메일 수신정책을 변경하면서 메일발송서버에 대한 요청이 급증했습니다.스티비에서 네이버로 대량메일을 발송했을 때 해당 메일의 본문 링크를 자동검사하는 것을 발견했는데요, 따라서 네이버로부터 비정상적으로 많은 요청이 들어오고 있었습니다. (어떤 기준으로 이런 검사를 하는 것인지 정확한 정책은 아직 모릅니다. 담당자분 이 글을 보신다면 연락주세요. 친하게 지냈으면 합니다#슬로워크 #스티비 #개발 #서버개발 #개발환경 #MySQL #인사이트

기업문화 엿볼 때, 더팀스

로그인

/