스토리 홈

인터뷰

피드

뉴스

조회수 2096

AWS S3를 이용하여 Vue 배포하기

Vue를 처음 만났을 때, 이것으로 무엇을 할 수 있을지 궁금했다. 하지만 Vue로 데모 앱과 개발 가이드를 따라하면서 의문은 점점 풀렸다. 알다시피 Vue는 front-end 로 활용이 된다. 빌드가 없어도 되고, 빌드를 해서 배포할 수도 있다. Vue는 일반 CDN을 이용하여 페이지를 만드는 방법과 여러 프레임워크를 활용하여 배포하는 방법 외에 다양한 방법이 존재하는데, 무슨 방법을 쓰든 결과물은 html과 js, css 같은 static 파일로만 이루어져 있다.처음에는 일반적인 방법으로 테스트하면서 다양한 디렉티브와 손쉽게 DOM 처리를 하는 방법을 익혔다. 나중엔 프로젝트에 참여하면서 webpack 으로 빌드해 배포하도록 프로젝트를 구성했다. webpack을 이용한 배포방법은 여기 를 참고하면 된다. 참고로 webpack은 nodeJS로 실행되기 때문에 기본적인 환경을 세팅해야 한다.webpack build.js 일부위처럼 직접 스크립트를 만들어서 사용해도 되지만 Vue에서 제공하는 템플릿으로 프로젝트를 생성할 수도 있다. 단 Vue-CLI가 미리 설치되어 있어야 한다.터미널에서 vue init webpack 프로젝트명만 치면 세팅된 템플릿으로 폴더 및 스크립트들이 구성된다. 아래와 같이 프로젝트의 기본 속성들을 입력하자.프로젝트를 만들면 기본적인 파일들로 이루어진 폴더가 생성된다. 현재는 관련 라이브러리들이 없는 상태이므로 npm install 을 통해 설치한다. 설치 후 nom run dev 로 개발모드를 실행하면 브라우저로 화면을 볼 수 있다. 만약 설치하고 빌드 설정을 수정하지 않았다면 기본 8080 포트로 가동된다. 브라우저를 실행해 http://localhost:8080 으로 접속하면 아래와 같은 화면이 나온다.여기까지 하면 webpack 으로 배포할 수 있는 상태가 되었다. 이제 AWS로 가서 회원가입을 하고 S3를 생성한다. 생성 방법은 여기를 참고하면 된다. 버킷까지 생성되었다면 이제 빌드 후 업로드하자.위와 같이 nom run build 를 하면 빌드가 시작된다.빌드가 완료되면 해당 프로젝트 폴더에 dist 폴더가 생성된다. dist 폴더에는 index.html 과 js, css 와 같은 리소스들이 들어간다. 이제 S3로 가서 올리려는 버킷을 클릭하자.업로드 버튼을 클릭하고, dist 폴더에 있는 index.html 과 static 폴더를 업로드한다. 폴더가 업로드되면 아래와 같이 파일과 폴더들이 보인다.업로드가 완료되었다고 지금 바로 웹사이트처럼 접근할 수는 없다. 정적 웹사이트 호스팅 설정을 활성화해야 비로소 가능하다. 속성 탭을 클릭해 정적 웹사이트 호스팅을 활성화 상태로 만든다.위와 같이 활성화하고 인덱스 문서에만 index.html 을 입력한 후 저장 버튼을 클릭한다. 현재 보이는 엔드포인트 주소가 외부에서 접근할 수 있는 사이트 도메인이다. 그 후 엔드포인트 주소로 접속하면 아래와 같이 오류 페이지를 볼 수 있다.이게 무슨 오류란 말인가… index.html 파일도 있는데 403 오류라니..자세한 http 응답코드는 여기를 참고하면 된다. 위의 오류는 권한이 없어서 파일에 액세스할 수 없다는 페이지다. S3는 기본적으로 모두에게 공개하진 않는다. 그래서 특정 파일이나 특정 버킷만 공개형으로 변경해줘야 한다.이 문제를 해결하려면 권한 탭으로 이동해 버킷 정책을 설정해야 한다. 아래와 같이 설정해주면 누구에게나 공개되어 접근할 수 있다.위 내용을 아래와 같이 버킷 정책으로 설정한다.설정을 저장한 후 다시 엔드포인트로 접속하면 아래와 같이 로컬에서 보였던 페이지가 보인다.이렇게 보이면 성공!다음엔 Vue가 어떤식으로 동작을 하는지 알아보도록 하겠다.마치며Vue는 간결하면서도 강력한 기능을 가지고 있는 front-end 프레임워크다. 개념과 디렉티브, 이벤트 핸들링, 보안 등 궁금한 게 많았지만 신통방통한 놈인 건 확실하다. 아직 큰 프로젝트에 사용하는 건 힘들 수도 있으나 아래와 같이 장점이 많아 서버단과 클라이언트단 분리 개발, 외부 라이브러리와 사용하면 훌륭한 프레임워크가 될 거라는 생각이 든다.재사용 가능한 기능별 컴포넌트 개발훌륭한 라우터 탑재서버와 통신 가능한 ajax 모듈이 다양함 ( jQuery Ajax, Axios )다양한 호환 라이브러리를 활용하면 분명 훌륭한 프레임워크가 될 것!편집자 주) 함께 보면 좋아요!Vue, 어디까지 설치해봤니?PHP Codeigniter 환경에서 VUE 사용해보기JQuery 프로젝트에 VUE를 점진적으로 도입하기Vue와 Vuex, 컴포넌트간 통신과 상태 관리글장현준 팀장 | R&D 개발3팀[email protected]브랜디, 오직 예쁜 옷만
조회수 254

컴공생의 AI 스쿨 필기 노트 ③ K-평균 군집화

AI 스쿨 3주차에서는 K-means clustering(K 평균 군집화)에 대해 배웠어요. 이에 대해서 간략하게 정리해볼게요.K-means clustering클러스터링이란 군집화를 의미하는데요, K-means clustering은 비슷한 데이터끼리 묶어주는 머신 러닝 기법이에요. K-means clustering은 비지도학습(Unsupervised learning)의 일종이에요. 비지도 학습이란 데이터와 각각의 데이터가 무엇인지를 설명해주는 라벨이 없는 학습을 말해요. 따라서 우리는 주어진 데이터들을 가장 잘 설명하는 클러스터를 찾아 데이터를 분류할 수 있어요. 아래는 데이터를 2개의 클래스로 군집화한 것을 잘 나타내주는 그래프에요.K-means는 클러스터 내부에 속한 데이터들이 서로 가깝다고 정의해요. 그렇다면 같은 클러스터에 속한 데이터들은 서로 가까이 근접해 있겠죠? K-means는 클러스터의 중심으로부터 가까운 데이터들을 찾아서 묶어주는 알고리즘이에요. 데이터들은 가장 가까운 내부 거리를 가지는 클러스터를 고르게 되는데, 이를 위해서 각각의 클러스터는 중심(프로토타입)이 존재하고 각각의 데이터가 그 중심과 얼마나 가까운지를 Cost로 정의해요.위의 식은 같은 클러스터에 속하는 각각의 점들로부터 그 클러스터의 평균(프로토타입)과의 거리의 합을 제곱한 함수에요. - N : 데이터의 개수- K : 클러스터의 개수- uk : k 번째 클러스터의 중심(프로토타입)- rnk : n 번째 데이터가 k 번째 클러스터에 속하면 1, 속하지 않는다면 0을 가지는 이진 변수우리는 위 식에서 rnk, uk를 구해야 해요. 이때 반드시 잊지 말아야 하는 조건은 각 데이터가 한 개의 클러스터에 할당이 되어야 한다는 것이에요.K-means 알고리즘K-means algorithm을 구하는 방법은 아래와 같이 크게 2단계로 나누어져요. 먼저 uk에 랜덤 값을 사용하여 임의의 초깃값을 설정해요.1. Expectationuk를 고정시키면서 J를 최소화하는  rnk값을 지정해야 하는데,  rnk은 모든 데이터 n에 대해 각각 모든 클러스터 중에서 xn- uk가 가장 작은 클러스터에 할당해요.2. Maximization새롭게 얻어진 rnk를 고정하고 uk는 k 번째 클러스터의 mean을 계산해요. 두 값이 적당한 범위 내로 수렴할 때까지 계산을 반복해요, 위의 두 단계를 각각 E(expectation) 단계와 M(maximization) 단계라 하고, 이 두 단계를 합쳐서 EM 알고리즘이라고 해요.알고리즘 코드로 나타내기그럼 K-means algorithm을 코드로 어떻게 나타내는지 살펴볼게요!Step1. 데이터 만들기np.random.seed(42)digits = load_digits()  data = scale(digits.data)n_samples, n_features = data.shapen_digits = len(np.unique(digits.target))labels = digits.targetx_train, x_test, y_train, y_test = train_test_split(data, labels, test_size=0.25, random_state=42) - digits = load_digits(): load_digits 함수를 사용하면 data와 target이 반환되는데 이 데이터를 scale 함수를 사용하여 전처리해요.- data.shape을 사용하면 n_samples에는 1797, n_feature에는 64가 할당돼요.- n_digits에는 digits의 target의 중복된 값을 제외한 개수를 할당해요.- train_test_split() 함수를 이용하여 train_set과 test_set을 랜덤 시드를 42를 가지는 75:25의 비율로 나눠요.Step2. KMeans model 만들기sklearn 라이브러리를 사용하면 KMeans model을 아주 쉽게 구현할 수 있어요.kmeans = KMeans(init='k-means++', n_clusters=10, random_state=42)clusters = kmeans.fit_predict(x_train)- KMeans 함수를 이용하여 모형은 k-means++를 가지고, cluster는 10개를 가지며 랜덤 시드는 42를 가지는 K-means clustering을 만들어요.- x_train 데이터 셋을 중심으로 클러스터의 중심을 계산하고 각 샘플에 대한 클러스터의 인덱스를 예측할 수 있도록 fit_predict()를 사용해요.Step3. K-means clustering 결과 출력print('Clusters: ', clusters)위와 같이 출력하면 아래와 같은 결과가 나와요.Clusters: [1 3 2 ... 6 6 0]]그래프를 출력하면 아래와 같은 결과를 볼 수 있어요!이번 수업에 배운 K-means clustering의 개념은 1주차와 2주차 수업의 개념에 비해 어렵지 않았던 것 같아요. 이해하기에 큰 문제는 없었지만 코드로 직접 짜려고 하니 막히는 부분이 있어서 고생을 좀 했어요. 저는 과제를 하다가 에러가 나면 구글링을 통해서 에러를 해결하거나 도저히 못하겠다 싶으면 도움 요청을 해요. 목요일에는 조교분들께서 Multiple Regression에 대해 숙명여대에서 수업을 진행해주셨는데요. 1, 2주차에 배운 내용을 복습하고 3주차 수업에서 짧게 살펴본 Multiclassification을 더 자세히 알려주셔서 본 수업 때 이해가 되지 않았던 부분이 해결이 되었습니다! 목요일 수업은 정식 수업이 아닌 보충수업이었기 때문에 소수의 사람들이 강의에 참여했는데요. 시간이 된다면 참석을 꼭 해주시면 굉장히 큰 도움이 될 것 같아요. * 이 글은 AI스쿨 - 인공지능 R&D 실무자 양성과정 3주차 수업에 대해 수강생 최유진님이 작성하신 수업 후기입니다.
조회수 405

iOS 개발자를 구합니다!

“세상 모든 광고영상을 누구나 쉽게 만들 수 있게 한다.”영상광고는 사업의 규모와 업종을 막론하고 모든 분야에서 필수적인 요소로 자리잡고 있습니다. 잘 만든 영상광고가 매출로 이어진다는 사실은 검증되었고, 그 중요성은 나날이 증가하고 있습니다.하지만, 영상제작 전문기술 없이 광고영상을 제작한다는 것은 시간과 비용적인 측면에서 매우 어려운 일입니다. 광고영상을 SNS에 업로드 하고 싶은 마케터나 창업가들은 영상 전문가나 디자이너가 되는 것을 꿈꾸지 않습니다. 단지 자신의 서비스와 제품이 멋지게 홍보될 영상을 원하고 있습니다.더브이플래닛은 전문기술 없이도 누구나 쉽고 빠르게 광고영상을 제작할 수 있는 브이플레이트를 통해 많은 마케터들과 창업가들이 겪는 시간과 비용에 대한 어려움을 해소할 것입니다.“더브이플래닛”에서 영상광고 생태계의 흐름을 바꿀 iOS개발자를 모집합니다.광고영상을 누구나 쉽게 만들 수 있도록 함께 고민하고 시장을 주도해나갈 분을 애타게 찾고 있어요.우리는 한사람 한사람의 소중한 능력들이 맘껏 발휘될 수 있도록 존중과 배려로 서로를 응원하고 있어요. 우리와 함께 소중한 능력을 맘껏 발휘하실 분들의 많은 지원 부탁드려요.
조회수 1177

AWS Lambda + API Gateway로 API 만들어보자

Overview좋은 아침입니다. 오늘은 AWS Lambda와 API Gateway 이용하여 API를 만들어보겠습니다. 서버 구축부터 해야 하지만 이번 글에서 서버는 따로 필요 없습니다. 당황하셨나요? 괜찮습니다. 이 글을 보면 곧 이해가 될 겁니다. 우선 Lambda와 API Gateway부터 알아봅시다. Lambda는 서버를 프로비저닝하거나 관리하지 않고도 코드를 실행할 수 있게 해주는 컴퓨팅 서비스입니다. 브랜디 랩스에는 이미 이것을 활용한 예제가 많은데요. 아마 아래의 포스팅들을 보시면 도움이 될 겁니다.SQS + Lambda: 이상근 팀장님CodeStar + Lambda + SAM으로 테스트 환경 구축하기: 천보성 팀장님API 호출부터 결과 확인까지API Gateway는 규모에 상관없이 API 생성, 유지 관리, 모니터링과 보호를 할 수 있게 해주는 서비스입니다. 이 글에서는 API를 호출해 결과를 확인하는 걸 목표로 진행하겠습니다.최종 API 호출 URL* GET /v1/reviews/{review-no}/comments* POST /v1/reviews/{review-no}/comments AWS(Amazon Web Service) 가입 절차는 생략하겠습니다. 1.AWS 로그인 후 API Gateway 시작!AWS에서도 설명되어 있듯이 API gateway엔 이와 같은 장점이 있습니다.1. API 개발 간소화: 새로운 버전을 신속하게 반복하고, 테스트하고, 출시할 수 있습니다.2. 규모에 따른 성능: 백엔드 시스템에 대한 트래픽 관리하여 유동적으로 API 호출하여 성능을 높이는데 도움이 됩니다.3. SDK 생성: 사용자 지정 SDK를 만들어 애플리케이션에서 신속하게 API를 테스트하고 배포할 수 있습니다. 2.API 생성새 API로 엔드 포인트 유형을 지역으로 선택하여 생성하세요. 엔드 포인트 유형1. 지역 : 현재 리전에 배포2. 최적화된 에지 : CloudFront 네트워크에 배포3. 프라이빗 : VPC에서만 엑세스 가능3.최종 호출 url로 순차적으로 리소스 생성리소스 이름과 리소스 경로를 입력하고 리소스를 생성합니다.리소스는 호출할 수 있는 특정 URL입니다. 생성된 리소스로 /reviews 주소가 만들어졌습니다.다음은 /reviews 주소 뒤에 {review-no}를 생성합니다. 리소스 경로에 {} 가 포함되어 있으면 경로 파라미터를 나타냅니다.마지막 리소스를 생성하게 되면 위의 이미지와 같이 /reviews/{review-no}/comments 리소스가 생성되었습니다. 이제 메서드에 연결할 Lambda 함수를 먼저 생성하겠습니다.4.Lambda 함수 생성GET, POST 메서드에 연결할 각각의 Lambda 함수를 생성합니다.‘Hello from Lambda’ 문자열로 리턴되는 Lambda 함수가 생성되었습니다. 생성된 Lambda 함수를 API Gateway 메서드에 연결해보겠습니다.5.메서드 생성GET, POST 메서드를 생성합니다.메서드의 의미* POST : 새로 생성(Create)* GET : 조회(Read)* PUT : 수정(Update)* DELETE : 삭제(delete)* PATCH : 일부만 수정(Update) 새 메서드의 통합 유형을 Lambda 함수로 선택하고 기존에 생성한 함수명으로 입력한 다음 저장을 누릅니다.메서드 실행 화면입니다. 해당 메서드에 통합 요청할 Lambda 함수가 연결됩니다. 연결된 Lambda 함수를 눌러보겠습니다.왼쪽 목록 트리거 추가하는 부분에 API Gateway가 연결되었습니다. 그럼 이제 정상적으로 호출되는지 테스트해보겠습니다.테스트를 클릭하면 오른쪽에 요청에 대한 결과가 나옵니다. 조금 전에 연결했던 Lambda 함수에 ‘Hello from Lambda’ 값으로 출력됩니다. 이제 리소스로 추가한 경로 파라미터를 매핑하여 출력해보겠습니다.메서드 요청에서는 사용자에게 노출되는 API를 정의할 수 있습니다. 리소스로 경로 파라미터를 추가하게 되면 메서드 요청 -> 경로 요청 부분에 자동으로 추가되어 있습니다.통합 요청에서는 백엔드와의 통신 방식을 지정할 수 있습니다. 메서드 요청에서 보낸 URL 경로 부분을 매핑시켜야 합니다. 명명 규칙은 아래와 같습니다. method.request.{"path" | "querystring" | "header"}.{param_name}매핑 템플릿을 추가하여 수신된 요청을 변환하여 통합 백엔드로 보내야 합니다. 정의된 템플릿이 없기 때문에 매핑 템플릿을 추가한 후 메서드 요청 패스스루로 지정합니다. 그러면 클라이언트가 제공한 요청이 변환없이 통합 백엔드로 전달됩니다.클라이언트가 요청한 경로 파라미터 출력하도록 Lambda 함수를 수정합니다.이제 다시 테스트를 해보겠습니다. 경로에 값을 요청하여 응답 본문에 출력되는 걸 확인할 수 있습니다.6.API 배포스테이지 정보를 입력하고 배포를 클릭합니다.스테이지 상세 정보에 API 호출 주소가 생성됩니다. Postman으로 생성된 API주소를 입력하여 정상적으로 return 값을 확인합니다.Conclusion정말 긴 과정이었습니다. 지금까지 API Gateway를 이용하여 API 생성부터 배포까지 알아봤습니다. API Gateway를 사용하면 서버 없이 높은 확장성을 가진 백엔드 애플리케이션을 구축하고 운영할 수 있게 될 겁니다. 백엔드에 관심이 있는 개발자에게 이 글이 도움이 되길 바랍니다.글곽정섭 과장 | R&D 개발1팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발자 #개발팀 #인사이트 #경험공유
조회수 1709

[H2W@NL] 실패해도 끝까지 간다, COMET팀

네이버랩스의 인재상은 passionate self-motivated team player입니다. 어쩌면 '자기주도적 팀플레이어'라는 말은 형용모순(形容矛盾)일 지도 모릅니다. 하지만 우린 계속 시도했고, 문화는 계속 쌓여갑니다. 다양한 분야의 전문가들이 경계없이 협력하고 스스로 결정하며 함께 도전하는 곳의 이야기를 전합니다. How to work at NAVER LABSH2W@NL 시리즈 전체보기공간 데이터를 디지털라이즈하는 것, 즉 '고정밀 매핑'은 네이버랩스 기술의 시작이 되는 중요한 과제입니다. COMET 프로젝트는 매핑 로봇이나 MMS (mobile mapping system) 차량이 다니기 어려운 복합 지형에서의 매핑 기술을 연구하고, 네이버랩스 매핑 디바이스들의 표준을 개발하는 것을 목표로 합니다. 그런데 이 프로젝트 이전, 많은 시도와 실패가 있었습니다. 물론 실패를 극복해 더 단단한 결과물을 만들어낸다는 아름다운 결말이 현실에서 비일비재하지는 않습니다. 여건도 상황도 이를 쉽게 허락하지 않지만, 무엇보다 사람도 지치기 마련입니다. 그래서 COMET 팀이 더 궁금했습니다. 어떤 일들이 있었는지 들어보았습니다. Q. 어떤 프로젝트인가요?(정은교|TL) 그간의 매핑 디바이스 개발은 주로 고정형이거나 특정 지형에 한정되었죠. 그런데 COMET은 지형 지물에 상관없이 데이터 수집이 가능해야 한다는 것이 전제였습니다. 실내나 도로처럼 규격화된 곳이 아닌 울퉁불퉁한 인도, 계단, 구불구불한 등산로 등등. 지형의 특성과 무관하게 고정밀 데이터를 수집할 수 있어야 합니다. 먼저 백팩 타입 설계를 시작한 이유입니다.프로젝트 이름에 모든 의미가 담겨있다(이성준|PM) 그래서 COMET이라는 프로젝트 명을 정했죠. 우주에는 정해진 궤도를 따라 움직이는 행성들만 있는 것이 아니라 궤도를 가로지르는 혜성도 있죠. COMET 프로젝트는 네이버랩스의 실내 매핑로봇 M1, 도로의 모바일매핑시스템 R1 사이에서 그간 커버하기 힘들었던 공간들을 빈틈없이 연결해주는 역할을 합니다.한 획을 그어보자, 혜성처럼(정성용|하드웨어/펌웨어 설계) 사실 다른 컨셉의 프로젝트들이 계속 있었어요. 그런데 예상치 못했던 내외부 변수들로 여러차례 중단되었죠. 거의 완성 직전인 프로젝트도 있었거든요. 그때 의욕이나 열정이 많이 사라질 뻔 했는데, 성준님이 ‘마지막으로 혜성처럼 회사에 한 획을 그어보자’고 하며 COMET 프로젝트를 제안했던 게 기억나요. 그런 의미의 이름 아니었나요?"COMET 의 핵심 컨셉은 기존의 고정밀 매핑 디바이스들로 접근하기 어려웠던 영역들의 빈틈을 빠짐없이 연결한다는 것입니다. 이동 환경이 비교적 균일한 도로나 실내의 보도에서는 이미 솔루션이 충분한 편입니다. 하지만 아직 고정밀 지도를 만들기 어려운 영역이나 복합 지형들은 여전히 많아요. 그런 곳에서도 COMET을 통해 공간 데이터를 끊김없이 연결할 수 있게 된 것이 가장 큰 성과입니다." 실패라는 것을 팀에서는 어떻게 활용 했나요?실패도 자산화하려면 프로세스가 필요하다(이성준|PM) COMET 이전의 여러 시도와 실패를 통해 깨달은 게 있습니다. 프로젝트의 자산에 대한 것입니다. 중단된다고 그간 쌓아왔던 것이 없어지면 안되죠. 그래서 각 프로젝트를 통해 얻은 경험과 노하우를 자산화하기 위한 프로세스를 만들고자 했습니다. 일단 큰 틀을 잡고, 각 단계는 sprint 방식으로 진행했습니다. 지금 우리가 어디까지 왔는지를 가시적으로 확인할 수 있다는 점도 큰 도움이 되었어요.모든 끝은 새로운 시작으로 연결(천정훈|프로그래밍/하드웨어 설계) 진행되었던 모든 프로젝트 정보들이 정리되고 공개되어 있습니다. 저 역시 이전의 솔루션들을 참고해 개발속도를 높일 수 있었습니다. 이런 정리를 중요하게 생각하는 이유는, COMET이 끝이 아니라 다음 프로젝트로 이어지는 단계라고 생각했기 때문입니다. 애초에 추후 프로젝트에서 활용될 수 있는 기술들에 대한 고려를 많이 하고 있습니다. 예를 들어, 다음 프로젝트에서도 활용할 것을 전제로 각종 센서데이터의 효율적 수집 프로토콜을 설계하거나, circuit board의 펌웨어 업데이트 기능도 적용하여 확장성을 미리 대비해 두는 것이죠.프로세스가 작동하면 일어나는 일(정성용|하드웨어/펌웨어 설계) 저는 사실 COMET도 완료되지 않을 거라 생각했어요. 기술적인 어려움은 아니었어요. 올해 회사의 리더십이나 로드맵이 변화되는 상황에서 이 프로젝트가 안정적으로 끝나는 것이 쉽지 않을 거라 생각했죠. 그런데 그간 쌓인 경험들, 그로 인해 만들어진 단단한 프로세스가 작동하기 시작했습니다. 그래서 모두의 예상보다 빠르게 완료가 되어버렸어요. 정말 말도 안되게 기간 단축이었습니다. 물론, 개발 중엔 하루 하루가 도전이고 위기였죠.담당자라는 개념과 경계를 넘는 것(천정훈|프로그래밍/하드웨어 설계) 분명 개개인이 달성해야 할 목표라는 건 있습니다. 보통 이런 건 명확한 편이죠. 그런데 그것만 각자 잘 한다고 프로젝트가 잘 되는 건 아닙니다. 다른 담당자의 역할이나 완료를 그저 기다리는 것이 아니라, 필요하다고 생각되면 스스로 리드하거나 함께 고민하고 대화했습니다. 팀과 상관없이 해당 분야의 전문가를 찾아 풀어야 할 문제에 대해 편하게 논의할 수 있다는 건 네이버랩스 조직문화의 확실한 강점입니다. 누구든 언제든 쉽게 서로 피드백을 나눌 수 있는 분위기이기 때문에, 고민이 생겼을 때마다 더 잘 해결할 수 있었던 것 같네요.전문가들의 진짜 전문가다운 협업(최문용|GPS 하드웨어 설계) COMET의 GPS 수신이 예상보다 나쁘게 나온 적이 있었어요. 그러면 하드웨어 전문가, 소프트웨어 전문가, GPS 알고리즘 전문가가 총출동합니다. 각각의 전문 분야를 기반으로 다각적으로 관찰하고, 논의하며, 효과적인 대응 방안을 찾으면 기구 파트에서 바로 적용을 해줍니다. 그 결과 우리가 기대하는 성능까지 올릴 수 있었습니다. 그걸 바라보는 저는, 소름이죠! 각자의 업무 경계를 크게 가르지 않고도, 협업을 통해 팀 전체의 전문성을 높일 수 있었어요.너도 코딩 나도 플래닝(정성용|하드웨어/펌웨어 설계) 실제로 우리는 서로의 영역을 구분하지 않고 자연스럽게 영역을 넘나듭니다. 담당자는 정해져 있지만, 그렇다고 개발 및 의사결정을 담당자만 하지 않습니다. 필요하다고 생각되면 누구든 직접 회로를 그려보고, 직접 코드를 작성해보고, 기구를 설계하거나 스스로 프로젝트 계획을 수립합니다.(이재량|기구개발) 물론 현실은 티격태격이죠. 의견 차이가 있을 때는 정말 뜨겁습니다. 서로 화를 내며 논쟁하기도 합니다. (저는 아닙니다) 그런데 결과적으로는 더 좋은 결론에 다다르더라고요. 누구나 자유롭게 의견을 말하고 논쟁할 수 있다는 건 프로젝트 완성도를 위해 정말 중요한 환경입니다. 결국 각자의 분야에서 아주 뛰어난 전문가들이기 때문이죠."전문성을 가진 팀원들간의 자유로운 소통이 주는 장점은 무엇일까요? 각자의 담당 업무 영역이 오버랩되면서 ‘너의 문제’와 ‘나의 문제’라는 경계가 어느 순간 사라진다는 점입니다. 서로의 전문성을 진심으로 인정하고, 서로 다른 분야에 대한 관심과 이해하려는 노력이 있었기 때문에 가능했던 것 같아요. 지금은 농담으로 다음 프로젝트에서 각자 무엇을 담당할지 사다리 타서 정하더라도 프로젝트는 잘 돌아가겠다고 말해요." Q. 앞으로의 목표는?어떤 형태로도 적용 가능한 매핑 디바이스의 표준을 만들 것(정은교|TL) 앞서 말했듯 COMET 프로젝트는 다양한 지형에서 고정밀 공간 데이터를 수집하는 것이 목표였고, 그것이 가능해졌다는 것이 가장 큰 성과입니다. 이 프로젝트를 통해 센서간 조합에서 오는 아주 다양한 문제와 side effect들을 경험하고 해결했습니다. 이러한 정보와 노하우를 바탕으로 네이버랩스 매핑 디바이스들의 표준화를 준비하고 있습니다. 그래야 이후의 많은 매핑 프로젝트에 빠르고 효율적으로 대응할 수 있습니다.(이성준|PM) 실제로 COMET은 그 자체로 끝이 아닙니다. 실제 운용 시간과 환경을 늘려가며 테스트하면서 새로운 개선점을 발견하게 될 것이고, 이러한 과정을 통해 더 다양한 환경과 머신에 적용할 수 있는 확장성 있는 시스템으로 발전시킬 수 있을 것입니다.(이재량|기구개발) 처음에는 기존에 해보지 않았던 타입을 개발해야 한다는 점에서 초기 컨셉 단계부 터 막막했습니다. 지금은 어느새 새로운 소재나 구조를 검토하며 업그레이드를 위한 테스트를 지속하고 있는 상태입니다. 계속 버전업되는 COMET을 기대해주세요.과거의 자산을 잃지 않기 위해 단단한 근간을 마련한다(정성용|하드웨어/펌웨어 설계) 결국 우리가 COMET을 통해 얻어낸 가장 큰 것은, 우리만의 매핑 디바이스 표준을 만들어가고 있다는 점이 아닐까 생각합니다. 앞으로 네이버랩스에서 개발될 매핑디바이스는 그 형태나 목적이 어떻게 되더라도 COMET이 근간이 됩니다. 이제는 프로젝트 방향이 달라질 때마다 컨셉을 새로 설계하는 방식을 벗어나, 그간의 자산을 하나도 잃지 않은 상태에서 지금 가장 효과적인 방식의 매핑 디바이스를 만들 수 있습니다. 이러한 결과를 위해 필요했던 과거의 실패들이었던 것 같습니다.
조회수 945

맛있는 인터뷰: 잔디 그로스 팀 개발자, Hugo

 역삼 맛집▲ 금강산도 식후경이라 했던가? 맛있는 인터뷰가 맛있는 이유는 늘 음식과 함께 하기 때문이다오늘 온 맛집. 분위기가 심상치 않다. 어떤 곳인지 소개해달라. Hugo(이하 ‘휴’): 역삼역 근방에 있는 ‘산촌’이란 곳이다. 얼마 전 버디런치 장소 물색을 위해 ‘다이닝코드’로 역삼역 주변 한식집을 찾던 중 발견했다. 예로부터 어르신들이 찾는 곳은 맛집이라는 얘기가 있다. 보면 알겠지만 어르신들이 많다. 괜찮은 가격에 건강한 음식을 섭취할 수 있는 곳이라 많은 듯 하다. 그리고.. 우리도 건강을 챙겨야 하는 나이다. 몸에 좋은 곤드레밥, 메밀 전병을 먹으며 함께 하는 건강한 인터뷰가 되었으면 하는 바람에 이 곳을 선택했다.깔끔한 답변 고맙다. 이제 본인 소개를 부탁한다. 휴: 반갑다. 개발자 Hugo다. 잔디 그로스 팀(Growth Team)에서 로우 데이터(Raw data) 가공, 분석을 통해 유의미한 지표를 보여주는 데이터 분석 툴 ‘스프링클러’를 개발하고 있다. 잔디 멤버들 사이에서 유독 명성이 자자하다 휴: 여러분의 관심을 먹고 자라는 임무를 수행하다 보니 그런 듯 하다. Hannah, Jihoon, Jane 등과 함께 GWP 팀으로 활동해서 많이들 알아봐 주시고 격려해주시는 것 같다. * GWP 팀? GWP는 Great Working Place의 줄임 말이다. 단어 그대로 물리적+비물리적 최고의 업무 공간을 만들기 위해 TF팀 형태로 구성된 그룹이 다양한 활동을 한다. 예를 들면, 할로윈 파티 개최부터 탕비실 냉장고 음식 채우기 등 업무 환경 개선을 위해 크고 작은 일을 수행한다. ‘비선실세’라는 얘기도 돌던데? 휴: 천부당 만부당한 말씀이다. 그저 잔디를 사랑하는 멤버 중 한 명이다.스프링클러? 휴: 잔디 그로스 팀에서 자체적으로 만든 분석 툴이다. 쉽게 말하면 잔디 데이터 분석과 가공에 최적화된 잔디 전용 구글 어널리틱스(Google Analytics)로 보면 된다. 스프링클러를 통해 잔디 DAU(Daily Active User) 파악, 마케팅 채널 별 효율 측정, 유저 별 사용량 측정 등을 할 수 있다.  스프링쿨러▲ 잔디의 모든 데이터를 가공, 분석해 보여주는 스프링클러잠깐! 유저 별 사용량 측정도 스프링클러를 통해 가능하다고 했는데 잔디 팀이 유저의 모든 정보를 열람하는 건가? 휴: 많은 분들이 오해할 수 있을 것 같은데 그렇지 않다. 스프링클러에서 열람할 수 있는 유저 별 사용량 확인은 특정 채널을 통해 유입된 유저가 메시지를 몇 건 보내고, 파일 업로드를 얼마나 하는지 정도다. 유저가 어떤 메시지를 주고 받는지, 어떤 파일을 올리는지 등 개인 정보는 원칙적으로 잔디 팀이 접근할 수 없다.   스타트업은 시간과 리소스 관리가 생명이다. 구글 어널리틱스와 같은 훌륭한 툴이 있는데 굳이 자체 데이터 분석 툴을 만든 이유가 무엇인지? 휴: 날카로운 질문이다. 나도 처음에 왜 스타트업에서 데이터 관련 팀을 꾸려 분석 툴을 만들려고 하는지 이해가 가지 않았다. 하지만 좀 더 생각해보니 잔디에서 발생한 데이터에 특화된 분석 툴이 있어야 정확한 결과를 얻을 수 있고, 이를 통해 스타트업 특유의 린(Lean)한 개발이 가능할거란 결론에 도달하였다.   듣기엔 스프링클러의 사용성과 분석 능력이 뛰어나 독자 서비스로 나오는 것 아니냔 루머가 있었다. 사실인가? 휴: 하하. 루머일 뿐이다. 다만 그런 생각을 갖고 그로스 팀과 최선을 다해 스프링클러 개발을 하고 있다. 어쨌든 좋게 봐주셔서 이런 루머가 나온 것 같아 담당자로서 기쁘다.   스프링클러에 애정이 많을 것 같다 휴: 내게 잔디도 소중하지만 스프링클러도 무척 중요하다. 소박한 꿈이 있다면 스프링쿨러가 내가 없어도 100% 완벽히 잘 돌아가게 만들고 싶다. 물론, 분석 툴로서 멤버들이 원하는 결과를 보여줄 수 있도록 정교하게 만드는 것도 중요하다.   그로스 팀은 과거 ‘맛있는 인터뷰’의 Kevin을 통해 소개한 바 있다. 당시 개발자 중 몇 명을 차출해 그로스 팀에 합류시킨 걸로 알고 있는데 여러 개발자 중 Hugo가 차출된 이유가 있다면? 휴: 평소 데이터 마이닝 분야에 관심이 많아 대학원에서 관련 공부를 하기도 했고, 그로스 팀 초창기 모든 업무를 책임지던 팀장 겸 팀원 Kevin이 추천해 팀에 합류하게 되었다. 아, 그로스 팀 오기 전엔 백엔드(Back-end) 개발자 포지션으로 있었다. 팀을 옮길 땐 백엔드 개발자들로부터 ‘배신자’란 오명과 함께 모진 고문과 학대를 받았다. 하하.. 농담이다.   다른 얘기를 해보자. 잔디에 어떤 이유로 조인했는지 궁금하다 휴: 건방진 말일 수 있지만 내 의지대로 무언가 만들고 싶었다. 대한민국 수 많은 개발자들이 그렇겠지만 회사에서 내가 할 수 있는 건 생각보다 한정돼 있다. 아이디어를 내도 예산 때문에 혹은 기타 다른 이슈 때문에 반려되기 일쑤였다. 어떻게 보면 그런 현실에 대한 반발심으로 잔디를 선택한 게 가장 크다고 볼 수 있다.   잔디에서는 생활은 만족스러운가? 휴: 70% 정도?   왜 70%인가? 휴: 장-단점이 있지만 장점이 조금 더 크기 때문에?   그럼 장점부터 말해보자 휴: 합당한 이유가 있다면 내가 하고 싶은 일을 진행할 수 있다는 점이 큰 장점이다. 그 일을 실행하기까지 절차도 이전까지 다녔던 회사 대비 상당히 간소화되어 있어 부담감도 적다. 각 분야에서 두각을 드러낸 사람들과 함께 일하고 있다는 점도 매력적이다. 다들 자부심을 갖고 일하고 있어 자극을 받는다.   단점은? 휴: 장점이 때에 따라 단점으로 보일 때도 있다. 논리적인 어프로치가 필요할 때도 있지만 분명 전쟁터로 돌진하는 돌격병 같은 저돌성이 필요할 때도 있다. 그럴 땐 일부터 치고 보는 자세가 필요한데 그 때를 놓치는 경우가 눈에 보여 개인적으로 아쉽다.   스트레스는 어떻게 푸는지? 휴: 주말에 13시간 이상 잔다. 밤에 10시간, 낮에 3시간. 남는 시간엔 수영이나 등산을 한다.   등산? 휴: 집 바로 뒤에 나지막한 산이 있다. 평소 자연을 좋아하는데 등산을 하다 보면 산의 나무나 풀, 바람을 보고 즐길 수 있어 좋다.   생각보다 감성적인 남자라 당황스럽다 휴: ^^ ▲ 감성적인 남자로 보이는 그는 한 때 해병대 전우였다.수영은 시작한지 얼마 안됐다고 들었다 휴: 작년 10월부터 시작했다. 이제 갓 1년이 넘었다. 작년 초부터 체력적으로 처진 것 같은 느낌이 들어 이대론 안되겠다 싶어 수영을 시작했다. 등산과 함께 꾸준히 하는 운동 중 하나다.   꾸준히 운동하고 있는데 달라진 점이 있다면? 휴: 몸도 몸이지만 정신적으로 건강해졌다. 확실히 체력이 떨어지면 부정적인 생각을 하는 경향이 있는 것 같다. 운동을 시작하기 전과 후의 마음 상태가 정말 많이 다르다. 앞으로도 꾸준히 운동을 할 생각이다.   곤드레밥과 함께 한지 벌써 1시간 가까이 됐다. 인터뷰 질문도 다 소진되어 이전 맛있는 인터뷰 주인공이었던 David이 남긴 질문을 묻고 싶다 휴: 준비됐다.   잔디 멤버 중 전생에 공주나 왕자였을 것 같은 사람은? 휴: 왕자는 디자인 팀의 Ben. 도도하고 말수도 적고. 공주는 디자인 팀의 Yujin (A.K.A Summer)? 얘기는 많이 안 해봤지만 말도 고급스럽게 하는 것 같다. 두 사람 모두 괜찮은 사람들이라 이번 인터뷰를 통해 점수를 따보고 싶다.   전략적인 답변 감사하다 휴: ^^   마지막 질문이다. ‘맛있는 인터뷰’의 백미는 다음 인터뷰이에게 현재 인터뷰이가 질문을 남기는 것이다. 다음 사람에게 묻고 싶은 질문이 있다면? 휴: 잔디 멤버 중 내 주변 괜찮은 남자 사람이나 여자 사람을 소개시켜주고 싶은 사람은?   오늘 맛있는 곤드레밥 덕분에 잘 먹었다. 계산은 인터뷰이가 한다는 거 다시 한번 더 상기시켜 드리며 인터뷰 마무리하겠다 휴: …^^#토스랩 #잔디 #JANDI #개발 #개발자 #개발팀 #인터뷰 #팀원 #팀원소개 #팀원인터뷰 #기업문화 #조직문화
조회수 1112

Single Layer Perceptron

Single Layer Perceptron이번 포스팅에서는 모든 인공신경망의 기초가 되는 perceptron의 개념에 대해서 배워보고, 이를 이용한 단층 퍼셉트론 구조를 구현해보도록 하겠습니다.퍼셉트론은 여러분이 고등학교 과학시간에 한 번쯤은 들어보았을 인간의 신경망, 뉴런으로부터 고안되었습니다. 퍼셉트론은 여러 개의 신호를 입력받으면, 하나의 신호를 출력합니다. 이 때 퍼셉트론이 출력하는 신호는 전달 혹은 차단이라는 1 또는 0의 값을 갖게됩니다. 직관적인 예시를 들어보도록 하죠. 여러분이 매달 초 용돈, 아르바이트비를 받거나(1) 받지 않는다(0)고 가정해보겠습니다. 여러분의 통장에 입금된 이 두 가지 수익을 input(입력) 신호라고 합니다. 이 때 여러분은 두 개의 수익이 합쳐진 통장 잔고를 확인하고 전부터 갖고 싶던 옷을 살지(1) 혹은 사지 않을지(0)를 결정합니다. 이렇게 여러분이 내리는 결정이 output(출력) 신호가 되는 것입니다.하지만 여러분의 의사결정은 이것보다는 복잡할 것입니다. 용돈은 거의 생활비로만 사용하고, 아르바이트비를 주로 취미생활에 사용한다고 가정해보죠. 그럼 여러분이 옷을 살지 여부를 결정할 때에는 아르바이트비가 들어왔는지가 좀더 중요할 것입니다. 따라서 우리는 각 input(입력) 신호를 그대로 사용하지 않고, 각각에 가중치(weight)를 주어 output(출력) 신호를 결정하게 됩니다. 이것을 도식으로 나타내면 다음과 같습니다. 이처럼 input에 weight가 곱해진 형태가 정해진(혹은 학습된) 임계치를 넘을 경우 1을 출력하고 그렇지 않을 경우 0을 출력하게 하는 것이 퍼셉트론의 동작 원리입니다. 정말 간단하죠! 이는 아래 수식과 같습니다.하지만 임계치를 그때그때 바꿔주는 것은 조금 직관적이지 않습니다(저만 그런가요). 그래서 우리는 아래 형태로 식을 바꾸게 되며, 이 때 추가된 b를 bias 혹은 절편이라고 말합니다. 위 식은 여러분이 중고등학교 수학 수업을 잘 들었다면 굉장히 익숙한 형태일 것입니다. 바로 2차원 좌표축을 그리고 직선을 그었을 때, 그 직선을 기준으로 나뉘는 두 개의 공간을 표현한 식입니다. 역시 말보다는 그림이 이해하기 쉬울테니, 아래에 그림을 그려보도록 하겠습니다.위처럼 공간을 올곧은 직선으로 나누는 것을 선형으로 나눴다고 말합니다. 하지만 직선만으로 공간을 나누는 것은 유연하지 않습니다. 위와 같은 방식으로는 OR, AND, NAND 문제는 해결할 수 있지만, XOR 문제는 해결할 수 없습니다. 이와 같은 문제를 해결하기 위해서는 층을 하나 더 쌓고, 공간을 단순한 선형이 아닌 곡선으로 분리해내어 좀더 유연한 적용이 가능해져야합니다.(사실 XOR은 선형만으로도 층을 하나 더 쌓으면 해결이 가능합니다). 이에 따라 multi layer perceptron(MLP) 의 개념이 등장하고, activation function(활성함수) 의 개념이 등장하게 됩니다. 후에 활성함수의 개념을 배우게 되면, 지금 배운 단순 퍼셉트론은 활성함수로 계단함수를 가진 것과 동일하다는 것을 알게 되실겁니다.정리단층 퍼셉트론은 모든 딥러닝 공부의 시작이다.단층 퍼셉트론은 입력 신호를 받으면 임계치에 따라 0 또는 1의 값을 출력한다.이러한 단층 퍼셉트론은 결국 공간을 선형으로 잘라서 구분하는 것과 동일하다.
조회수 1438

VCNC가 Hadoop대신 Spark를 선택한 이유

요즘은 데이터 분석이 스타트업, 대기업 가릴 것 없이 유행입니다. VCNC도 비트윈 출시 때부터 지금까지 데이터 분석을 해오고 있고, 데이터 기반의 의사결정을 내리고 있습니다.데이터 분석을 하는데 처음부터 복잡한 기술이 필요한 것은 아닙니다. Flurry, Google Analytics 등의 훌륭한 무료 툴들이 있습니다. 하지만 이러한 범용 툴에서 제공하는 것 이상의 특수하고 자세한 분석을 하고 싶을 때 직접 많은 데이터를 다루는 빅데이터 분석을 하게 됩니다. VCNC에서도 비트윈의 복잡한 회원 가입 프로세스나, 채팅, 모멘츠 등 다양한 기능에 대해 심층적인 분석을 위해 직접 데이터를 분석하고 있습니다.빅데이터 분석 기술큰 데이터를 다룰 때 가장 많이 쓰는 기술은 Hadoop MapReduce와 연관 기술인 Hive입니다. 구글의 논문으로부터 영감을 받아 이를 구현한 오픈소스 프로젝트인 Hadoop은 클러스터 컴퓨팅 프레임웍으로 비싼 슈퍼컴퓨터를 사지 않아도, 컴퓨터를 여러 대 연결하면 대수에 따라서 데이터 처리 성능이 스케일되는 기술입니다. 세상에 나온지 10년이 넘었지만 아직도 잘 쓰이고 있으며 데이터가 많아지고 컴퓨터가 저렴해지면서 점점 더 많이 쓰이고 있습니다. VCNC도 작년까지는 데이터 분석을 하는데 MapReduce를 많이 사용했습니다.주스를 만드는 과정에 빗대어 MapReduce를 설명한 그림. 함수형 프로그래밍의 기본 개념인 Map, Reduce라는 프레임을 활용하여 여러 가지 문제를 병렬적으로 처리할 수 있다. MapReduce slideshare 참조MapReduce는 슈퍼컴퓨터 없이도 저렴한 서버를 여러 대 연결하여 빅데이터 분석을 가능하게 해 준 혁신적인 기술이지만 10년이 지나니 여러 가지 단점들이 보이게 되었습니다. 우선 과도하게 복잡한 코드를 짜야합니다. 아래는 간단한 Word Count 예제를 MapReduce로 구현한 것인데 매우 어렵고 복잡합니다.MapReduce로 단어 갯수를 카운트하는 간단한 예제 (Java). 많은 코드를 작성해야 한다.이의 대안으로 SQL을 MapReduce로 변환해주는 Hive 프로젝트가 있어 많은 사람이 잘 사용하고 있지만, 쿼리를 최적화하기가 어렵고 속도가 더 느려지는 경우가 많다는 어려움이 있습니다.MapReduce의 대안으로 최근 아주 뜨거운 기술이 있는데 바로 Apache Spark입니다. Spark는 Hadoop MapReduce와 비슷한 목적을 해결하기 위한 클러스터 컴퓨팅 프레임웍으로, 메모리를 활용한 아주 빠른 데이터 처리가 특징입니다. 또한, 함수형 프로그래밍이 가능한 언어인 Scala를 사용하여 코드가 매우 간단하며, interactive shell을 사용할 수 있습니다.Spark으로 단어 개수를 카운트하는 간단한 예제 (Scala). MapReduce에 비해 훨씬 간단하다.Spark과 MapReduce의 성능 비교. I/O intensive 한 작업은 성능이 극적으로 향상되며, CPU intensive 한 작업의 경우에도 효율이 더 높다. (자료: RDD 논문)Apache Spark는 미국이나 중국에서는 현재 Hadoop을 대체할만한 기술로 급부상하고 있으며, 국내에도 최신 기술에 발 빠른 사람들은 이미 사용하고 있거나, 관심을 갖고 있습니다. 성능이 좋고 사용하기 쉬울 뿐 아니라, 범용으로 사용할 수 있는 프레임웍이기에 앞으로 더 여러 분야에서 많이 사용하게 될 것입니다. 아직 Spark를 접해보지 못하신 분들은 한번 시간을 내어 살펴보시길 추천합니다.기존의 데이터 분석 시스템 아키텍처기존의 데이터 분석 시스템 아키텍처기존의 시스템은 비용을 줄이기 위해 머신들을 사무실 구석에 놓고 직접 관리했으며, AWS S3 Tokyo Region에 있는 로그를 다운받아 따로 저장한 뒤, MapReduce로 계산을 하고 dashboard를 위한 사이트를 따로 제작하여 운영하고 있었습니다.이러한 시스템은 빅데이터 분석을 할 수 있다는 것 외에는 불편한 점이 많았습니다. 자주 고장 나는 하드웨어를 수리하느라 바빴고, 충분히 많은 머신을 확보할 여유가 없었기 때문에 분석 시간도 아주 오래 걸렸습니다. 그리고 분석부터 시각화까지 과정이 복잡하였기 때문에 간단한 것이라도 구현하려면 시간과 노력이 많이 들었습니다.Spark과 Zeppelin을 만나다이때 저희의 관심을 끈 것이 바로 Apache Spark입니다. MapReduce에 비해 성능과 인터페이스가 월등히 좋은 데다가 0.x 버전과는 달리 1.0 버전에서 많은 문제가 해결되면서 안정적으로 운영할 수 있어 비트윈 데이터 분석팀에서는 Spark 도입을 결정했습니다.Apache Zeppelin은 국내에서 주도하고 있는 오픈소스 프로젝트로써, Spark를 훨씬 더 편하고 강력하게 사용할 수 있게 해주는 도구입니다. 주요한 역할은 노트북 툴, 즉 shell에서 사용할 코드를 기록하고 재실행할 수 있도록 관리해주는 역할과 코드나 쿼리의 실행 결과를 차트나 표 등으로 시각화해서 보여주는 역할입니다. VCNC에서는 Zeppelin의 초기 버전부터 관심을 가지고 살펴보다가, Apache Spark를 엔진으로 사용하도록 바뀐 이후에 활용성이 대폭 좋아졌다고 판단하여 데이터 분석에 Zeppelin을 도입하여 사용하고 있고, 개발에도 참여하고 있습니다.또한, 위에서 언급한 하드웨어 관리에 드는 노력을 줄이기 위해서 전적으로 클라우드를 사용하기로 함에 따라서1 아래와 같은 새로운 구조를 가지게 되었습니다.새로운 데이터 분석 시스템 아키텍처새로운 데이터 분석 시스템 아키텍처새로운 데이터 분석 시스템은 아키텍처라고 하기에 다소 부끄러울 정도로 간단합니다. 애초에 전체 시스템 구성을 간단하게 만드는 것에 중점을 두었기 때문입니다. 대략적인 구성과 활용법은 아래와 같습니다.모든 서버는 AWS 클라우드를 이용수 대의 Zeppelin 서버, 수 대의 Spark 서버운영Spark 서버는 메모리가 중요하므로 EC2 R3 instance 사용로그는 별도로 저장하지 않고 서비스 서버에서 S3로 업로드하는 로그를 곧바로 가져와서 분석함중간 결과 저장도 별도의 데이터베이스를 두지 않고 S3에 파일로 저장Zeppelin의 scheduler 기능을 이용하여 daily batch 작업 수행별도의 dashboard용 Zeppelin을 통해 중간 결과를 시각화하며 팀에 결과 공유이렇게 간단한 구조이긴 하지만 Apache Spark와 Apache Zeppelin을 활용한 이 시스템의 능력은 기존 시스템보다 더 강력하고, 더 다양한 일을 더 빠르게 해낼 수 있습니다.기존현재일일 배치 분석코드 작성 및 관리가 어려움Zeppelin의 Schedule 기능을 통해 수행 Interactive shell로 쉽게 데이터를 탐험 오류가 생긴 경우에 shell을 통해 손쉽게 원인 발견 및 수정 가능Ad-hoc(즉석) 분석복잡하고 많은 코드를 짜야 함분석 작업에 수 일 소요Interactive shell 환경에서 즉시 분석 수행 가능Dashboard별도의 사이트를 제작하여 운영 관리가 어렵고 오류 대응 힘듦Zeppelin report mode 사용해서 제작 코드가 바로 시각화되므로 제작 및 관리 수월성능일일 배치 분석에 약 8시간 소요메모리를 활용하여 동일 작업에 약 1시간 소요이렇게 시스템을 재구성하는 작업이 간단치는 않았습니다. 이전 시스템을 계속 부분적으로 운영하면서 점진적으로 재구성 작업을 하였는데 대부분 시스템을 옮기는데 약 1개월 정도가 걸렸습니다. 그리고 기존 시스템을 완전히 대체하는 작업은 약 6개월 후에 종료되었는데, 이는 분석 성능이 크게 중요하지 않은 부분들에 대해서는 시간을 두고 여유 있게 작업했기 때문이었습니다.Spark와 Spark SQL을 활용하여 원하는 데이터를 즉석에서 뽑아내고 공유하는 예제Zeppelin을 활용하여 인기 스티커를 조회하는 dashboard 만드는 예제결론비트윈 데이터 분석팀은 수개월에 걸쳐 데이터 분석 시스템을 전부 재구성하였습니다. 중점을 둔 부분은빠르고 효율적이며 범용성이 있는 Apache Spark, Apache Zeppelin을 활용하는 것최대한 시스템을 간단하게 구성하여 관리 포인트를 줄이는 것두 가지였고, 그 결과는 매우 성공적이었습니다.우선 데이터 분석가 입장에서도 관리해야 할 포인트가 적어져 부담이 덜하고, 이에 따라 Ad-hoc분석을 수행할 수 있는 시간도 늘어나 여러 가지 데이터 분석 결과를 필요로 하는 다른 팀들의 만족도가 높아졌습니다. 새로운 기술을 사용해 본 경험을 글로 써서 공유하고, 오픈소스 커뮤니티에 기여할 수 있는 시간과 기회도 생겼기 때문에 개발자로서 보람을 느끼고 있습니다.물론 새롭게 구성한 시스템이 장점만 있는 것은 아닙니다. 새로운 기술들로 시스템을 구성하다 보니 세세한 기능들이 아쉬울 때도 있고, 안정성도 더 좋아져야 한다고 느낍니다. 대부분 오픈소스 프로젝트이므로, 이러한 부분은 적극적으로 기여하여 개선하여 나갈 계획입니다.비트윈 팀에서는 더 좋은 개발환경, 분석환경을 위해 노력하고 있으며 이는 더 좋은 서비스를 만들기 위한 중요한 기반이 된다고 생각합니다. 저희는 항상 좋은 개발자를 모시고 있다는 광고와 함께 글을 마칩니다.연관 자료: AWS 한국 유저 그룹 - Spark + S3 + R3 을 이용한 데이터 분석 시스템 만들기↩저희는 언제나 타다 및 비트윈 서비스를 함께 만들며 기술적인 문제를 함께 풀어나갈 능력있는 개발자를 모시고 있습니다. 언제든 부담없이 [email protected]로 이메일을 주시기 바랍니다!
조회수 3696

iOS에서 간결한 API 클라이언트 구현하기 (like Retrofit+GSON)

이 글은 안드로이드 개발에서 웹 서버 API 클라이언트를 간결하게 구현할 수 있도록 도와주는 강력한 오픈소스 라이브러리인 Retrofit과 GSON의 조합을 iOS 개발에서도 따라해보고 싶은 분들을 위해 작성되었습니다. Retrofit+GSON를 실제로 사용하는 좋은 예제는 다른 블로그 글에서도 찾아볼 수 있습니다.배경리디북스 서비스가 발전하면서 점점 복잡해지고, 자연히 앱의 기능도 다양해지기 시작했습니다. 기능이 다양해지면서 웹 서버와의 연동을 위한 API 종류도 늘어났고 앱 내에서 API 호출이 필요한 부분도 다양해지면서 관련된 중복 코드가 이곳 저곳에 산재하게 되었고 전체적인 코드 퀄리티 향상을 위해 이를 최소화하고 모듈화 할 필요성이 생겼습니다.안드로이드에서는 Pure Java로 작성되어 어노테이션을 통한 간결한 코드를 사용할 수 있게 해주는 Retrofit을 GSON과 연동하여 JSON 응답을 손쉽게 객체에 맵핑 하여 사용함으로써 이러한 문제를 성공적으로 해결할 수 있었습니다. 이후 iOS 개발을 진행하면서 비슷한 역할을 할 수 있는 도구가 있을까 찾아봤지만 마땅하지 않아 결국 사용 가능한 도구들을 이용해 비슷하게 따라해보기로 했습니다.목표Retrofit+GSON 조합을 최대한 따라해서 iOS 앱의 코드 퀄리티를 높이기 위한 작업을 진행하기는 하지만 모방하는 것 자체가 목적이 될 수는 없으므로, 구체적인 목적은 다음과 같은 것들로 상정해보았습니다.API 통신 부분을 모듈화하여 관련 중복 코드를 최소화하기NSArray, NSDictionary를 직접 사용하여 제어 했던 JSON 처리 부분을 추상화하여 모델 클래스를 정의, JSON 응답을 자동으로 객체에 맵핑 해서 사용할 수 있도록 하기필요한 것Retrofit과 GSON의 동작에 대한 이해AFNetworking비동기 HTTP 요청 처리에 용이하므로 기존에도 이미 API 호출을 위해서도 사용하고 있었습니다.이 글의 내용은 버전 2.6.3 기준입니다.Swift 언어와 그에 대한 이해사실 Objective-C를 사용해도 무방하지만, 작업 당시 Swift가 발표된 지 얼마 되지 않은 시점 이었기 때문에 시험 삼아 선택 되었으며 실제로 Swift가 Objective-C 대비 가진 장점들이 적지 않게 활용되었습니다.이 글의 내용은 버전 2.0 기준입니다.구조와 동작클래스 이름 앞에 붙어 있는 RB는 리디북스에서 사용하는 클래스 접두어 입니다.RBApiServiceAPI 통신을 담당하는 부분의 핵심은 중앙의 RBApiService 클래스를 포함한 상속 구조라고 할 수 있으며 상술하면 다음과 같습니다.AFNetworking에서, HTTP 요청 작업의 큐잉부터 시작과 종료까지 라이프 사이클 전반을 관리하는 역할을 하는 AFHTTPRequestOperationManager를 상속받는 RBApiService 클래스를 정의각 API들은 역할군에 따라 RBBookService(책 정보 관련 API), RBAccountService(사용자 계정/인증 관련 API) 등과 같은 RBApiService의 하위 클래스들의 메소드로 정의됨이 하위 클래스들이 AFHTTPRequestOperationManager의 역할을 그대로 이어받아 자신을 통해 이루어지는 API HTTP 요청 작업들을 관리이 설명에 따르면 웹 서버의 /api/foo/bar API를 요청하는 메소드는 RBFooService 클래스에 다음과 같이 정의될 것입니다.func bar(param1: String, param2: String, success: RBApiSuccessCallback, failure: RBApiFailureCallback) -> AFHTTPRequestOperation! { let paramters = ["param1": param1, "param2": param2] responseSerializer = RBJSONResponseSerializer(responseClass: RBFooBarResponse.class) return GET("/api/foo/bar", parameters: parameters, success: success, failure: failure) }RBApiSuccessCallback과 RBApiFailureCallback은 요청과 응답이 완료되고 각각 성공, 실패일 때 호출되는 람다 함수(Objective-C의 block에 대응되는 개념) 타입으로 다음과 같이 typealias를 통해 선언되어 있습니다. typealias RBApiSuccessCallback = ((operation: AFHTTPRequestOperation, responseObject: AnyObject) -> Void)? typealias RBApiFailureCallback = ((operation: AFHTTPRequestOperation?, error: NSError) -> Void)?GET 메소드는 AFHTTPRequestOperationManager의 메소드로 새로운 HTTP GET 요청 작업을 생성하고 큐에 넣은 뒤 그 인스턴스를 반환합니다. bar 메소드는 이렇게 반환된 인스턴스를 다시 그대로 반환하는데 API 호출을 의도한 측에서는 이 인스턴스를 통해 필요한 경우 요청 처리를 취소할 수 있습니다. API에 따라 GET 이외의 다른 방식의 요청이 필요하다면 POST, PUT, DELETE등의 메소드들 또한 사용할 수 있습니다.RBFooBarResponse 클래스는 이 API 호출의 JSON 응답을 맵핑하기 위한 모델 클래스입니다. 이 API 요청의 응답은 RBJSONResponseSerializer 클래스를 통해 사전에 정의된 규칙에 따라 적절히 RBFooBarResponse 인스턴스로 변환되고 이 모든 과정이 성공적으로 진행되면 RBApiSuccessCallback의 responseObject 인자로 전달됩니다.모델 클래스와 RBJSONResponseSerializer앞서 이야기했듯이 RBJSONResponseSerializer는 JSON 형태로 온 응답을 특정 모델 클래스의 인스턴스로 맵핑시키는 작업을 수행합니다(Retrofit+GSON 조합에서 GsonConverter의 역할에 대응한다고 볼 수 있습니다).iOS 개발에서 전통적으로 JSON을 다루는 방식은 Cocoa 프레임워크에서 기본적으로 제공하는 NSJSONSerialization 클래스를 이용하여 JSON Array->NSArray로, 그 외의 JSON Object는 NSDictionary로 변환하여 사용하는 방식입니다. 이러한 방식을 사용할 경우 별다른 가공이 필요 없다는 장점이 있는 대신 다음과 같은 문제들에 직면할 수 있습니다.데이터가 명시적으로 정의된 프로퍼티로 접근되지 않고 문자열 키 기반의 키-밸류 형태로만 접근되므로 데이터의 타입이 명시적이지 않아 타입 검사와 캐스팅이 난무하게 되어 가독성을 해침오타와 같은 개발자의 단순 실수로 인한 버그를 유발할 가능성도 커짐특히 오타로 인한 버그의 경우 명시적인 모델 클래스의 프로퍼티로 맵핑 해서 사용한다면 IDE가 에러를 검출해주거나 최소한 빌드 타임 에러가 발생할테니 미연에 방지할 수 있습니다. 이러한 문제는 사소한 실수로 인해 찾기 힘든 버그가 발생한다는 점과 코드 리뷰를 통해서도 발견하기가 힘들다는 점에서 지속적으로 개발자를 괴롭힐 수 있습니다.RBJSONResponseSerializer를 통한 인스턴스로의 변환은 이런 문제 의식에서 출발했고 Retrofit에 GSON을 연계하여 사용하기 위한 GsonConverter가 해결을 위한 힌트를 제공한 셈입니다.// AFJsonResponseSerializer는 NSJSONSerializer를 이용해 NSArray/NSDictionary로 변환하는 기본적인 작업을 해줌 class RBJSONResponseSerializer: AFJSONResponseSerializer { var responseClass: NSObject.Type! override init() { super.init() } required init(responseClass: NSObject.Type!) { self.responseClass = responseClass super.init() } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func responseObjectForResponse(response: NSURLResponse?, data: NSData?, error: NSErrorPointer) -> AnyObject? { // 파서를 직접 구현하는 건 노력이 많이 필요하므로 우선 AFJSONResponseSerializer를 이용해 NSArray/NSDictionary로 변환 let responseObject: AnyObject! = super.responseObjectForResponse(response, data: data, error: error) if let dictionary = responseObject as? NSDictionary where responseClass != nil { // 변환 결과가 NSDictionary이면서 responseClass가 정의되어 있다면 변환 작업 시작 return responseClass.fromDictionary(dictionary, keyTranslator: PropertyKeyTranslator) } // NSArray라면 JSON이 top level array로 이루어졌다는 뜻이므로 변환 불가로 보고 그대로 반환 // 혹은 responseClass가 정의되어 있지 않아도 그대로 반환 return responseObject } }Key translatorfromDictionary 메소드 호출 시 함께 인자로 전달되는 keyTraslator는 JSON에서 사용되는 키로부터 모델 클래스의 프로퍼티 이름으로의 변환을 나타내는 람다 함수로 개발자가 원하는 규칙에 따라 정의하면 됩니다. 위의 코드에서 사용 중인 PropertyKeyTranslator는 리디북스 API에서 사용 중인 규칙 및 Swift의 네이밍 컨벤션에 따라 다음과 같이 언더스코어(_) 케이스로 된 이름을 카멜 케이스로 바꾸는 형태로 정의되었으며 이는 GSON의 FieldNamingPolicy 중 LOWERCASE_WITH_UNDERSCORES와 유사합니다.let PropertyKeyTranslator = { (keyName: String) -> String in let words = keyName.characters.split { $0 == "_" }.map { String($0) } var translation: String = words[0] for i in 1..NSObject.fromDictionary 메소드fromDictionary 메소드는 NSDictionary로 표현된 데이터를 실제 모델 클래스의 인스턴스로 변환하는 작업을 수행하며 NSObject의 extension(Objective-C의 category 개념과 유사합니다)으로 정의하여 원하는 모델 클래스가 어떤 것이든지 간에 공통적인 방법을 사용할 수 있게끔 했습니다.extension NSObject { class func fromDictionary(dictionary: NSDictionary) -> Self { // keyTranslator가 주어지지 않으면 디폴트 translator 사용 return fromDictionary(dictionary, keyTranslator: { $0 }) } class func fromDictionary(dictionary: NSDictionary, keyTranslator: (String) -> String) -> Self { let object = self.init() (object as NSObject).loadDictionary(dictionary, keyTranslator: keyTranslator) return object } func loadDictionary(dictionary: NSDictionary, keyTranslator: (String) -> String) { // 주어진 dictionary에 포함된 모든 키-밸류 쌍에 대해 작업 수행 for (key, value) in (dictionary as? [String: AnyObject]) ?? [:] { // keyTranslator를 이용해 키를 프로퍼티 이름으로 변환 let keyName = keyTranslator(key) // 프로퍼티 이름을 사용할 수 있는지 검사 if respondsToSelector(NSSelectorFromString(keyName)) { if let dictionary = value as? NSDictionary { // 밸류가 NSDictionary면 해당 프로퍼티의 타입에 대해 fromDictionary 메소드 호출 if let ecls = object_getElementTypeOfProperty(self, propertyName: keyName) as? NSObject.Type { setValue(ecls.fromDictionary(dictionary, keyTranslator: keyTranslator), forKey: keyName) } else { NSLog("NSObject.loadDictionary error: not found element type of property. (key: \(keyName), value: \(dictionary))") } continue } else if let array = value as? NSArray { var newArray = [NSObject]() // 밸류가 배열이면 각 요소별로 작업 수행 for object in array { if let dictionary = object as? NSDictionary { // 배열 요소가 NSDictionary면 프로퍼티의 배열 요소 타입에 대해 fromDictionary 메소드 호출한 뒤 배열에 추가 if let ecls = object_getElementTypeOfProperty(self, propertyName: keyName) as? NSObject.Type { newArray.append(ecls.fromDictionary(dictionary, keyTranslator: keyTranslator)) } else { NSLog("NSObject.loadDictionary error: not found element type of property. (key: \(keyName), value: \(dictionary))") } } else if let object = object as? NSObject { // NSDictionary가 아니면 그대로 배열에 추가 newArray.append(object) } else { NSLog("NSObject.loadDictionary error: can't cast element. (key: \(keyName), value: \(object))") } } setValue(newArray, forKey: keyName) continue } else if value is NSNull { continue } // NSDictionary, NSArray가 아니면서 null도 아니면 그대로 사용 setValue(value, forKey: keyName) } } } }주어진 dictionary에 존재하는 모든 키-밸류 쌍에 대해 밸류가 가진 타입과 이에 대응하는 프로퍼티의 타입에 따라 적절히 프로퍼티에 대응될 객체를 구한 다음 Cocoa 프레임워크에서 제공하는 KVC를 이용해 채워넣습니다.프로퍼티 타입 정보 가져오기모델 클래스가 반드시 Int, String, Float과 같은 기본적인 타입들로만 이루어져 있을 필요는 없고 다른 모델 클래스의 인스턴스나 배열을 포함하고 있어도 타입 정보를 런타임에 가져와 재귀적으로 데이터를 채워나가는 것이 가능합니다. 프로퍼티의 타입을 알아내는 과정은 다음과 같이 Swift에서 제공하는 Mirror 구조체를 통해 이루어지는데 이는 마치 (이름에서도 느낄 수 있듯이) Java의 리플렉션을 떠올리게 합니다.// 타입 이름에서 특정 접두어("Optional", "Array", "Dictionary" 등)를 찾아 제거 func encodeType_getUnwrappingType(encodeType: String, keyword: String) -> String { if encodeType.hasPrefix(keyword) { let removeRange = Range(start: encodeType.startIndex.advancedBy(keyword.length + 1), end: encodeType.endIndex.advancedBy(-1)) return encodeType.substringWithRange(removeRange) } else { return encodeType } } // object의 타입에서 propertyName의 이름을 갖는 프로퍼티의 타입 이름을 반환 func object_getEncodeType(object: AnyObject, propertyName name: String) -> String? { let mirror = Mirror(reflecting: object) let mirrorChildrenCollection = AnyRandomAccessCollection(mirror.children)! // object의 타입 구조 children 중에서 propertyName을 찾음 for (label, value) in mirrorChildrenCollection { if label == name { // Optional 타입인 경우 "Optional" 접두어를 제외 return encodeType_getUnwrappingType("\(value.dynamicType)", keyword: "Optional") } } return nil } // object의 타입에서 propertyName의 이름을 갖는 프로퍼티의 타입 인스턴스를 반환 func object_getElementTypeOfProperty(object: AnyObject, propertyName name: String) -> AnyClass? { // 타입의 이름을 가져옴 if var encodeType = object_getEncodeType(object, propertyName: name) { let array = "Array" // "Array" 접두어로 시작할 경우 (배열인 경우) if encodeType.hasPrefix(array) { // "Array" 에서 "Array" 제외하고 T를 반환 return NSClassFromString(encodeType_getUnwrappingType(encodeType, keyword: array)) } let dictionary = "Dictionary" if encodeType.hasPrefix(dictionary) { // "Dictionary" 에서 "Dictionary", "K"를 제외하고 V를 반환 encodeType = encodeType_getUnwrappingType(encodeType, keyword: dictionary) encodeType = encodeType.substringWithRange(Range(start: encodeType.rangeOfString(", ")!.endIndex.advancedBy(1), end: encodeType.endIndex)) return NSClassFromString(encodeType) } // 커스텀 클래스 접두어를 가지고 있다면 그 타입 그대로 반환 if encodeType.hasPrefix(RidibooksClassPrefix) { return NSClassFromString(encodeType) } } return nil }RidibooksClassPrefix는 커스텀 클래스들의 접두어를 나타내는 상수이며(리디북스의 경우 앞서 이야기했듯 “RB”), 이 접두어가 붙어있는 경우에만 모델 클래스로 간주해 해당 타입 인스턴스가 반환됩니다.예시앞서 정의한 PropertyKeyTranslator를 사용했을 때, 위에 예시로 사용했던 /foo/bar API 요청의 JSON 응답과 모델 클래스 및 생성되는 인스턴스 형태의 예를 들면 다음과 같을 것입니다.(Int, Bool, Float과 같은 기존 NSNumber 기반의 타입을 가지는 프로퍼티들은 아직 정확한 원인은 알 수 없으나 nil 이외의 값으로 초기화 해주지 않으면 프로퍼티가 존재하는지 확인하기 위해 사용하는 respondsToSelector 메소드가 false를 뱉게 되어 사용할 수 없으므로 클래스 선언시 적절한 초기값을 주어야 합니다.{ "success": true, "int_value": 1, "string_value": "Hello!", "float_value": null, "baz_qux": { "array_value": [1, 2, 3] } }class RBFooBarResponse : NSObject { var success = false // true var intValue = 0 // 1 var stringValue: String! // "Hello!" var floatValue: Float! = 0.0 // nil var bazQux: RBBazQux! } class RBBazQux : NSObject { var arrayValue: [Int]! // [1, 2, 3] }맺음말이런 작업들을 통해 당초 목표했던 두 가지, API 통신 관련 중복 코드를 최소화 하면서 JSON 응답을 가독성이 더 좋고 실수할 확률이 적은 모델 클래스의 인스턴스로 자동 변환 하도록 하는 것 모두 달성하는 데에 성공했습니다.다만 모든 것이 뜻대로 될 수는 없었는데 Retrofit+GSON과 비교했을 때 플랫폼 혹은 언어의 특성에 기인하는 다음과 같은 한계들 또한 존재했습니다.Retrofit에서는 Java 어노테이션을 이용해 API 메소드의 인터페이스만 정의하면 됐지만 iOS 구현에서는 GET, POST 등의 실제 요청 생성 메소드를 호출 하는 것 까지는 직접 구현해줘야 함키->프로퍼티 이름 변환 규칙에 예외 사항이 필요할 때 GSON에서는 @SerializedName 어노테이션을 통해 손쉽게 지정할 수 있지만 iOS 구현에서는 예외 허용을 위한 깔끔한 방법을 찾기가 힘듬 (다만, 예외가 필요한 경우가 특별히 많지는 않기 때문에 큰 문제는 되지 않음)향후에는 HTTP 통신을 위해 사용 중인 AFNetworking(Objective-C로 작성됨)을 온전히 Swift로만 작성된 Alamofire로 교체하는 것을 검토 중이며 기존에 비해 좀 더 간결한 코드를 사용할 수 있을 것으로 기대하고 있습니다. 다만 Alamofire의 최신 버전이 iOS 8 이상을 지원하고 있어 iOS 7을 아직 지원 중인 리디북스인 관계로 언제 적용할 수 있을지는 아직 미지수입니다.#리디북스 #개발 #개발자 #iOS #iOS개발 #API #API클라이언트 #GSON #Retrofit #중복코드 #최소화 #API통신 #웹서버 
조회수 295

프로그래밍 수업의 모든 것.

안녕하세요 엘리스입니다. :)엘리스의 프로그래밍 수업은 누구에 의해서, 어떻게, 어떤 생각을 바탕으로 만들어질까요?미래를 이끌어나갈 컴퓨터 사이언스 기술과 그 근간이 되는 교육 사이에서 좋은 프로그래밍 수업을 만들기 위해 치열하게 고민하는 엘리스의 코스 매니저가 직접 이야기합니다! 마침 엘리스는 코스 매니저 채용 중에 있으니 관심이 있다면 눈여겨 봐주세요!코스 매니저가 관여한 프로덕트로 인하여 사용자가 성장을 하고 있다면 그것은 충분히 의미 있는 일.안녕하세요 저는,트라우마를 극복한 프로그래밍 수업 크리에이터.Q. 자기소개 부탁드려요.A. 엘리스의 프로그래밍 과목을 만드는 코스 매니저 이용희입니다.Q. 엘리스에서 일하게 된 이유는 무엇인가요?A. 원래는 프로그래밍에 대한 트라우마가 있었어요. 하지만 기술 창업에 대한 꿈이 있었기 때문에 프로그래밍은 극복해야 할 산이었죠. 엘리스는 가장 뛰어난 기술자들이 모여 창업한 스타트업이에요. 당연히 기술 창업을 가장 가까이에서 경험할 수 있는 매력적인 곳으로 느껴졌죠. 그리고 프로그래밍 교육을 제공한다는 것 역시 기회로 느껴졌어요. 저와 같이 프로그래밍을 미워하고 두려워하는 사람들에게 보다 쉽게 배울 수 있는 환경을 마련해주고 싶다는 기대로 일을 시작하게 되었습니다.Q. 두려운 대상을 향해 몸을 던지셨군요! 그런데 코스 매니저가 프로그래밍을 몰라도 되나요?A. 많이 알면 알수록 당연히 좋아요. 많이 알고 있을수록 시도할 수 있는 것도 많고 학생에게 전달해줄 수 있는 것은 더욱더 많기 때문에요. 하지만 최소한으로는 Class가 뭔지 알고 있으면 OK. 예를 들어서 코드를 보고 이 코드가 어떤 목적을 갖는지 알 수 있으면 직접 코딩을 하지는 못한다고 해도 괜찮아요.Q. 코스 매니징 외에도 라이브 수업 참여, 조교, 챌린지 사회자 등 많은 역할을 하셨는데 이유가 있나요?A. 좋은 수업을 만들기 위한 첫 번째 방법은 코스를 만드는 모든 과정에 참여하는 사람들의 역할을 직접 체험해 보는 것이라고 생각했어요. 학생으로서, 조교로서, 사회자나 라이브 어시스턴트로서. 이렇게 하니까 학생으로서 수업을 접할 때의 감상은 무엇인지, 조교로서 가르쳤을 때는 어떤 어려움이 있는지를 알 수 있었어요. 라이브 수업 어시스턴트로 참여했을 때는 방송하시는 선생님들의 애로사항을 알 수 있겠더라고요.코스 매니징의 정수.프로그래밍적 성장을 도움으로써 가치를 만들어 냅니다.Q. 코스 매니징의 A to Z는? 구체적인 업무 프로세스가 궁금해요.A. 크게 기획 - 모집 - 제작 - 분석의 네 단계로 이루어져 있어요. 1. 수업 기획 -  어떤 과목을 만들 것인가? 주차별로 무엇을 다룰 것인가? 흥미로운 콘텐츠는? 2. 선생님, 조교 모집 - 엘리스가 구상한 수업을 가장 잘 전달할 수 있는 선생님과 조교를 모집. 3. 수업 제작 및 운영 - 실습 문제, 강의 자료 등을 엘리스의 색깔로 제작하여 수업을 운영. 4. 데이터 분석 - 학생들의 피드백과 데이터를 다음 수업의 발전 및 교육자와의 관계 개선에 반영.Q. 업무 방식은? 어떤 메리트가 있나요?A. 처음부터 끝까지 모든 과정을 주도해나가는 방식이에요. 어떤 회사를 가도 프로덕트의 end to end 프로세스를 전부 경험하기는 어려운데 엘리스에서는 그 전 과정을 경험할 수 있어요. 저는 이러한 경험이 교육 업계나 특정 프로덕트에만 적용할 수 있는게 아니라 다른 업계에 간다고 하더라도 충분히 전환될 수 있는 좋은 경험이라고 생각해요.Q. 미래 산업의 근간이 될 교육을 직접 만든다는 중책을 맡고 계신다고 생각하는데요, 좋은 프로그래밍 수업을 만들기 위해 어떤 노력들을 하시나요?A. 그런 영향을 미칠 수 있다는 게 무서운 일인 것도 같아요. 어떤 사람들은 엘리스를 통해서 프로그래밍을 처음 접하는 것일 수도 있는데 그 경험이 불쾌했다면 앞으로 프로그래밍을 배울 생각이 전혀 들지 않을 수도 있는 거잖아요. 그래서 최대한 다양한 피드백을 받아서 수렴하려고 해요. 외적으로는 대학강의, 수많은 수업들을 참고해요. 여러 강의를 보다보면 좋은 예도 많지만 모든 수업이 재미있지는 않아요. 중간에 듣다 마는 경우도 있고요. 그럴 때마다 내가 왜 중단했고 어떤 요소를 바꾸면 엘리스에서는 학생들이 끝까지 들을 수 있을까 고민해서 반영하려고 하죠.Q. 언제 보람을 느끼나요?A. 내가 관여한 프로덕트가 누군가에게 임팩트를 만들어내고 나뿐만 아니라 프로덕트를 사용하는 사람들이 성장을 하고 있다면 그것은 충분히 가치 있는 일인 것 같아요. 저희 플랫폼에서는 대시보드를 통해서, 그리고 학생이 코드를 어떻게 짜고 있는지 보면서 그 결과를 가시적으로 확인할 수 있어요. 누군가 제가 만든 코스를 수강함으로써 실질적으로 성장하는 게 눈에 보일 때 가장 큰 보람을 느끼는 것 같아요.한 번은 한 선생님께서 학생으로부터 ‘선생님 덕분에 취업할 수 있었어요’라는 메시지를 받은 것을 엘리스와 공유해주셨는데 그때 정말 행복하더라고요. 이게 엘리스가 추구하는 거다,라는 생각을 했어요. 엘리스도 하나의 커뮤니티이고 싶거든요. 이 경우에는 학생-선생님-엘리스가 서로의 영향으로 좋은 결과를 만들어 낸 거죠. 이런 접점을 앞으로 더 많이 만들려고 생각하고 있어요.대시보드에 나타나는 학생들의 학습 현황 및 성취도.엘리스는 이런 팀.가치, 성장, 사람. 포기할 수 없는 세 가지가 있는 곳.Q. 함께 일하는 동료들은 어떤 사람들인가요? 총평을 하자면?A. 항상 내가 최고의 사람들과 함께하고 있다라는 확신이 있어요. 각자 자기 분야에서 최고의 실력을 가진 사람들과 함께 일한다는 것만으로도 큰 자극이 되죠. 프로그래밍이든 스타트업 생존 노하우든 항상 뭔가를 새롭게 배우고 성장하게끔 동기부여를 해주는 사람들이에요. 저는 트라우마가 있었을 정도로 프로그래밍을 두려워했지만 이들과 함께 일하며 작은 피드백을 하나 듣는 것만으로도 제 실력이 빠르게 성장한다는 것을 몸소 느낄 수 있었어요. Q. 엘리스의 분위기, 팀 문화는 어떤가요?A. 새로운 것에 도전하는 것을 환영하는 수평적이고 자유로운 팀. 인턴도 아이디어를 제시할 수 있어요. 이 다음이 더 중요한데, 아이디어에서 그치는 게 아니라 활발한 피드백이 오가요. 아이디어를 실행하기 어렵다고 판단하더라도 왜 그렇고 어떻게 발전시킬 수 있는지 이야기하죠. 실행하게 되었을 때는 아이디어를 제시한 사람에게 일에 대한 권한이 전적으로 주어지고요. 저도 처음엔 파트타임 인턴이었지만, 이런 팀문화 덕분에 계속해서 업무 범위를 확장하고 제 역량을 키울 수 있었어요.코스 매니저 채용.Generalist & Infinite LearnerQ. 현재 코스 매니저를 구인하고 있는데요. 코스 매니저에 적합한 성향이 있나요?A. 두 단어가 떠오르네요. Generalist, 그리고 Infinite Learner. 깊게 한 분야를 아는 사람보다는 얕고 넓게 아는 사람이 더 적합하다고 생각해요. 다르게 말하면 새로운 것을 시도하는 것을 좋아하고 새로운 것을 접할 때 포용력이 높은 사람이요. 두 번째로는 배움에 재미를 느끼는 사람. 엘리스는 교육 스타트업이고 코스 매니저는 직접 교육의 경험을 만드는 사람이니 스스로가 배움에서 행복을 느끼는 사람이라면 훨씬 더 재미있게 일할 수 있겠죠. 한 가지 덧붙이면, 데이터 분석을 배우고 싶은 분께 엘리스는 최고의 장소입니다.Q. 코스 매니저로서 갖추고 있으면 좋은 역량이나 자질이 있다면?A. 소통 능력과 균형 감각. 코스 매니저는 수업을 만드는 모든 단계에서 다양한 이해당사자들과 일하게 돼요. 이들과 원활하게 소통하고 의견을 공유하는 게 중요하죠. 그리고 다양한 사람들 사이에서 최고의 균형을 찾아내는 것도 중요해요. 예를 들어서 선생님의 경우 개발만 해왔고 교육이라는 것을 접해본 적이 없는 분들이 대부분이고, 학생은 프로그래밍을 처음 접하면 그 수업이 좋은 건지 아닌지 평가하기 어려워요. 때문에 코스 매니저가 이 둘 사이에 다리를 놓는 중재자의 역할을 하기 위해서는 다양한 시각에서 볼 수 있는 균형 감각이 필요하다고 생각해요.
조회수 2195

전산팀의 홍일점, 김민서 개발자

안녕하세요 써티입니다!벌써 4월 중순, 벚꽃 흩날리는 봄이에요.비욘드펀드는 오늘도 상품 두개나 오픈했어요!오늘의 인터뷰 주인공은전산팀의 홍일점! 김민서 개발자입니다.입사 4개월차 신입이지만맡은 몫을 완벽히 해내고 계신 민서님:)사내인터뷰를 거부하며 3주간 저를 피해다니셨지만............ 언주역 태양빌딩에서 나의 인터뷰를 피할 수 있는 자 아무도 없으리.재밌는 이야기 들어볼까요?1. 안녕하세요 민서님. 전산팀의 유일한 여자 개발자이시네요. 현재 맡고 있는 일을 간단히 설명해주세요.일단 전산팀은 부장님, 과장님, 대리님, 저까지 총 4명인데요. 저는 비욘드펀드 홈페이지 프론트엔드를 맡고 있습니다.2. 프론트엔드가 뭔가요? (역시 개발자 인터뷰가 젤 어렵;;)음….홈페이지 구성할 때 프론트엔드와 백엔드가 있는데요. 프론트엔드는 브라우저로 보이는 기능들을 만드는거고 백엔드는 프론트엔드가 기능을 제대로 할 수 있도록 해주는 거거든요. 지금 백엔드는 과장님이 하고 계시고요. 제가 하는 일은 사용자들이 비욘드펀드 홈페이지에 들어갔을 때 보이는 모든 것들이라고 생각하시면 됩니다.3. 여기가 첫 직장이시라고 들었어요. 어떻게 오게 되셨어요?비욘드플랫폼에 합류하기 전에 한국정보기술연구원(Kitri) 산하 학원에서 웹/어플리케이션 과정을 공부하고 있었는데요. 추천 채용이 들어와서 면접을 보게 됐어요.4. 그러면 전공도 공대쪽이겠네요? 혹시…. 공대 아름이?+_+여대였어요……………………(절망) (역시 여대나온 써티도 함께 웁니다)서울 모 여대에서 컴퓨터학과를 졸업했습니다^^5. 면접 보고 어떠셨어요? P2P금융이라는 산업에 대해서는 알고 계셨었나요?잘 몰랐어요. 금융회사의 개발자가 되라라고는 상상도 못했죠. 사실 스타트업에서 일한다는 생각 자체를 해본 적이 없어요. 아는 분이 스타트업에 다니셔서 제안을 받아본 적은 있지만 진지하게 고려해보지 않았었거든요. 항상 일이 많은 전산팀...... ㅠㅠ 태양빌딩 3층에서는 커피를 양손에 들고 전산실로 걸어가는 그녀의 모습을 종종 발견할 수 있다.6. 오, 그런데 비욘드플랫폼에는 합류를 하신거네요?처음에는 회사소개에 ‘카드론’, ‘대부업’ 같은 단어가 나오니까 걱정이 좀 됐었어요. 사실 아직도 P2P금융이 일반인들에게는 많이 알려져 있지 않잖아요. 더구나 저처럼 금융에 대해서 잘 모르는 사람들은 더더욱 들어본 적이 없고요. 친구들에게 ‘여기 어떤 것 같아?’라고 물어봐도 다들 가지말라고 하더라고요ㅎㅎ그런데 홈페이지 들어가보니까 깔끔한 분위기가 맘에 들었어요. 트렌디한 회사 같다는 느낌? 대표님도 삼일회계법인 임원 출신의 대단한 분이라서 믿고 입사를 하게 됐어요.7. 그래서 P2P금융에는 관심을 좀 갖게 되셨어요?아니요. 돈이 없어요ㅋㅋㅋㅋㅋㅋㅋ 농담이고요. 비욘드펀드 상품이 좋은건 알겠는데 개발자다 보니 솔직히 완벽히 상품을 이해하진 못했어요. 지금은 사회초년생이라 투자할만한 돈은 없지만 목돈이 생기면 P2P로 재테크해볼 생각입니다.8. 비욘드펀드가 이제 좀 커나가고 있는데, 어떤 회사가 됐음 좋겠어요?비욘드펀드라고 말했을때 ‘거기 믿을만하다!’라는 평을 들을 수 있는 그런 회사가 됐으면 좋겠습니다. (사내 복지 쪽으로는 아침을 주면 좋겠…)9. 일적으로 목표가 있다면?솔직히 아직 잘 모르겠어요. 그게 문제라고 생각하기도 하면서도… 이제 4개월차 개발자니까 한창 고민할 때라고 생각해요. 예전에는 모호하게 알던 것들이 이제 조금 구체적으로 다가와요. 점점 더 디테일하게 알아가면서 깊이 공부하고 싶은 부분들이 생기는 것 같아요. 일단은 비욘드플랫폼에서 주어진 일을 열심히 해나가는 것이 목표입니다.10. 마지막으로 민서님이 제일 좋아하는건?누워있는거요. 주말에 약속 잡는 친구들이 제일 싫어요. 완전 집순이거든요. 그래서 우리 회사 휴게실에 있는 영롱한 오렌지색의 이케아 빈백이 너무 탐나요. 나중에 사려고요.민서님이 좋아하는 휴게실 빈백(옆)에서 진행된 즐거운 인터뷰!요즘 비욘드펀드가 상품출시를 활발히 하다보니 민서님이 많이 바쁘신 것 같은데, 화이팅입니다:)#비욘드플랫폼서비스 #비욘드펀드 #개발자 #인터뷰 #팀원 #팀원소개 #팀원인터뷰 #사내문화 #조직문화 #기업문화
조회수 1723

잔디의 새싹 같은 안드로이드 개발자 Gary를 만나다.

맛있는 인터뷰 : 안드로이드 개발자(Android Developer) Gary 편집자 주잔디와 함께 하는 멤버는 총 35명. 국적, 학력, 경험이 모두 다른 이들이 어떤 스토리를 갖고 잔디에 합류했는지, 무슨 일을 하고 있는지 궁금해하는 분들이 많습니다. 잔디 블로그에서는 이 궁금증을 해결해 드리고자 ‘맛있는 인터뷰’를 통해 ‘잔디’ 멤버들의 이야기를 다루고 있습니다.인터뷰에서 가장 기초적인 질문. 예상하신 자기소개 부탁한다.G : 잔디 개발자 중 제일 어린! 핵심 키워드다. 강조 부탁한다. 가장 어린! 안드로이드 플랫폼 개발을 맡은 Gary다(이하:G). 잔디 입사한 지는 9개월 되었다. 특별한 일 없이 정말 열~! 심히 개발만 했다. 일주일 전부터 식당 선택을 강요(?)했다. 이 식당을 선택한 이유는 무엇인가?G : 음식이 푸짐하게 나오기도 하지만 조명이 좋다. 인터뷰 중 사진을 찍는다고 들었는데 그 사진이 예쁘게 나올 것 같아서 선정했다. 게다가 음식이 정갈하다. 안에 룸도 있어서 회식하기도 좋다. 내 입이 복잡하질 않아서 뭘 먹어도 다 맛있다. 어차피 다 맛있는 거 사진이라도 잘 나와야 한다 싶어서 선택하게 되었다. 잔디에 들어오게 된 계기는?G : 모집 공지가 뜨길래.. 농담이다^^; 전 직장과의 시스템이 다른, 자체 서비스를 하는 회사에 가보고 싶었다. 전 직장에서는 기획, 서버, 디자인, 개발을 각각 다른 회사에서 진행했다. 내가 속한 회사는 개발만 진행했다. 처음부터 끝까지 한 곳에서 서비스하는 회사를 가보고 싶었다. 또한, 기술 스택이 너무 좋았다. 이를 통해 앞으로 나의 실력이 일취월장할 수 있겠다는 생각이 들었다. 9개월 동안 많이 발전한 것 같은가?G : 상당히 많이 발전했다. 어떤 부분에서 발전한 것 같은가?G : 이전 회사에서는 일정에 쫓기다 보니 개발 자체에서 설계라는 게 없었다. 손 가는 데로, 일단 만들고 보자라는 식으로 신기술이고 뭐고 공장처럼 찍어내는 것이 일이었다. 하지만 잔디는 다르다. 2주 단위로 생각을 통해 설계도 해보고 ‘객체지향 설계 5대 원칙’ 등 다양한 사항을 고려해보며 많은 고민 끝에 개발하는 것이 너무 좋다. 이를 통해 개발자로서 더욱 성장한 것이 느껴진다. 이전 회사보다는 일찍 퇴근하는 편인가?G : 이전 회사는 철야, 야근 거의 매일 했다. 입사한 지 9개월 정도 되었는데 이제야 사람답게 사는 것 같다. 그동안은 짐승인 줄 알았다. 일어나면 출근하고 퇴근하면 자고. 9개월 동안 사람답게 살면서 잠도 푹 잤다. 몸이 편해지면 사람 얼굴이 확 산다고 하던데 생긴 건 나아지지 않더라. 옛말도 틀린 말이 있나 보다. (하하) 주말엔 뭐하시는가?G : 집돌이 성향이라 집에 있는 경우가 많다. 밖에 나가면 이웃 주민들과 소통하기도 한다. 지금 사는 곳은 취업한 지 얼마 안 된 사회초년생들에게 국가에서 주는 ‘행복주택’이라는 곳이다. 그곳엔 대부분 사회초년생이라 연령대가 20대 후반에서 30대 초반 정도 된다. 그분들과 소통을 하며 지내고 있다. 나이가 비슷하니 공감대 형성도 되고 행복주택에서 행사 같은 걸 많이 해서 문화생활 영위하는 듯하다. 말 그대로 사람 사는 듯한 느낌이다. 서울 집값이 너무 비싸다. 행복주택은 저렴한 편인가?G : 다른 원룸에 비교하면 저렴한 편이다. 보증금이 들어가지만, 월세는 10만 원 전후다. 서울에서 월세 10만 원 전후라면 저렴한 편 아닌가? 사회 초년생분들께 추천한다. 이웃들도 좋고 문화생활도 하고. 엄청나지 않은가? 신청 후 당첨이 되어야 하지만 당첨되기 쉬운 편이다. 꼭 한번 도전해봐라. 처음 들어왔을 때 잔디는 어땠는가?G : 사실 처음 들어왔을 때 사무실이 시끌벅적하며 소통이 아주 활발할 줄 알았다. 그런데 딱 들어오니 어?! 음? 오?!… 조용하다. 진짜 활발한 곳은 따로 있었다. 목소리가 아닌 손가락으로 얘기하는 곳. 잔디 앱이었다. 사무실 자체는 너무 조용한데 잔디 앱 안에서 매우 활발하다. 아이러니하지만 의사소통은 아주 활발했다. 잔디의 생활 중 가장 마음에 드는 문화는?G : 영어 이름을 사용하며 상호 간에 존중하는 문화다. 30년 동안 한글 이름으로만 살았는데. 회사만 오면 Gary라고 부른다. 첨엔 이게 날 부르는 건지도 잘 몰랐지만 익숙해지니 너무 좋다. 수평적인 관계의 시작이 무엇인지 알게 되었다. 이전 회사와는 다르게 잔디에서는 수평적인 관계여서 의견 개진이 편했다. 의견을 나눌 수 있다는 것이 너무 좋았다. 물론 손끝으로 얘기하지만:D 감정표현도 이모티콘으로 한다. 표정은 무표정이지만 손가락은 웃고 있달까? 내 얼굴은 무표정인데 프랑키 (파랑몬스터 캐릭터)가 웃어준다. 이젠 오프라인으로도 소통이 되었으면 한다. 사무실 밖에선 말이 많으신 분들인데. 사무실만 들어오면 조용하시다. 손으로 말하고 계시니까. (웃음) 회식은 자주 하는가?G : 팀마다 다른 것 같다. 팀 내에서 석 달 치 회식비를 모아서 한 번에 하던가 쪼개서 자주자주 하던가. 어차피 쓰는 돈은 같으니까. 이루고 싶은 꿈이 있다면?G : 백수가 되고 싶다. (비장) 충분한 불로소득이 있는. 소득과 상관없이 내 맘대로 살 수 있는 그런 백수가 되고 싶다. 회사를 가고 싶으면 회사를 가고 사업을 하고 싶으면 사업을 하는 그런 백수(하하). 사실 프로그래머로서 직업을 정했을 때는 최고의 프로그램을 만들어보는 게 꿈이었다. 또한, 안드로이드로 시작했으니 구글에서 종지부를 찍자! 이런 꿈을 꾸었다. 그런데 이전 직장이 너무 힘들었나 보다. 꿈이 변했다. 백수로. 하루는 7개월 정도 만에 칼퇴근하고 집에 갔더니 어머니께서. “너 잘렸냐?”라고 물어보시더라. 그땐 내 회사 생활에 문제가 있구나 싶었다. 백수는 아니지만 일과 삶의 밸런스가 맞는 삶을 살고 싶다. 다음 인터뷰어에게 하고 싶은 질문이 있나?G : 회사 내에 다른 팀원들과 지금 먹고 있는 음식을 같이 먹을 수 있다면 누구랑 같이 먹고 싶은가?#토스랩 #잔디 #JANDI #팀원소개 #인터뷰 #기업문화 #조직문화 #사내문화 #팀원자랑

기업문화 엿볼 때, 더팀스

로그인

/