스토리 홈

인터뷰

피드

뉴스

조회수 3982

코드리뷰, 이렇게 하고 있습니다.

토스랩 안드로이드팀이 코드리뷰 하는 방법실리콘밸리 이야기 - 코드리뷰는 어떻게 하나요? 를 보고 토스랩이 코드리뷰 하는 프로세스와 방법에 대해서 공유해드리고자 합니다.왜 코드리뷰를 하게 되었나요?토스랩에 안드로이드가 팀 단위로 꾸려진 것은 5월 전후였습니다. 그 전에는 1인 개발 체제를 가지고 있었습니다. 갑작스럽게 인원이 많아지면서 코드스타일, 구조의 일관성 등이 계속적으로 깨지게 되고 이에 따라 제품의 안정성도 급격히 떨어지는 사태가 발생하였습니다.이에 내부적으로 제품의 품질을 강화하기 위한 대책들이 강구되었는데 그 중에 하나가 코드리뷰였습니다.코드리뷰를 위한 프로세스는 토스랩 웹 개발팀의 프로세스를 참고하여 안드로이드 개발 팀원의 내부 의견을 반영하여 진행되었습니다.1. 언제 코드리뷰를 요청하나요?안드로이드팀은 코드리뷰 요청에 대해 별도의 제약을 두지 않았습니다. 언제든지 코드리뷰 시스템이 코드리뷰를 요청할 수 있습니다. 다만 코드 리뷰가 시작되는 시점이 조금 다릅니다.모든 개발자가 코드리뷰를 각자의 업무(Task)가 완료되면 코드리뷰 시스템에 코드리뷰를 요청하고 이를 각 개발자가 언제든지 확인할 수 있도록 하고 있습니다.코드리뷰의 시작은 3. 그럼 코드리뷰는 언제 하나요? 에서 확인해보록 하겠습니다.2. 어떻게 요청하나요코드리뷰는 내가 아닌 다른 사람이 코드를 읽어야 하므로 어떤 목적에서 작업 된 코드인지를 미리 할 수 있어야 빠르게 코드리뷰를 할 수 있습니다. 최대한 자유롭게 하되 아래와 같은 형식을 지키도록 하고 있습니다.TitleFeature/Bug-fix 건인지 알 수 있도록 합니다.어떤 목적인지 간략하게 적도록 합니다.어떤 이슈와 연결된 건인지 알 수 있도록 합니다.Description어떤 로직을 추가/수정했는지를 작성합니다.어떻게 추가/수정했는지를 작성합니다ex)Title - [fix] 소켓 API 버전 처리 (JND-3986) Description@Version 커스텀 어노테이션 추가Version 없는 Event 에 Version 필드 추가, @Version어노테이션 부여SocketObject -> EventObject 로 파싱하는 로직 공통 메소드로 분리파싱 후 바로 반환하지 않고 Version Valid 로직 추가class JandiSocketServiceModel { T getObject(Object, T) // 파싱 공통 메소드 boolean validVersion(Object) // version 확인 } Java Reflection 사용.위와 같이 작성함으로써 이 이슈는 소켓 API 버전에 대한 버그 수정건으로 JND-3986 이라는 이슈와 연관된 것임을 알 수 있습니다. 상세 내용으로는 @Version 이 JandiSocketServiceModel의 getOject 와 validVersion 메소드와 연관되어 있음을 알 수 있도록 기술하였습니다.코드리뷰를 상세하게 쓰는 것은 리뷰어들이 코드리뷰를 효율적으로 하기 위함이기 때문에 리뷰할 부분을 빨리 확인 할 수 있게 적도록 하도 있습니다.3. 그럼 코드리뷰는 언제 하나요?실리콘 밸리의 큰 회사들 (구글, 페이스북 등)은 코드리뷰가 요청이 오면 업무의 최우선순위로 조정되어 즉시 응답하도록 하는 것이 원칙입니다. (지금 당장 하든지 아니면 언제부터 할 것인지를 피드백을 반드시 줘야 한다고 들었습니다.)하지만 스타트업은 일반적으로 개발해야 할 것들이 훨씬 더 많고 코드리뷰가 아니더라도 일이 산더미인 경우가 많습니다. 저희 토스랩이라고 이를 크게 벗어나지 않기 때문에 안드로이드팀은 별도로 코드리뷰하는 프로세스를 정의하였습니다.월~수 : feature/bug-fix 개발이 업무의 최우선 순위이다.목, 금 : 코드리뷰가 업무의 최우선 순위이며 코드리뷰 대상은 목요일 출근 전까지 리뷰 요청을 한 건을 대상으로 한다.이는 개발자들끼리 코드리뷰의 중요성을 이해하지만, 이것이 개발 건보다 더 큰 업무 비중을 차지하게 되면 개발 속도나 의욕을 저해할 수 있기 때문에 최대한 분리하여 해당 건에만 집중하기 위해 룰을 정하였습니다.업무에 따라서 편차는 있지만, 대개의 코드리뷰는 금요일에 모두 완료를 하고 있으며 긍정적 피드백이 나올때까지 코드를 변경해야만 완료가 됩니다.4. 무엇을 리뷰하나요?개발자 개인의 성향과 개발건의 성격에 따라 그때마다 다른 모습을 보여줍니다.성능 개선 개발 : 시간복잡도신규 feature 개발 : 잠재적인 오류에 대한 검출리팩토링 : 테스트코드나 구조에 대한 물음신규 기술 도입 : 해당 기술의 로직과 그에 대한 물음기타 : 변수명과 같은 코드 컨벤션을 하기도 합니다. 전체적인 흐름을 이해하기 위해 실제 빌드를 해서 동작을 시켜보고 이해하기도 합니다.기본적인 사항들은 CI 품질도구 리포팅 기능을 이용하기 때문에 주로 큰 그림에서의 코드리뷰를 하는 편입니다.5. 코드리뷰 코멘트는 어떻게 작성하나요?OO 보다는 XX 가 더 나은 것 같아요.XX 는 OO 부분을 참고해서 이용하면 되요.OO 는 XX 에 의해서 문제되지 않을까요?XX 를 하려다가 OO 로 했는데 어떻게 생각하세요?위와 같이 가급적이면 상대방을 공격하지 않는 느낌을 주도록 하며 단순히 문제를 이슈업하기 보다는 대안을 제시하는 방법을 주로 하고 있습니다. 코드리뷰는 서로의 코드에서 이해할 수 없는 부분을 찾고 문제가 될 수 있는 부분을 미리 찾아내는 자리인만큼 문제의 검출과 해결에 주안을 두고 진행합니다.6. 코드리뷰가 끝나면 어떻게 하나요?서로가 이해할 수 있을 만큼 리뷰가 진행되면 코드는 그때서야 개발용 브랜치에 통합을 합니다. 최소 1명의 피드백도 진행되지 않은 코드는 통합하지 않는 것이 원칙으로 하며 통합되어야 하는 건이 코드리뷰가 진행되지 않으면 늦어도 월요일 아침에 긴급히 진행해 줄 것을 환기시킵니다.7. 긴급히 코드리뷰해야 하는 건은 어떻게 하나요?긴급히 해야하는 건은 그만큼 사안이 중요하다고 생각하기 때문에 리뷰를 요청하는 즉시 진행을 하도록 합니다. 다만 해당 건이 즉시 반영해야 할만큼 중요한지를 서로간의 의논해서 진행하도록 합니다.총평안드로이드팀이 코드리뷰를 최초 시작한 것은 6월초입니다. 브랜치를 통합하기 전 개발 완료된 건에 대한 코드리뷰가 처음이었기 때문에 자리를 잡는데는 2달여 시간이 흐른 다음이었습니다. 초기에는 실수로 코드리뷰를 생략한다던가, 어떻게 코멘트를 남겨야할지에 대해서 조심스럽다던가 하는 시행착오를 겪어서 지금은 개발 건에 따라 20건이 넘는 의견이 남겨질 정도로 활발하게 의견을 교류하고 통합을 거칩니다.코드리뷰에 생소한 사람은 대개 나의 작업물을 누군가에게 검토 받는다는 느낌에 거부감을 가지기 마련입니다. 하지만 더 큰 그림에서 본다면 코드리뷰는 코드의 안정성을 서로 다른 관점에서 검토하는 것이기 때문에 코드의 신뢰성이 더욱 커지는 과정입니다. 그러기에 이에 대한 이해 없이 진행하는 코드리뷰는 금방 유명무실해지기 때문에 모두의 이해를 가진 다음에 진행 할 것을 추천합니다.제품의 안정성을 신경써야 하는 시점에 QA 강화와 같은 외부의 요인만을 찾는 것보다 내부에서 좀 더 개선 할 수 있는 요인을 찾는 것도 하나의 방법입니다. 토스랩에서는 다양한 품질 검증 과정에서 코드리뷰를 매우 중시하고 있습니다. 모든 팀이 각자만의 스타일대로 코드리뷰를 진행하고 있습니다.모든 개발자분들이 코드리뷰에 열린 자세로 올바른 코드리뷰를 진행하기를 바랍니다.#토스랩 #잔디 #JANDI #개발 #개발팀 #개발자 #개발환경 #업무환경 #코드리뷰 #인사이트 #조언
조회수 966

AWS IoT Core 활용하기

이 포스팅에 실린 실습은 AWS CLI가 설치되어 있고, AWS credentials이 설정되어 있는 상태에서 진행했습니다. 서버와 하드웨어 사이의 TCP 연결을 구현하지 않고 AWS IoT를 이용해 MQTT 프로토콜로 데이터를 송수신하는 환경을 구성해보겠습니다. 진행을 위해 AWS IoT와 NodeJS가 필요합니다.1.AWS IoT Core로 접속해 사물을 생성합니다. 테스트로 1개만 사용할 것이므로 “단일 AWS IoT 사물”로 등록합니다.2.‘인증서 없이 사물 생성’을 클릭합니다. 인증서는 사물 등록 후에 생성할 예정입니다.3.사물이 정상적으로 등록되었는지 확인합니다.4.루트 CA 인증서를 생성합니다. 4-1.개인키를 생성하기 전, openssl 설정 파일을 추가해 아래 내용으로 저장합니다. 아래와 같이 진행하는 이유는 basicConstraints = true로 설정하기 위해서입니다.4-2.개인키를 생성합니다.openssl genrsa -out rootCA.key 2048 4-3.루트 인증서를 생성합니다.openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem -config rootCA_openssl.conf -extensions v3_ca 5.인증서를 생성합니다. 5-1.AWS IoT 등록 코드를 확인합니다.aws iot —region=ap-northeast-1 get-registration-code 5-2.개인키를 생성합니다.openssl genrsa -out verificationCert.key 2048 5-3.CSR을 생성합니다. 앞서 5-1에서 확인한 등록코드를 Common Name 항목에 입력합니다.openssl req -new -key verificationCert.key -out verificationCert.csr 5-4.인증서를 생성합니다.openssl x509 -req -in verificationCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out verificationCert.pem -days 500 -sha256 5-5.CA 인증서와 개인 인증서 파일들을 확인합니다.5-6.AWS에 인증서를 등록합니다.aws iot register-ca-certificate —ca-certificate file://rootCA.pem —verification-cert file://verificationCert.pem —region=ap-northeast-2 5-7.AWS에 인증서를 활성화합니다.aws iot update-ca-certificate --certificate-id 인증서 등록 후 응답으로 오는 certificateId 값 --new-status ACTIVE --region=ap-northeast-2 예)aws iot update-ca-certificate —certificate-id AAAAAABDADFDF1ABADFDFDFDF### —new-status ACTIVE —region=ap-northeast-2 5-8.AWS에 인증서 자동 등록 활성화를 켭니다.6.AWS 콘솔에 접속해 CA 인증서 등록을 확인합니다.7.AWS 콘솔에서 인증서를 생성합니다.7-1.원클릭 인증서 생성을 클릭합니다.7-2.활성화를 클릭하면 완료됩니다.8.인증서와 사물을 연결합니다.9.상호 작용 탭에서 디바이스를 연결합니다.10.환경에 맞게 선택하여 다운로드합니다.11.압축을 해제해 srart.sh를 실행하고, 연결 대기합니다.12.AWS IoT 테스트 접속 후, topic 1으로 메시지를 게시합니다.13.터미널을 확인합니다.이것으로 AWS IoT 로컬 환경이 구성되었습니다. AWS IoT를 사용하면 서버와 하드웨어를 제어하는 클라이언트 간 통신을 쉽게 하도록 다양한 구성을 할 수 있습니다. 모든 포맷은 JSON 포맷으로 송수신하며, MQTT(Message Queueing Telemetry Transport) 방식이라 양방향 통신을 쉽게 처리하고 전송할 수 있을 겁니다.참고자세한 MQTT - Publish/Subscribe 모델은 여기를 클릭하세요.글장현준 팀장 | R&D 개발3팀[email protected]브랜디, 오직 예쁜 옷만
조회수 1069

안드로이드 색상 투명도

제 깃헙블로그 https://heelog.github.io/about/ 에서 동시에 포스팅을 진행하고 있습니다.개발 관련 글을 보기에는 블로그를 통하시는 것이 더 좋습니다!안드로이드에서 색상을 표현할 때는 #AARRGGBB 형태로 표현한다. 앞의 AA 자리에 16진수를 이용하여 투명도를 표현해줄 수 있다. 범위는 0~255이다.0%~100% 투명도 값  100% — FF99% — FC98% — FA97% — F796% — F595% — F294% — F093% — ED92% — EB91% — E890% — E689% — E388% — E087% — DE86% — DB85% — D984% — D683% — D482% — D181% — CF80% — CC79% — C978% — C777% — C476% — C275% — BF74% — BD73% — BA72% — B871% — B570% — B369% — B068% — AD67% — AB66% — A865% — A664% — A363% — A162% — 9E61% — 9C60% — 9959% — 9657% — 9456% — 9156% — 8F55% — 8C54% — 8A53% — 8752% — 8551% — 8250% — 8049% — 7D48% — 7A47% — 7846% — 7545% — 7344% — 7043% — 6E42% — 6B41% — 6940% — 6639% — 6338% — 6137% — 5E36% — 5C35% — 5934% — 5733% — 5432% — 5231% — 4F30% — 4D28% — 4A28% — 4727% — 4526% — 4225% — 4024% — 3D23% — 3B22% — 3821% — 3620% — 3319% — 3018% — 2E17% — 2B16% — 2915% — 2614% — 2413% — 2112% — 1F11% — 1C10% — 1A9% — 178% — 147% — 126% — 0F5% — 0D4% — 0A3% — 082% — 051% — 030% — 00참고한 블로그: 커피한잔의 여유와 코딩#트레바리 #개발자 #안드로이드 #앱개발 #인사이트 #경험공유 #꿀팁
조회수 1945

Golang 체험기

AWS EC2 태그를 Kubernetes Label로 뽑아주는 Vungle/Labelgun에 문제가 많아서 이번에 대대적인 수술을 하였다. 하루에 수백번씩 Pod가 죽는 통에 도저히 참을 수가 없었다. 아무튼 이와 관련한 이야기는 다른 글에서 썰을 풀고 여기서는 Go에 초점을 맞추고 경험담을 늘어놓아볼까 한다.장점기술 탐색 — golang이란 글에서는 주로 부정적인 견해를 보였지만 최근에는 생각이 바뀌었다. 무엇보다 Docker와 같은 컨테이너 기반 서비스에는 Golang과 같은 언어가 Java 또는 Python 같은 언어보다 분명 장점이 있다. 미리 빌드한 바이너리 파일만 컨테이너에 넣으면 되기 때문에 가볍다. Java Runtime을 컨테이너에 넣을 때보다 월등히 가볍다. 여기서 가볍다 함은 컴퓨팅 리소스 측면, 컨테이너 빌드 구성의 용이함 모두를 뜻한다. 물론 전통적인 C/C++ 환경도 비슷하지 않냐라고 의문을 품는 사람도 있겠지만 Golang은 goroutine등으로 동시성 제어를 런타임 시스템이 알아서 제어해주기 때문에 언제든 머신을 갈아치울 수 있는 클라우드 환경에 훨씬 적합하다. 그 외에도 현대적인 언어의 여러 장점을 누릴 수 있는데 이는 다른 글이 훨씬 잘 설명해놓았기에 자세한 언급은 하지 않으려 한다.GOPATH 를 처음 여행하는 GOPHER 들을 위한 GOLANG 안내서단점Application Performance Monitoring을 구축하기가 생각보다 어렵다. New Relic과 DataDog Trace 모두 개발자가 코드를 상당량 추가해줘야 한다. 보통 에이전트만 붙이면 알아서 잘 작동하는 Java APM에 비해 상당히 과거의 방식이다.func saveFile(ctx context.Context, path string, r io.Reader) error { // Start a new span that is the child of the span stored in the context. If the span // has no context, it will return an empty one. span := tracer.NewChildSpanFromContext("filestore.saveFile", ctx) defer span.Finish() // save the file contents. file, err := os.Create(path) if err != nil { span.SetError(err) return err } defer file.Close() _, err = io.Copy(file, r) span.SetError(err) return err }소스코드를 바이너리 코드로 컴파일하기 때문에 빌드 및 테스트 피드백 주기가 길다. C++을 한참 다루던 시절로 돌아간 느낌이다. 한마디로 답답하다.게다가 npm과 같은 패키지 관리 시스템이 없고 Git과 같은 소스버전관리시스템을 바로 접근해 사용하기 때문에 초기 빌드가 엄청나게 느리다. Git clone 보다는 이미 잘 패키징된 파일 몇 개를 다운로드 받는 쪽이 월등히 빠를 수밖에 없지 않나?패키지 관리 시스템과 더불어 빌드와 관련해 그 존재가 매우 의심쩍은 게 하나 있으니 바로 GOPATH이다. Python의 virtualenv처럼 프로젝트별로 완전히 고립된 개발환경을 갖추면 여러 모로 장점이 많은데 왜 이런 환경변수가 존재해야 하는가? 왜? 대체 왜?마지막으로 한가지 더. Go는 goroutine 등으로 병렬작업을 지원하여 분명 편하다. 하지만 순수한 함수형 언어가 아니고 Immutable한 데이터를 메시지 패싱하는 방식이 아니기 때문에 애먹는 부분이 많다. goroutine과 channel을 장점으로 내세우는만큼 최소한 표준 라이브러리는 동시성을 최대한 고려해서 설계했을 법한데 그렇지 않은 부분이 많아서 당혹스러웠다. 물론 이러한 설계는 그만한 장점이 있지만 한동안 유행하던 다수의 언어와는 방향이 달라서 다소 적응하기 힘들었다.#데일리 #데일리호텔 #개발 #개발자 #개발팀 #스킬스택 #기술스택 #스택도입기 #후기 #golang
조회수 2540

타다 시스템 아키텍처 - VCNC Engineering Blog

2018년에는 VCNC에 큰 변화가 있었습니다. 오랫동안 비트윈 기반의 서비스들을 개발하고 운영했지만 2018년 10월에 기사 포함 렌터카 서비스를 포함한 종합 모빌리티 플랫폼인 타다를 기획하고 출시하였습니다. 변화가 많은 모빌리티 시장에서 신규 서비스를 성공적으로 출시하기 위해 많은 고민을 하였습니다. 이번 글에서는 타다의 시스템 구성과 이를 위해 사용한 여러 기술을 소개하면서, 타다 개발팀의 기술적 결정을 공유해보고자 합니다.타다에서 사용하는 기술들의 로고. 왼쪽부터 Kotlin, Spring Boot, Kubernetes, Terraform, gRPC, Redis.기존과 다른 선택비트윈의 경우 Netty를 이용해 인하우스 네트워크 라이브러리를 만들기도 하였고, 메인 데이터베이스로 NoSQL인 HBase를 사용하는 등 남들이 통상적으로 사용하지 않는 기술 스택을 선택한 경우가 많았습니다. 그 배경에는 나름대로 이유가 있었지만, 서비스 초기에는 안정성에 어려움을 겪기도 하였고 서버 배포 과정이 느리고 복잡하여 쉬운 길은 아니었습니다. 여러 문제를 해결하기 위해 Haeinsa 등 라이브러리와 소프트웨어를 직접 만들기도 하였습니다.타다는 이슈가 많은 모빌리티 시장을 타겟으로 하고 있기 때문에 Time to Market이 특히 중요했습니다. 개발하는 기간 동안 시장 상황에 따라 기능의 우선순위가 변하기도 하였습니다. 이에 따라 서비스를 빨리 출시하고 외부의 변화에 유연하게 대처할 수 있도록, 완성도 있게 만들어져 있는 프레임워크나 라이브러리를 선택하였고, AWS에서 이미 잘 관리되고 있는 서비스를 적극적으로 활용하였습니다.사용 중인 기술들Kotlin: Java는 불편한 점이 많지만, JVM에 대한 경험을 무시할 수는 없어 비교적 새로운 JVM 기반 언어인 Kotlin을 사용하기로 하였습니다. 다른 여러 JVM 기반의 대안 언어들이 있지만, Spring Boot에 쉽게 적용할 수 있고 커뮤니티에서 적극적으로 권장하고 있는 점 등 여러 이유로 Kotlin을 선택하게 되었습니다.Spring Boot: 널리 쓰는 웹 프레임워크이며 이미 지원하는 기능 또한 많기 때문에 보일러 플레이트 코드 작성을 줄이고 서비스 개발에 집중할 수 있습니다. SQS 메시지 처리, HTTP 요청 및 응답으로 Protocol Buffers 메시지 사용 등 프레임워크에서 제공하는 기능을 많이 활용하고 있습니다.Kubernetes: 컨테이너 오케스트레이션 플랫폼으로 배포 자동화와 스케일링 등 여러 가지 운영적인 편의성을 제공합니다. 처음에는 kops를 이용해 클러스터를 직접 띄웠지만, 지금은 EKS를 이용하고 있으며 직접 object를 만들기보다 helm을 이용하고 있습니다.gRPC: 실시간성이 중요한 차량 위치나 운행 상태 변화 등은 Streaming을 이용하여 전달하고 있습니다. 직접 개발할 수도 있었지만, 서비스 개발에 집중하고 앞으로의 관리 오버헤드를 줄이기 위해 gRPC를 이용하기로 하였습니다.Redis: 서버 간 메시징을 위해 Redis의 Pub/Sub 기능을 사용하고 있습니다. 메시지 브로커 기능을 제공하는 RabbitMQ, ActiveMQ, Kafka 등 여러 옵션이 있었지만, 개발을 시작하던 당시에는 Redis만이 ElastiCache를 이용하여 쉽게 띄우고 관리할 수 있어 Redis를 선택하게 되었습니다.Protocol Buffers: gRPC 뿐만 아니라 HTTP/2로 주고받는 메시지를 정의할 때도 이용하고 있습니다. 덕분에 따로 문서화 하지 않고 proto파일을 공유하여 더욱 명확하고 편리하게 API 명세를 공유할 수 있었습니다.Terraform: HCL을 이용해 인프라스트럭처 프로비저닝 및 관리를 편하게 해주는 도구입니다. AWS 서비스의 생성 및 관리를 콘솔에서 직접 하지 않고 Terraform을 이용하고 있습니다.사용 중인 AWS 서비스들AWS는 개발팀이 오랜 기간 사용하여 가장 익숙한 클라우드 플랫폼이기 때문에 큰 고민 없이 선택할 수 있었습니다.EKS: Kubernetes 클러스터의 마스터 노드들을 쉽게 띄우고 관리해주는 서비스입니다. 서울 리전에 EKS가 출시된 후에는 관리 오버헤드를 줄이기 위해 EKS로 옮겼습니다.ECR: 타다 서버를 배포할 때는 Docker Gradle Plugin을 통해 docker 이미지를 만들고 ECR에 푸시합니다. 그 후 helm 명령을 통해 Kubernetes에 배포합니다.SQS: 배차 요청을 처리하기 위해 SQS를 이용합니다. 배차 요청을 구현하는 방법에는 다양한 옵션이 있었지만 AWS 서비스를 최대한 활용하여 빠르게 개발할 수 있었습니다.RDS: 타다의 대부분 데이터는 Aurora에 저장하고 있습니다. RDS를 이용하면 DB의 배포와 관리가 쉬우며, Aurora는 MySQL과 호환될 뿐만 아니라 같은 비용이면 성능이 더 좋습니다.Kinesis: 실시간 차량 위치 정보 및 로그를 수집하기 위해 사용하고 있습니다. 다른 오픈소스 소프트웨어를 직접 이용하기보다는 AWS에서 제공하는 서비스를 최대한 이용하고 있습니다.Firehose: 비트윈에서는 KCL를 활용해 Acheron이라는 프로그램을 직접 만들어 로그들을 S3에 저장하였지만, 이제는 서울 리전에서 Firehose를 사용할 수 있으므로 큰 고민 없이 사용하기로 하였습니다.시스템 구성타다에서는 필요에 따라 서비스를 여러 종류로 분리하여 운영하고 있습니다. 일반적인 모바일 앱 API와 실시간 차량의 위치 정보를 바탕으로 사용자의 요청에 대해 적합한 차량을 배차하는 기능이 필요했습니다. 핵심적인 역할을 하는 일부 서비스와 시스템 구성에 대해 간단하게 소개합니다.라이더 앱: 아이폰은 Swift, 안드로이드는 Kotlin으로 작성하였으며 여러 오픈소스 라이브러리를 적극적으로 활용하였습니다. 서비스 특성상 RIBs라는 아키텍처를 사용하여 개발하였습니다.드라이버 앱: 아이폰과 안드로이드를 모두 지원하려면 기술적, UX적으로 고려해야 할 점들이 많고 불특정 다수의 유저를 대상으로 하는 앱도 아니었기 때문에 안드로이드 버전으로만 개발하게 되었습니다.서버: 모바일 앱의 요청을 대부분 처리하며 Spring Boot로 작성된 HTTP/2 API 서버입니다. Protocol Buffers로 정의된 메시지를 JSON 형태로 주고받습니다.gRPC 서버: 서버에서 발생하는 이벤트를 실시간으로 전달하기 위한 서버입니다. Redis Pub/Sub을 통해 받은 이벤트 메시지들을 클라이언트들에게 전달합니다.Dispatcher: 배차 요청을 처리하는 서버입니다. 주변 차들의 ETA 계산을 위해 외부 API를 이용하는데, Reactor를 이용해 비동기적, 동시적으로 요청하여 쓰레드 점유 없이 효율적으로 처리되도록 구현하였습니다.Tracker: 차량 위치 정보 수집 서버입니다. KCL를 이용해 위치 정보 레코드를 읽어 들여 TrackerDB에 기록합니다.Redis: 서비스 초기에는 차량의 최신 위치 등을 저장하기도 했지만, 지금은 주로 서버 간 메시징을 위해 Pub/Sub 기능을 이용하고 있습니다.DB: 운행 기록, 사용자 데이터 등 대부분 데이터를 기록합니다. 비트윈에서는 HBase를 이용했지만 타다의 경우 아직 절대적인 트래픽이 많지 않기 때문에 트랜잭션 등 다양한 편의 기능을 제공하는 RDB를 이용하고 있습니다.TrackerDB: 차량 운행 정보 및 차량의 최신 위치 등을 저장합니다. Aurora를 이용하며 대부분의 요청이 차량 위치 정보 업데이트이므로 안정성을 위해 별도의 인스턴스를 띄워 사용하고 있습니다.Kinesis Log Stream: 타다의 여러 서비스에서 로깅을 위해 이용합니다. Firehose를 통해 S3에 기록됩니다.Kinesis Tracker Stream: 드라이버의 실시간 위치 정보는 Kinesis를 통해 Tracker로 전달됩니다.서비스 플로우차량 위치 업데이트차량 위치 업데이트는 요금 계산, 차량 위치 제공 등 서비스에서 가장 많이 일어나는 요청입니다. 드라이버 앱에서 안드로이드 Foreground 서비스를 이용해 GPS 정보를 수집하고 일정 주기마다 서버로 현재 위치를 전송합니다. 이렇게 전송받은 GPS 위치 정보는 데이터 크기를 최소화하기 위해 Protocol Buffers로 직렬화되어 Kinesis 레코드로 만들어지게 됩니다. Tracker에서는 전달된 Kinesis 레코드를 읽어 간단한 처리를 한 후에 TrackerDB에 삽입합니다.서비스 초기에는 차량의 마지막 위치에 대한 정보만 Redis에 적었습니다. 그러나 차량의 이동 경로를 효율적으로 조회해야 할 일이 생겼는데, 당시 차량 이동 경로는 로그로만 저장되고 있었습니다. S3 Select나 Athena를 이용해 조회하는 방안도 고려했지만, 일단은 Aurora에 저장하기로 하였습니다. 당분간은 Aurora로도 충분했고 RDB를 쓰는 것이 가장 쉽고 편한 방법이었기 때문입니다.차량 배차차량 배차는 서비스의 가장 기본적인 기능으로 배차 요청에 가장 적절한 주변 차량을 할당하는 플로우입니다. 라이더 앱에서 유저가 배차를 요청하면 서버가 배차 요청 정보를 DB에 기록하고 배차 요청 메시지를 SQS 대기열에 집어넣습니다. Dispatcher가 배차를 처리하는 로직을 수행하여 차량이 매칭되면 드라이버 앱으로 이벤트가 전달됩니다.드라이버가 배차를 수락하면 서버로 수락 요청이 전송되고 서버에서는 DB의 배차 요청 상태를 수락 상태로 변경합니다. 배차 요청이 수락되었다는 이벤트는 결과적으로 gRPC 서버를 통해 해당 이벤트를 구독하고 있던 유저에게 전달됩니다.Dispatcher에서 배차를 처리하는 로직은 여러 옵션이 있었지만 가장 간단하고 효율적으로 개발하기 위해 SQS의 기능을 최대한 활용하였습니다. Dispatcher 수를 늘리는 것만으로도 처리량 확장이 가능하며 Dispatcher가 갑자기 종료되어도 한 대라도 살아있다면 결국에는 잘 처리가 됩니다. Dispatcher가 배차 요청을 받으면 다음과 같은 로직을 수행합니다. 종료 조건을 만족하지 않았다면 일정 시간 후 동일한 로직을 다시 반복합니다.배차가 가능한 상태라면 배차 로직을 수행합니다. 이동 경로와 교통정보를 고려하여 적합한 주변 차량을 찾습니다.만약 적합한 차량이 있다면 배차 요청을 해당 드라이버에게 할당되었다는 정보를 DB에 적고 배차 할당 이벤트를 전파합니다. 드라이버의 수락을 기다리기 위해 일정 시간 후 로직을 재시도합니다.만약 적합한 차량이 없다면 일정 시간 후에 로직을 재시도합니다.배차 요청이 드라이버의 수락을 기다려야 하거나 타임아웃이 남아있는 상태라면 적절한 시간 후 재시도합니다.배차 요청이 수락되어 완료된 상태거나 취소되었거나 타임아웃이 지난 상태라면 SQS에서 메시지를 삭제합니다.못다 한 이야기타다를 런칭하는 날, 기사 간담회에서 쏘카의 VCNC 인수 이후 짧은 기간 동안 타다를 만들 수 있었을 리 없으니, 실제 개발 기간은 어느 정도냐는 질문이 있었습니다. 짧은 기간 내 서비스를 성공적으로 런칭할 수 있었던 것은 상황에 맞는 올바른 기술적 선택들뿐만 아니라 훌륭한 팀원들이 있었기에 가능했던 일이었습니다. 타다는 개선해야 할 부분도 많고 앞으로 새로운 기술적 도전들이 많이 있을 것입니다.네 그렇습니다. 결론은 기술적 난제들을 고민하면서 좋은 팀과 서비스를 함께 만들고 키워나갈 좋은 분들을 기다리고 있다는 것입니다.
조회수 1303

공포의 Swift3

라이비오를 시작하며 이전 사업과는 다르게 어쩔 수 없이 안고 출발했던 핸디캡이 있었다."너는 개발자가 아니잖아."사실이다.아무래도 위제너레이션이나 오드리씨를 할 때는 영업과 마케팅 위주의 조직이었다보니 급하면 급한대로 내가 직접 할 수 있는 것들이 많았다. 하지만 앱 개발은 완전 다른 차원의 이야기라 (디자인은 직접 맡고 있지만) 새롭게 배워야 할 부분이 정말 많았다.'그래도 이제와서 어떻게 개발을 배우겠어.' 싶어서 공부를 시작했다가 그만두기도 몇 번.개발의 ㄱ자라도 잡아보자 싶어 HTML이나 CSS, PHP 같은 언어들을 끄적끄적 공부해보곤 했었는데, 기본서 수준이거나 Codecademy 따라해 본 것이 전부이다보니 실제로 뭔가를 해 볼 수준에는 전혀 미치지 못했다.그래서 이번에는 돈을 좀 쓰더라도 독학 말고 수업을 들어보자고 생각했다.새해를 맞아 큰 맘 먹고 백만원 상당의 패스트캠퍼스 수업을 질러 Swift3 를 배우게 되었다. (iOS 개발언어)(나만의 앱을 만들고 싶은데 넘나 어려운 것..........)벌써 오늘이 11강째인데 전체가 16강인 것을 생각하면 어느새 진도를 많이 뺐다.그런데 문제는,초기 문법 배울 때는 괜찮았는데예제 따라하기로 들어가면서부터 수준이 높아져 따라갈 수가 없다는 것이다.특히 지난 주에는 수업을 들으면서 동시에 절망하는 수준에 이르렀는데다들 아무 말도 없고 키보드 마우스 소리만 들리기에, 나만 이해를 못하고 있다는 생각에 중반부터는 아예 수업 듣기를 포기하고 조용히 yes24를 켜서 Swift 기본서를 주문했다. (빠른 상황판단ㅋㅋㅋㅠㅠㅠ)그런데 수업을 마친 후 강사님이 "오늘 너무 빨랐나요?"하고 물으니,수강생들이 너도나도 손을 들며 너무 빨랐다고, 놓쳤다고 얘길 하는 게 아닌가!나만 놓친게 아니라는 (어리석은..) 잠깐의 위로를 받았다.하지만 설날이 지나고,이제 좀 더 쉬워졌게지 하는 생각으로 오늘 11강에 들어갔더니 웬걸.여전히 어렵고, 이해가 0되는 현상이 발생했다.역시 공부에는 지름길도 속임수도 없다.아무래도 Swift 책을 때며 따로 복습해야 따라갈 수 있을 것 같다.슬프게도 두께가 이만큼이다. (1473페이지 중에 226페이지까지 복습했다^^............)*강사님이 쓰신 책도 있지만 Objective C 라는 다른 언어와의 비교를 중심으로 설명하셔서 초심자에게는 오히려 어려운 부분이 있었다. 아예 초보에게는 '꼼꼼한 재은씨의 스위프트3 (기본편)' 책을 추천한다. 제목만큼 꼼꼼하게 쓴 책이다. (홍보는 아닙니다만 책이 너무 좋아서 구매링크)뭐 하나 쉬운 것이 없지만, 그래도 서른이 되기 전에 좀 더 제대로 코딩 공부를 해 보게 되어서 다행이다.언어 + 수학 + 논리의 결합인 코딩은 어렵지만 꽤 아름답다.난 문돌이라 못 한다고 한계만 짓지 않으면 충분히 할 수 있을 것 같다.대신 만만하게 생각하지는 말고 꾸준히...........올해 안에 꼭 내 이름으로 된 앱 출시를 해봐야겠다.#라이비오 #비전공개발자 #iOS #Swift #인사이트 #경험공유
조회수 762

HBase상 트랜잭션 라이브러리 Haeinsa를 소개합니다 - VCNC Engineering Blog

비트윈에서는 서비스 초기부터 HBase를 주요 데이터베이스로 사용하였습니다. HBase에서도 일반적인 다른 NoSQL처럼 트랜잭션을 제공하지 않습니다. HBase, Cassandra와 MongoDB는 하나의 행 혹은 하나의 Document에 대한 원자적 연산만 제공합니다. 하지만 여러 행에 대한 연산들을 원자적으로 실행할 수 있게 해주는 추상화된 트랜잭션 기능이 없다면 보통의 서비스 개발에 어려움을 겪게 됩니다. 비트윈 개발팀은 이런 문제를 해결하기 위해 노력했으며, 결국 HBase에서 트랜잭션을 제공해주는 라이브러리인 Haeinsa를 구현하여 실제 서비스에 적용하여 성공적으로 운영하고 있습니다. VCNC에서는 Haeinsa를 오픈소스로 공개하고 이번 글에서 이를 소개하고자 합니다.Haeinsa란 무엇인가?Haeinsa는 Percolator에서 영감을 받아 만들어진 트랜잭션 라이브러리입니다. HAcid, HBaseSI 등 HBase상에서 구현된 트랜잭션 프로젝트는 몇 개 있었지만, 성능상 큰 문제가 있었습니다. 실제로 서비스에 적용할 수 없었기 때문에 Haeinsa를 구현하게 되었습니다. Haeinsa를 이용하면 다음과 같은 코드를 통해 여러 행에 대한 트랜잭션을 쉽게 사용할 수 있습니다. 아래 예시에는 Put연산만 나와 있지만, 해인사는 Put외에도 Get, Delete, Scan 등 HBase에서 제공하는 일반적인 연산들을 모두 제공합니다.HaeinsaTransaction tx = tm.begin(); HaeinsaPut put1 = new HaeinsaPut(rowKey1); put1.add(family, qualifier, value1); table.put(tx, put1); HaeinsaPut put2 = new HaeinsaPut(rowKey2); put2.add(family, qualifier, value2); table.put(tx, put2); tx.commit(); Haeinsa의 특징Haeinsa의 특징을 간략하게 정리하면 다음과 같습니다. 좀 더 자세한 사항들은 Haeinsa 위키를 참고해 주시기 바랍니다.ACID: Multi-Row, Multi-Table에 대해 ACID 속성을 모두 만족하는 트랜잭션을 제공합니다.Linear Scalability: 트래픽이 늘어나더라도 HBase 노드들만 늘려주면 처리량을 늘릴 수 있습니다.Serializability: Snapshot Isolation보다 강력한 Isolation Level인 Serializability를 제공합니다.Low Overhead: NoSQL상에서의 트랜잭션을 위한 다른 프로젝트에 비해 오버헤드가 적습니다.Fault Tolerant: 서버나 클라이언트가 갑자기 죽더라도 트렌젝션의 무결성에는 아무 영향을 미치지 않습니다.Easy Migration: Haeinsa는 HBase를 전혀 건드리지 않고 클라이언트 라이브러리만 이용하여 트랜잭션을 구현합니다. 각 테이블에 Haeinsa 내부적으로 사용하는 Lock Column Family만 추가해주면 기존에 사용하던 HBase 클러스터에도 Haeinsa를 쉽게 적용할 수 있습니다.Used in practice: 비트윈에서는 Haeinsa를 이용하여 하루에 3억 건 이상의 트랜잭션을 처리하고 있습니다.Haeinsa는 오픈소스입니다. 고칠 점이 있다면 언제든지 GitHub에 리포지터리에서 개선에 참여하실 수 있습니다.Haeinsa의 성능Haeinsa는 같은 수의 연산을 처리하는 트랜잭션이라도 소수의 Row에 연산이 여러 번 일어나는 경우가 성능상 유리합니다. 다음 몇 가지 성능 테스트 그래프를 통해 Haeinsa의 성능에 대해 알아보겠습니다.아래 그래프는 3개의 Row에 총 6개의 Write, 3개의 Read연산을 수행한 트랜잭션의 테스트 결과입니다. 두 개의 Row에 3Write, 1Read 연산을 하고, 한 개의 Row에 1Read 연산을 한 것으로, 비트윈에서 가장 많이 일어나는 요청인 메시지 전송에 대해 시뮬레이션한 것입니다. 실제 서비스에서 가장 많이 일어나는 종류의 트랜잭션이라고 생각할 수 있습니다. 그런데 그냥 HBase를 사용하는 것보다 Haeinsa를 이용하는 것이 더 오히려 좋은 성능을 내는 것을 알 수 있습니다. 이는 Haeinsa에서는 커밋 시에만 모든 변경사항을 묶어서 한 번에 반영하기 때문에, 매번 RPC가 일어나는 일반 HBase보다 더 좋은 성능을 내는 것입니다.HBase 클러스터가 커질수록 트랜잭션 처리량이 늘어납니다. HBase와 마찬가지입니다.HBase 클러스터의 크기에 따른 응답시간 입니다. HBase와 다르지 않습니다..아래 그래프는 2개의 Row에 각각 한 개의 Write, 나머지 한 개의 Row에는 한 개의 Read 연산을 하는 트랜잭션에 대해 테스트한 것입니다. 각 Row에 하나의 연산만이 일어나기 때문에 최악의 경우라고 할 수 있습니다. 처리량과 응답시간 모두 그냥 HBase를 사용하는 것보다 2배에서 3배 정도 좋지 않은 것을 알 수 있습니다. 하지만 이 수치는 DynamoDB 상의 트랜잭션과 같은 다른 트랜잭션 라이브러리와 비교한다면 상당히 좋은 수준입니다.HBase보다 처리량이 떨어지긴 하지만, 클러스터가 커질수록 처리량이 늘어납니다.HBase보다 응답시간이 크긴 하지만 클러스터 크기에 따른 변화가 HBase와 크게 다르지 않습니다.프리젠테이션Haeinsa에 대한 전반적인 동작 원리와 성능을 소개하는 프리젠테이션입니다. 좀 더 자세히 알고 싶으시다면 아래 프리젠테이션이나 Haeinsa 위키를 참고해주세요.<iframe class="speakerdeck-iframe" frameborder="0" src="//speakerdeck.com/player/2d4b2bd00fc201314ae312fe4cd13937?" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" style="border: 0px; background: padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 750px; height: 563px;">
조회수 2296

Dropwizard와 Asynchronous HBase 적용기

Background워크인사이트 서비스는 루비 온 레일즈 기반으로 작성된 웹 애플리케이션입니다. 주로 사용하는 데이터의 대부분은 HBase에 저장되어 있습니다. HBase는 자바로 작성된 API를 기본으로 제공하므로, 레일즈가 직접 HBase의 데이터에 접근할 수 없습니다. 따라서 데이터를 효과적으로 읽어들이기 위해서는 두 가지 방법 중 하나를 선택해야 합니다. 첫 번째는 HBase Java API를 이용하기 위해 웹 애플리케이션 역시 자바 기반의 프레임워크로 재작성하는 것이고, 두 번째는 HBase 스토리지 측 데이터 형식과 레일즈 웹서비스 측 데이터 형식을 서로 연결해주는 RPC 중개자를 도입하는 것입니다. 첫 번째 방법은 프로그래밍 언어를 통일함으로써 데이터 통신의 일관성은 물론 시스템 안정성이나 성능 측면에서 좀 더 낫다는 장점이 있는 반면에, 현재까지 작성한 레일즈 애플리케이션을 전부 자바 기반의 프레임워크로 재작성해야한다는 단점이 있습니다. 두 번째 방법은 보다 범용성을 지향하는 방식으로 향후 시스템의 확장에 좀 더 유용하지만, 첫 번째 방법보다 시스템 전체 성능은 뒤떨어진다는 단점을 갖고 있습니다.당시에는 이미 워크인사이트의 개발이 상당히 진척된 상태였기 때문에, 레일즈 프레임워크를 그대로 유지하면서 자바와 소통할 수 있는 JRuby를 사용하는 것이 최선인 것 같았습니다. 하지만 실험 결과 JRuby는 실 사용할 수 없을 정도의 성능을 냈습니다. 무엇보다도 레일즈 지원이 아직 미성숙한 상태였고, 사용중인 루비 젬 중에도 네이티브 C 구현 루비만 지원하는 젬이 상당 수 있었으며, 이러한 이유들로 인해 결국 JRuby는 대안에서 제외되었습니다. 루비 온 레일즈를 버리고 다른 자바 기반 프레임워크로 전면 재작성하기에는 너무 큰 소모비용과 위험요소가 있었기에 다른 방식을 고려하게 됩니다.그래서 조이는, 앞서 말한 크게 두 가지의 대안 중 두 번째, 범용 데이터 중개자를 도입하기로 결정하고, Thrift를 선택하기로 결정하였습니다. Thrift는 페이스북에서 처음 개발하였고, 현재는 아파치 재단에서 관리하고 있는 범용 RPC 프레임워크입니다. 비슷한 기능을 가진 다른 프레임워크로는 구글의 Protocol Buffer나 아파치 Avro등이 있습니다만, Thrift를 선택한 이유는 지원하는 프로그래밍 언어의 종류가 가장 다양하다는 것이었고, 워낙 많은 사용 사례가 있어 신뢰성이 검증되었다는 판단을 했기 때문입니다. Thrift는 그 규모에 걸맞게 다양한 플랫폼별 배포판을 지원하고 있으며, 조이는 현재 사용중인 하둡 시스템 관리용 Cloudera manager를 지원하는 배포판을 이용하여 디플로이하였습니다. 레일즈와의 연동도 thrift젬을 이용하여 손쉽게 할 수 있었습니다. 테스팅 결과도 문제 없었고, 이것으로 모든 것이 잘 돌아가는 줄 알았습니다.그림1. Thrift를 적용한 ZOYI Back-end SystemProblem워크인사이트는 런칭 이후 지금까지 가파른 성장세를 이어오고 있습니다. 서비스 초기에 느긋한 속도로 성장하던 적용 매장 증가 추세는, 2015년 현재 기하급수적으로 증가하는 상승곡선을 그리고 있으며, 그에 따른 시스템의 스케일 업 & 아웃 이슈도 매 달 새롭게 발생하고 있습니다.그림2. 오픈 이후 워크인사이트가 구동 중인 실제 매장 수문제없이 잘 굴러갈 것만 같았던 Thrift서비스 역시 조이의 성장세에 따라 점차 부하가 걸리기 시작했는데, 당초에 기대했던 범용 RPC 프레임워크가 보장하는 확장성과 동시성과는 조금 다른 성격의 문제가 발생하게 되었습니다. 시스템에 대규모 질의가 집중되는 시점에 병목 현상이 발생하고, 이것이 CPU와 메모리의 한도를 초과하면 그대로 다운되는 현상이었습니다. 특히 메모리 사용량이 복구되지 못하고 계속 쌓여만 가는 누수 현상이 치명적이었습니다. 게다가 이렇게 다운된 Thrift가 재시작된 경우, 레일즈와의 연결을 복구하지 못하는 현상도 비주기적으로 발생하였습니다.조이의 하둡 클러스터는 본래부터 확장성을 고려하여 설계되었기 때문에, Thrift에서 발생한 이러한 문제는 생소한 것이었습니다. 다각도에서 테스트를 해 봤지만, 처음에는 원인을 파악하기가 쉽지 않았습니다. 리부트된 클러스터도 자가 복구가 되지 않아, 개발팀이 직접 클라우데라 매니저를 주시하고 있다가 Thrift 서버의 다운 시점에 수동으로 재시작을 해 줘야 하기도 했습니다. 데이터 변환 프로토콜의 문제인지 검토해 보았으나, Thrift 프로토콜이 갖는 본질적 결함은 더더욱 아니었습니다. 자바 언어가 갖고 있는 내재적 결함도 아니었습니다. HBase가 제공하는 자바 API의 문제도 아니었습니다.하지만 심도 있는 검증 과정을 통해, Thrift의 가비지 컬렉션이 제대로 작동하지 않는 문제를 발견하였고, 이는 단순히 Thrift의 최적화의 문제가 아니라는 결론에 이르렀습니다.Dropwizard그렇게 고심하던 개발팀은, 2014년의 워크인사이트 첫 런칭 시점으로 되돌아가서 생각해보기로 합니다. 당시의 조이가 먼저 생각했던 방식은 JVM 기반의 프레임워크였는데, 자바를 이용하여 서비스 레벨도 구현하면 Thrift에서의 데이터 변환 과정에서 야기되는 문제를 원천적으로 방지할 수 있음에 다시금 주목하게 되었습니다. 많은 프로그래밍 언어간의 데이터 통신을 위해 설계된 Thrift는 사실 레일즈와 자바로 균일하게 구축된 조이 시스템에는 필요 이상으로 무겁고 큰 프레임워크였습니다. 조이가 겪은 이런 Thrift의 문제를, 해외의 여러 기업들도 경험하였고 각기 다른 방법으로 최적화를 진행한 것도 알게 되었습니다. 이렇게 된 이상 바꿀 수 밖에 없었던 것입니다.그래서 다음 대안을 찾기 위해 많은 리서치와 스터디를 진행했습니다. 넘쳐나는 프레임워크들의 홍수 속에서 가볍고 안정적이며 구현이 편리한 프레임워크를 찾기란 쉽지 않았습니다만, 결국 Dropwizard라는 자바 프레임워크를 도입하기로 결정하게 됩니다. Dropwizard는 이미 잘 알려져 있는 Spring이나 Play 등과 같은 풀 스택 자바 프레임워크와는 다른, 경량 REST API 프레임워크입니다. Dropwizard는 모듈화가 잘 되어 있고, 숙성된 자바 생태계의 안정적인 라이브러리(Jetty, Jersey, Jackson)들을 사용하였으며, 모던 자바에 걸맞는 방식(리플렉션, 동시성 등)을 사용하기 쉽게 패키징되어있습니다. 국내에는 잘 알려지지 않았지만, 해외에서는 이미 Airbnb 등 유수의 스타트업들이 실제 서비스에 사용함으로써 그 유용성을 입증하고 있는 프레임워크입니다.그림3. Dropwizard로 새로 구성된 ZOYI Back-end System다만, 처음 사용하는 프레임워크에 조이의 모든 서비스를 포팅하는 것은 불가능에 가까웠고, 설령 하더라도 엄청난 리스크를 감당할 가치가 있는 지 의문이었습니다. 레일즈가 보장해주는 빠른 기능 구현과 쉬운 배포 및 강력한 ORM 등은 루비 온 레일즈가 주는 최대의 강점이기에, 이를 포기하기는 쉽지 않았습니다. 생산성과 성능, 어느 한 쪽도 놓치고 싶지 않았습니다.그래서 조이는 두 마리 토끼를 다 잡아 보기로 결정합니다. 레일즈의 장점을 유지하면서, Dropwizard의 최대 장점인 HBase 데이터 접근의 유연성도 살릴 수 있는 방법을 찾기로 하였고, 결론적으로 Dropwizard는 기존의 Thrift가 담당하던 데이터 중개자의 역할만을 수행하게 되었습니다. Dropwizard의 잘 나뉘어진 모듈화는 이를 가능하게 해 주었습니다. 모든 모듈을 사용하면 풀 스택 프레임워크에 버금가는 규모의 시스템도 구축할 수 있지만, 필요한 것만 선택하여 사용하면 가볍고 빠르게 작동하는 미들웨어 역할도 가능한 것입니다.Asynchronous HBase, and Java 8Dropwizard가 HBase 연결에 사용한 클라이언트 모듈은 AsyncHBase입니다. Asynchronous HBase는, 타임스탬프 기반 데이터베이스인 OpenTSDB를 만든 팀이 자신들의 제품에 HBase를 연동하기 위해 기존의 HBase 클라이언트인 HTable을 대체하는 모듈을 재작성한 것으로, 완전한 비동기 방식과 넌블록킹 및 스레드 안전성 보장이 강점이라 할 수 있습니다. AsyncHBase와 Dropwizard를 연동하는 것은 매우 수월했습니다. 테스트 결과, 간결한 코드로도 초당 수 만 단위의 동시성을 안정적으로 처리할 수 있음을 검증했습니다. 조이는 OpenTSDB를 실시간 데이터 분석에 사용하고 있어, 해당 팀이 제공하는 제품의 품질과 전망에 대해 신뢰를 갖고 있었습니다. 테스트 결과는 이 신뢰를 더욱 뒷받침해주었고, 본 모듈을 Dropwizard의 HBase 연결 모듈로 선정하게 되었습니다.또한, Dropwizard와 AsyncHBase의 도입과 함께 처음으로 자바 버전 8로의 이식도 진행하게 되었습니다. 자바 8은 람다와 스트림 등 함수형 프로그래밍의 여러 기법을 대거 도입하였고, 자바 특유의 장황한 문법을 조금 더 간결하게 축약할 수 있는 장점이 있습니다. Dropwizard와 AsyncHBase 모두 자바 8과 순조롭게 연동되었으며, 이 결과에 만족한 조이는 기존의 하둡 맵 리듀스 프로젝트 역시 자바 8로 버전업하기로 결정하였습니다.PerformanceDropwizard의 성능 테스트 결과는 만족스러웠습니다. AsyncBase도 기대를 저버리지 않는 결과를 보여 주었습니다. HBase Java API와의 매끄러운 연동은, 성능 측면에서 기존과는 비교할 수 없을 정도의 향상을 보여주었고, 이 덕분에 기존 맵 리듀스 워크플로우 중 일부를 실시간 처리로 옮겨, 좀 더 유연하고 동적인 분석이 가능하게 되었습니다.다음의 비교는 Thrift와 Dropwizard의 각각의 벤치마크 테스트를 100개 동시 작업, 단위당 10000개의 요청으로 수행한 경우의 결과를 나타낸 것입니다.그림4. Thrift 테스트 시의 메모리 사용량Concurrency Level: 100 Time taken for tests: 514.315 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 32090000 bytes HTML transferred: 27600000 bytes Requests per second: 19.44 [#/sec] (mean) Time per request: 5143.151 [ms] (mean) Time per request: 51.432 [ms] (mean, across all concurrent requests) Transfer rate: 60.93 [Kbytes/sec] received Thrift 벤치마크 결과. 전체 수행에 514초가 걸렸습니다.그림5. Dropwizard 테스트 시의 메모리 사용량Concurrency Level: 100 Time taken for tests: 4.599 seconds Complete requests: 10000 Failed requests: 121 (Connect: 0, Receive: 0, Length: 121, Exceptions: 0) Non-2xx responses: 121 Total transferred: 23288000 bytes HTML transferred: 21559452 bytes Requests per second: 2174.25 [#/sec] (mean) Time per request: 45.993 [ms] (mean) Time per request: 0.460 [ms] (mean, across all concurrent requests) Transfer rate: 4944.72 [Kbytes/sec] received Dropwizard 벤치마크 결과. 전체 수행에 4초가 걸렸습니다!그림6. 초당 처리량 (높을수록 좋음)벤치마크 테스팅 시 스레드 분산이 최적화 된 경우에는 최대 100배 이상의 속도 향상이 있었습니다. Dropwizard는 기존 Thrift에 비하여 성능 향상은 물론, 안정성 면에서도 시스템이 다운된 이후에 자동 복구되지 않는 현상도 사라졌습니다. 무엇보다도 짧은 코드만으로 대규모의 질의에도 견고하고 신속하게 반응하는 서비스를 구현할 수 있다는 점이 Dropwizard의 가장 큰 장점입니다.Conclusion유용한 오픈소스 프로젝트는 시장에 너무나도 많이 널려 있습니다. 이 중에 어떤 것을 선택하는가는 소프트웨어 기업에게 중요한 안건이며, 잘못된 결정은 프로젝트 자체는 물론 회사의 생사를 결정하기까지 합니다. 조이는 적합성, 성능, 안정성, 생산성 등 모든 면에서 조이의 서비스와 알맞는 제품을 찾으려고 항상 노력하고 있으며, 가능한 한 넓고 깊은 검증, 분석 및 연구를 통해 최적의 대안을 찾아내고 있습니다. 그 결과, 이번 Dropwizard와 Asynchronous HBase를 도입하여 기존의 Thrift를 대체하는 프로젝트는 예상보다 훨씬 좋은 성과를 낼 수 있었습니다. 국내에는 Dropwizard의 실무 사용기 등을 찾아보기 힘들고, 한글화된 문서 자체도 찾기 쉽지 않은데, 이 글이 앞으로의 선택을 고민하는 분들, 드롭위자드에 관심이 있는 분들께 도움이 될 수 있으면 좋겠습니다.#조이코퍼레이션 #개발팀 #개발자 #개발환경 #업무환경 #인사이트 #경험공유
조회수 1805

Google I/O 2018: Firebase의 새로운 기능

멋진 서비스를 제공하기 위해 잘 만들어진 앱을 개발하는 것은 중요합니다. 하지만 출시 이후 앱 운영을 통해 사용자 Retention과 Engagement를 유지 및 증가시키는 것 또한 앱을 잘 개발하는 것 만큼이나 중요하고 많은 고민과 노력을 들여야합니다. 그런 관점에서 Firebase는 앱을 운영함에 있어서 고민할 법한 다양한 기능들을 적절히 잘 모아놓은 서비스인 것 같습니다.스타일쉐어에서도 Crashlytics, Remote Config, Analytics 등 Firebase에 포함된 서비스들을 잘 활용하고 있습니다. 그래서 Firebase에 개선 및 변경 사항이 있다면 항상 주의 깊게 살펴보고 있습니다.https://events.google.com/io/올해도 어김없이 Google I/O가 개최됐습니다. 역시나 흥미로운 주제들이 많았습니다만, 이번 글에서는 앞서 언급한 Firebase 에 추가된 새 기능을 다룬 ‘What’s new in Firebase’ 세션에 대해서 공유드리고자 합니다.세션에서 주요 골자는 다음 4 가지입니다.ML Kit 베타 시작Test Lab iOS 플랫폼 지원Performance Monitoring 개선Google Analytics 개선이 글에서는 이 4 가지 내용에 대해서 정리하도록 하겠습니다.ML Kit 베타아직까지 베타 버전이긴 합니다만 ML Kit 를 통해 Machine Learning 을 앱에서 쉽게 활용할 수 있다고 하니 Machine Learning 이 한층 가까워진 느낌입니다.ML Kit 는 Android, iOS 양 플랫폼 모두 지원합니다. 따라서 앱에서 Machine Learning 을 활용해 서비스를 제공해보고 싶다면, 양 플랫폼 모두 시도해볼 수 있겠네요.What’s new in Firebase (Google I/O ’18) SlideML Kit 은 기본 API 를 제공합니다. 이 API 들은 Machine Learning 에 대한 폭 넓은 배경지식이 없더라도 충분히 활용할 수 있기 때문에 저처럼 막막한 느낌이 드는 분들은 아래 기본 API 5가지를 사용해서 먼저 친해져보는 것도 좋겠네요.텍스트 추출얼굴 인식바코드 스캔이미지 라벨링렌드마크 인식ML Kit 은 on-device 와 cloud 에서 모두 동작하기 때문에 상황에 맞게 적절한 방식을 사용하면 된다고 합니다. 예를 들어 사진앱 처럼 네트워크 연결이 중요치 않은 서비스의 경우에는 on-device 를 통해 오프라인으로도 동작이 원활하게 만들 수 있겠네요.또한 Machine Learning 에 대한 배경 지식이 충분하다면 TensorFlow-Lite 모델을 통해 직접 원하는 학습을 시킬 수도 있습니다.ML Kit 은 Android, iOS 양 플랫폼 모두 사용 가능하며 기본으로 제공하는 5가지 이외에도 향후에 더 추가될 예정이라고 합니다. 추가될 기능들에 대해서 조금 더 일찍 테스터로서 경험해보고 싶다면 waiting list에 메일을 등록하면 됩니다.Test Lab iOS 플랫폼 지원Test Lab 은 다양한 디바이스를 모두 고려한 앱을 개발하기 어려운 Android 플랫폼의 특징을 보완하기 위한 서비스입니다. 주로 UI 테스팅과 관련된 기능들을 제공하며, 좀더 쉽고 편하게 UI 테스팅을 작성하고 다양한 디바이스에서 테스트할 수 있는 환경을 제공해줍니다.What’s new in Firebase (Google I/O ’18) Slide앱을 서비스 할 때 Android, iOS 어느 한 쪽 플랫폼만 개발하는 경우는 드문 것 같습니다. 그래서인지 Firebase 팀도 iOS 지원에 항상 신경을 쓰는 것 같은 인상을 받았는데, 이번 경우도 그런 느낌이 강하게 듭니다.이번에 추가된 iOS 용 Test Lab 을 활용한다면 출시 전 Android와 iOS 모두 동일한 기준으로 품질 상태를 확인하고 배포할 수 있는 환경을 갖출 수 도 있겠네요. iOS용 Test Lab 은 다음 달에 정식으로 선보일 예정입니다만, 이 기능 또한 일찍 테스터로 참여하고 싶다면 waiting list에 메일을 등록하면 됩니다.Performance Monitoring 개선Performance Monitoring 의 베타 기간이 끝나고 정식으로 서비스를 한다고 합니다. Crash-free 도 중요하지만 사용자 입장에서 고려해봤을 때 앱의 퍼포먼스도 놓치면 안되는 중요한 요소입니다. Performance Monitoring 은 이런 관점에서 인사이트를 얻을 수 있게 도와주는 서비스라고 합니다.What’s new in Firebase (Google I/O ’18) Slide세션에서 강요한 기능은 New Issues Feed 입니다. Performance Monitoring화면의 상단에서 확인할 수 있는 이 기능은 단순한 데이터를 나열하는 것이 아니라 자체적인 분석을 통해 가장 최근에 해결해야할 이슈를 제안합니다.What’s new in Firebase (Google I/O ’18) Slide이 외에도 디바이스에서 렌더링할 때나 네트워크 요청을 할 때의 이벤트들을 기록해서 퍼포먼스 저하 요소들을 보여줍니다. 덕분에 어떤 부분에서 퍼포먼스 저하가 가장 심한지 보다 쉽게 파악할 수 있다고 합니다.Performance Monitoring 은 별도 코드 없이 모든 페이지에서 자동으로 데이터를 수집하고 있으니 별도의 노력없이 인사이트를 얻을 수 있다는 점이 또 다른 장점입니다.Google Analytics 개선What’s new in Firebase (Google I/O ’18) SlideGoogle Analytics 에서 두드러지는 개선 점은 Project level reporting이 가능해졌다는 것 입니다. 플랫폼 별 사용자 특성이 있기는하지만 하나의 서비스 차원에서 병합해서 데이터를 보고싶은 경우가 종종 있는데, 그럴 때 마다 별도의 서버 처리를 통해 병합하는 과정이 번거로웠습니다. 하지만 이번 개선을 통해서 프로젝트 단위의 데이터 분석이 가능해진 덕분에 번거로움을 좀 덜어낼 수 있겠습니다.그리고 세션에서 언급하진 않았지만, Filter가 조금 더 유연해지고 세분화된다고 합니다.지금까지 ‘Google I/O 2018: What’s new in Firebase’ 세션 중 주요 내용만 간단하게 살펴봤습니다. Firebase 는 매년 발전을 거듭해가며 앱 운영의 통합 관리 서비스로서의 자리매김을 해나가는 중인 것 같습니다. 덕분에 직감에만 의존해서 앱의 방향을 정하던 예전에 비해 정량적 데이터에 기반을 두며 더 성공에 가깝게 한발짝 씩 다가갈 수 있는 것 같습니다.이번에 Firebase 에 새로 추가된 기능들을 조금씩 건드려보면서 우리 서비스에서 어떻게 활용하며 인사이트를 얻고, 서비스를 이용하는 사용자들에게 더 나은 서비스를 제공해 줄 수 있을까 고민해봐야겠습니다.#스타일쉐어 #개발자 #개발팀 #인사이트 #Firebase #경험공유 #일지 #후기
조회수 4211

LSTM Tutorial

Summary:이 포스팅은 LSTM에 대한 기본 개념을 소개하고, tensorflow와 MNIST 데이터를 이용하여 구현해봅니다.LSTM1. 개념 설명LSTM(Long Short Term Memory)은 RNN(Recurrent Neural Networks)의 일종으로서, 시계열 데이터, 즉 sequential data를 분석하는 데 사용됩니다.기존 RNN모델은 구조적으로 vanishing gradients라는 문제를 가지고 있습니다. RNN은 기본적으로 Neural network이기 때문에 chain rule을 적용하여 backpropagation을 수행하고, 예측값과 실제 결과값 사이의 오차를 줄여나가면서 각 시간 단계의 gradient를 조정합니다. 그런데, 노드와 노드(시간 단계) 사이의 길이가 길어지다보면, 상대적으로 이전의 정보가 희석됩니다. 이 문제는 시퀀스 상 멀리 떨어져 있는 요소, 즉 오래 전에 발생한 이벤트 사이의 연관성을 분석할 수 없도록 만듭니다.LSTM은 RNN의 문제를 셀상태(Cell state)와 여러 개의 게이트(gate)를 가진 셀이라는 유닛을 통해 해결합니다. 이 유닛은 시퀀스 상 멀리 있는 요소를 잘 기억할 수 있도록 합니다. 셀상태는 기존 신경망의 은닉층이라고 생각할 수 있습니다. 셀상태를 갱신하기 위해 기본적으로 3가지의 게이트가 필요합니다. Forget, input, output 게이트는 각각 다음과 같은 역할을 합니다.Forget : 이전 단계의 셀 상태를 얼마나 기억할 지 결정합니다. 0(모두 잊음)과 1(모두 기억) 사이의 값을 가지게 됩니다. Input : 새로운 정보의 중요성에 따라 얼마나 반영할지 결정합니다. Output : 셀 상태로부터 중요도에 따라 얼마나 출력할지 결정합니다.게이트는 가중치(weight)를 가진 은닉층으로 생각할 수 있습니다. 각 가중치는 sigmoid층에서 갱신되며 0과 1사이의 값을 가지고 있습니다. 이 값에 따라 입력되는 값을 조절하고, 오차에 의해 각 단계(time step)에서 갱신됩니다.2. 응용 (MNIST data)MNIST는 손으로 쓴 숫자 이미지 데이터입니다. 하나의 이미지는 가로 28개, 세로 28개, 총 784개의 값으로 이루어져 있습니다.Many-to-One model는 여러 시퀀스를 넣었을 때 나오는 최종 결과물만을 이용하는 모델입니다. 이를 이용하여 784개의 input으로 1개의 output값(A) 을 도출합니다. 이 A를 하나의 층에 통과시켜 10개의 숫자 label중 하나를 할당합니다.784개의 입력값을 사이즈가 28인 벡터가 28번 이어지는 시퀀스(time step)로 보고, input의 크기를 28, 시퀀스 길이를 28로 각각 설정합니다. 28개의 input은 C라고 표현되어 있는 LSTM 셀로 순차적으로 들어가게 됩니다.output의 크기는 셀의 크기와 같으며, 64로 설정하였습니다. 셀크기가 너무 작으면 많은 정보를 담지 못하기 때문에 적당히 큰 값으로 설정합니다. 전체 output은 64개의 값을 가지고 있는 벡터 28개의 집합이 되고, 마지막 벡터만 사용합니다.1층의 fully connected layer를 이용하여 64차원 벡터를 10차원으로 줄이고 softmax를 이용하여 0부터 9까지 중 하나의 값을 예측합니다.LSTM으로부터 나온 예측값을 실제갑과 비교하여 cost를 개산합니다. cost function은 cross-entropy를 이용합니다. AdamOptimizer를 이용하여 cost를 최소화하는 방향으로 모델을 최적화 시킵니다.3. 토의구현 시 어려웠던 점을 중심으로 서술하였습니다. 전체 코드는 여기를 참고해주세요.batch sizebatch_size = 128 batch_x, batch_y = mnist.train.next_batch(batch_size) MNIST의 train data의 크기는 55,000개 입니다. 이는 (55000, 784) 크기의 데이터를 학습시켜야 한다는 것을 의미합니다. 이것을 한번에 학습시킨다는 것은 매우 어려운 일입니다. 전체 데이터를 메모리에 올리기 힘들뿐만 아니라, 너무 큰 data 한번에 학습시키면 가장 작은 cost값으로 수렴하기 힘들어진다는 문제가 있습니다. (너무 작아도 마찬가지입니다.) 그렇기 때문에 큰 덩어리를 일정크기의 작은 덩어리로 잘라서 모델에 넣어 학습시는데, 이 작은 덩어리의 크기를 batch size라고 합니다.작은 덩어리로 짜르는 것이 중요한 이유는, 작은 덩어리 단위로 모델에 밀어넣고(propagation) 네트워크의 파라미터들을 조정(update)하기 때문입니다. batch size는 분석하려고 하는 데이터가 어떻게 구성되어있는지에 따라 결정되는 경우가 많습니다. 어떤 수준의 batch size가 좋다고 이야기하기 어렵고, 아주 크지 않은 값으로 설정합니다.unstack모델 구현 시 static RNN을 사용하였습니다. Static RNN에서는 unstack을 해주지 않으면 TypeError가 발생합니다.unstack( value, num=none, axis=0, name=‘unstack’)unstack은 R차원(rank)의 데이터를 R-1 차원으로 줄여주는 역할을 합니다. value로부터 axis 차원을 기준으로 num개로 자른다고도 할 수 있습니다. 이 예제로 예를 들어보겠습니다.batch_x = batch_x.reshape((batch_size, input_steps, input_size)) x = tf.unstack(X, input_steps, axis=1) outputs1, states1 = tf.nn.static_rnn(lstm_cell, x, dtype=tf.float32) 실제 학습이 진행되는 순서로 보자면, batch size만큼 불러온 인풋 데이터는 (128, 784)에서 (128, 28, 28) 형식의 3차원 벡터로 reshape해 줍니다. 그리고 다시 unstack을 통해 time step을 기준으로(axis=1) 28개의 텐서를 만듭니다. 다시말해, (128, 28, 28)이라는 3차원 형식의 벡터는 (128, 28)이라는 2차원 벡터 28개로 변환되어 모델에 입력되게 됩니다. 이런 변환이 필요한 이유는 28*28의 크기를 가진input들을 차례로 넣게 되면 처리속도가 제한적이기 때문입니다. unstack을 이용하면 하나의 batch 안에 있는 input을 한꺼번에 한줄씩 병렬적으로 처리할 수 있게 됩니다.Dynamic RNN에서는 unstack을 해주는 과정이 필요 없습니다. Static과 Dynamic의 차이는 추후 포스팅에서 자세히 다루도록 하겠습니다.Training cycle참고한 다른 예제코드들은 서로 다른 스타일의 사이클로 학습시키고 있었습니다. 스타일은 크게 두가지로 나누어볼 수 있었습니다. 하나의 방법은 전체 학습 횟수를 정해놓고 while문을 통해 학습시키는 방법이었습니다. 다른 방법은 똑같은 데이터를 몇번 반복해서 학습시킬지 결정하는 것입니다. 이 반복 횟수를 epoch이라고 합니다. epoch의 사전적 의미는 ‘시대’ 또는 ‘세’이지만 예제 코드에서 만나는 epoch은 전체 데이터를 학습시키는 반복회수라고 이해하시면 되겠습니다. (이 두가지 방법은 스타일의 문제일 뿐입니다. 이것을 언급한 이유는 개인적으로 epoch을 처음 접했을 때 생소했기 때문입니다.for epoch in range(training_epochs): avg_cost = 0 total_batch = int(mnist.train.num_examples/batch_size) for i in range(total_batch): batch_x, batch_y = mnist.train.next_batch(batch_size) batch_x = batch_x.reshape((batch_size, input_steps, input_size)) c, _ = sess.run([cost2, optimizer2], feed_dict={X:batch_x, Y:batch_y}) avg_cost += c/total_batch 위의 코드는 두번째 스타일이고, 각 epoch마다 cost값과 test data로 예측의 accuracy를 계산하여 출력하였습니다. 당연하게도 학습이 반복 될수록 cost는 감소하고 accuracy는 증가하였습니다.4. 정리기본적으로 도식을 통해 input size, time step, hidden_size에 대한 개념을 이해하는 것이 도움이 됩니다.tensor의 shape을 이해하는 것이 중요하다고 생각합니다. input과 output의 형식(shape)을 머리속에 떠올릴 수 있다면 에러를 줄일 수 있고 해결하기도 수월합니다.batch size의 의미, unstack을 하는 이유, epoch의 의미를 알아두면 좋겠습니다.ReferenceDEEPLEARNING4J 초보자를 위한 RNNs과 LSTM 가이드Colah’s blog, Understanding LSTM Networks이태우, 엘에스티엠 네트워크 이해하기김성훈, 모두의 딥러닝 lec 9-2. Vanishing gadient
조회수 1669

데이터, 기록되고 있습니까?

올해 2월에 썼던 글을 이제야 올려봅니다. 태블로는 아직 잘 사용하고 있습니다. : )“아무개 님, 지난번에 요청한 자료 언제까지 받을 수 있죠?”다행이다. 꿈 이었다.가벼운 발걸음으로 출근하던 중 일감 하나가 떠오른다. 간밤의 꿈이 꿈 만은 아니었던게다.아뿔싸, 아직 시작도 못했는데.오늘 할 일을 내일로 미룬 자의 아침은 발걸음이 무겁다.Business Intelligence 라는 것이 있다. 뭔가 멋드러진 단어의 조합처럼 보이지만, 현실은 그리 아름답지 않다. 대부분의 시간을 비슷한 일을 반복하며 숫자를 맞춰야하고 엑셀과 SQL 에 빠져 살기 일쑤다. 잘못된 데이터라도 발견되면 이걸 어디서부터 수습해야 하나 고민해야 한다. (끝이 없는 재귀호출)반복, 반복, 반복. 비용을 줄이자.반복은 비용이다. 한두번 반복되는 일을 최적화 하는 것은 최적화 자체가 비용 이겠지만, 매일같이 반복되는 일, 주기적으로 찾아야 하는 데이터들은 그 자체만으로도 최적화의 대상이다.특히나, 아직 성장하고 있는 ‘스타트업’ 이라면 회사의 데이터가 잘 정리되어 있을리 만무하다. 몇몇 데이터는 잘 관리되고 있겠지만, 상당수는 흩어져 있을 것이다. 어느 순간을 지나면 이들을 모으는 게 일이 되어버린다. 임계점을 넘어서버린 일을 한다는 것은 손을 더럽히는 일이 된다는 뜻이기도 하다. 아무쪼록 그대에게 이 임계점을 분간할 지혜가 있기를.시간 비용을 절약하자스타트업의 구성원들에게 가장 중요한 것은 무엇일까? 나의 짧은 생각으로는 사람과 시간이라고 생각된다. 이 중에서 BI 툴이 해결해 줄 수 있는 것은 무엇일까?나 스스로에게 질문해보니 이런 답이 나온다. ‘사람은 쉽게 바뀌지 않는다’ 그럼 시간은? 다행히, 시간은 모두에게 공평하게 주어진다.‘그럼 이 시간을 아껴보자!’여기에 하나 더, 내가 모르는 것이 있었다.앞으로 회사가 데이터를 다루는 스펙트럼을 얘상할 수 없다는 것이다.Zeppelin무엇을 사용할까 고민하던 중 가장 먼저 떠오른 것은 다름 아닌 제플린 이었다.< 이 형님들 말고 >(출처 : http://fortune.com/2016/07/26/led-zeppelin-stairway-heaven-appeal/)아파치 제플린은 한국에서 시작해 아파치 인큐베이터에 들어간 오픈소스 데이터 분석 및 시각화 툴 이다.장점은 개발자에게 익숙한 노트북 기반이라는 것과 강력한 인터프리터를 통해 다양한 데이터 소스에 접근할 수 있다는 것이다.나프다 팟캐스트에서 들은 내용인데, 트위터의 경우 태블로에서 제플린으로 갈아탔다는 이야기도 있었다.기본적으로 프로그래밍이 가능하기 때문에 어떤 형태의 데이터를 요구해도 제공할 수 있다는 장점도 있다.물론, 단점도 있다. 먼저 시각화 부분이 약하다는 것이다. D3.js 를 같이 사용하면 보완할 수 있지만 개발자의 꾸준한 지원이 있어야 할 것이었다.더불어, 비개발자들에겐 노트북 형태로 데이터를 가공하는 것에 진입장벽이 있다고 생각 했다.한번쯤 사용해보고 싶었지만 개발 리소스가 부족한 우리 상황에는 맞지 않다고 생각했기에 다음을 기약해본다.Spotfire, Amazon Quicksight, Google Data Studio다음으로 찾아본 툴 들은 바다 건너에서 잘 사용 되는 몇가지 것들 이었다.Spotfire 는 레퍼런스도 충분했지만 다음에 등장한 강력한 후보로 인해 제외됬다.아마존 퀵사이트는 잠깐 사용해봤지만 회사의 요구사항을 맞추는데 부적절해 보였다.구글의 데이터 스튜디오 역시 기능에 제약이 많았다.아마존과 구글의 솔루션은 무료로 사용할 수 있거나 가격이 합리적이라는 장점도 있었다.Spotfire 역시 비싸지 않은 가격이었다.태블로, 그리고 plotly태블로는 동료 직원의 지인 중 사용해본 분이 있어서 직접 만나서 여러가지를 물어볼 수 있었다. 나중에 알았지만 한국에 공식 총판이 있어서 메일로 문의하면 다양한 안내를 받을 수 있었다.태블로는 장점이 많은 툴이다. 다양한 데이터 소스를 지원하며, 강력한 시각화를 통해 데이터를 분석할 수 있다.데이터를 유연하게 다룰 수 있어서 여러가지 인사이트를 얻는데 도움을 줄 것이라 생각됐다.온라인 튜토리얼도 잘 되어있고, 한국에서 오프라인으로 기초교육도 받을 수 있다.종합적으로 비교해 본 결과 비슷한 성격의 툴 중에선 가장 강력한 툴 이었다.유일한 단점이라면 가격이다.plotly 는 리서치 중 가장 마지막으로 접했는데 대시보드로도 사용할 수 있고 노트북에도 붙일 수 있는 라이브러리 형태로 제공되는 툴 이었다.데이터 분석에 주로 사용되는 파이썬, R, 매트랩에 모두 사용 가능했고 훌륭한 시각화도 가능했다. 학생이라면 아주 저렴한 가격으로도 이용이 가능하다.단점이라면, 개발자에게 더 친화적 이라는 것과 데이터 커넥터가 태블로에 비해 부족하다는 것 이었다.BI 툴, 개발자와 분석가 중 누구에게 더 쉬워야 할까?회사마다 개발자의 비중이 다르다. 스타트업 이라고 해서 개발자들로만 이루어진 것도 아니고, 이미 안정적으로 비즈니스를 운영하는 회사라고 해서 개발자가 적은 것도 아니다.각 회사가 처한 상황에 따라 어떤 툴을 사용할 지는 다를 것이다.나는 우리 회사가 어떤 BI 툴을 써야 최적일지 생각해 봤다.같은 작업을 하는데 있어서 시간을 줄여줄 수 있어야 하고, 앞으로의 변화에 유연하게 대응할 수 있는 툴이었으면 했다.개발자의 지원을 최소화 하면서 비즈니스를 이해하는 분들이 적극적으로 사용하는데 어려움이 없었으면 했다.가격적인 면도 중요했지만, 국내에서 사용하는데 참조할 수 있는 레퍼런스, 교육이 풍부한 것도 선택에 한 축이 되었다.모든 것을 종합해 본 결과 태블로 만한 것이 없다고 생각됐다.< 이제 데이터와 사랑에 빠져 볼까? >(출처 : https://www.youtube.com/watch?v=2onPdVj5zgQ)여러분들의 상황은 어떤가.지금 사용중인 툴이 충분한 효과를 가져다주고 있는가? 혹시 기존에 익숙하던 것을 습관적으로 사용하고 있지는 않나?대부분의 스타트업은 부족한 인원으로 복잡한 이슈를 해결하기 위해 고군분투 중일 것이다.특별히, 데이터를 들여다보고 최적화를 해야하는 업무를 담당하는 사람이라면 지금 이 순간도 머리를 싸메고 고민에 빠져 있을 것이라 생각된다.데이터 때문에 잠이 부족한 그대에게, 비슷한 고민을 하는 분들에게, 아무쪼록 이 글이 조금이나마 도움이 되었기를 바란다.#8퍼센트 #에잇퍼센트 #협업 #업무프로세스 #팀워크 #수평적조직
조회수 1065

블록체인 진짜 하나도 모르는 디자이너의 독학일기(2)

1편에 이어 2편을 작성하기까지 참으로 많은 시간이 걸렸답니다. 물론 내용이 어려워서 이해하는 데 시간이 걸린 것도 있고... 어려운 만큼 귀차니즘이 강해져서 미루고 미룬 이유도 있지요.1편에선 블록체인이 왜 발생했는가! 에 대해서 말했어용. 혹시라도 못 보신 분들은 링크를 타고 슝 한 번 더 보고 와주시면 좋을 것 같습니다.https://brunch.co.kr/@roysday/199짧게 줄이자면, 결국 신뢰의 문제 때문이예요. 내가 널 뭘 믿고??? 라는 명제죠. 단순히 너와 나의 사이뿐만 아니라 정부나 기업 등이 해커나 서버폭발 등으로 탈탈 털리는 일을 보면서 우린 두려워진 거예요. 은행을 믿을 수 있어?? 보험사를 믿을 수 있어?? 국민연금 겁나 떼가는데 나중에 받을 수는 있는거야?? 등등...그래서 우린 누구도 깰 수 없고 변하지 않고 삭제도 되지 않는 강력한 '장부'를 만들고 싶었던 거예요. 그래서 생각해낸 가장 좋은 방법이 바로 다수에게 뿌리는 거였죠. 하지만 우린 이런 궁금증이 생겨요. 다수라구??...누가 참여하는데?? 내 컴퓨터엔 블록체인 같은 게 없는데??사실 이 부분을 이해하기가 진짜 어려웠어요. 아니 페이스북에 투표참여나 주식시장같이 '내가 이걸 산다! 투표한다! 동의한다! 클릭~!' 이런 식의 동작이 없잖아요. 그런데 어떻게 내가 동의를 했는지 안했는지 내 장부에 뭐가 언제 어떻게 기록된다는 거야??....는 궁금증이 생기는 거죠.그래서 오늘은 이 과정을 쉽게 정리해보려고 해용 :) 혹시 틀린 부분이 있다면 꼭!! 댓글로 남겨주세요!!1. 컴퓨터에게 말을 걸어보자.지금 컴퓨터를 켜고 이렇게 외쳐보세요. "윙가르디움 레비오싸."네, 아무일도 일어나지 않았어요. 혹시 무슨 일이 일어나셨다면 소름이네요. 컴퓨터는 마법주문이나 우리의 감정이나 목소리나 표정을 인식하지 못해요.(물론 요즘엔 이걸 가능하게 만들고 있어요. 놀라워요. 하지마 마법주문은 좀 시간이 걸릴 것 같아요.) 일본은 일본어를 쓰고 중국은 중국어를 쓰고 스페인은 스페인어를 써요. 컴퓨터는 2진법을 써요. 얘네들은 0 아니면 1이라는 원시적인 언어를 쓰고 있어요. 물론 인간도 아주아주 오래전엔 2진법으로 언어를 말했어요. 쿼스랜드는 원시인들은 'a(아)'와 'o(오)' 만을 사용해서 숫자를 표현했다고 해요. 아, 오, 아오아, 오아오아..등으로 말이죠. 컴퓨터는 이처럼 0와 1로 이루어진 신호들을 통해 소통해요. 그러니 우리가 컴퓨터에게 말을 걸고싶다면 2진법으로 0과 1을 마구마구 적어줘야 해요.2. 컴퓨터의 언어를 만들었졍.근데 0과 1로만 말을 걸다보니 도대체 눈이 아프고 헷갈려서 너무 어려운 거예요. 그래서 규칙을 만들었어요.A = 100 0001B = 100 0010C = 100 0011D = 100 0100...이런식으로 알파벳이나 기호, 한글 등등을 컴퓨터가 이해할 수 있는 신호와 대응시켰어요. 그래서 나온 게 컴퓨터 언어죠. 오늘 날 코딩이라고 불리는 그것들은 결국 컴퓨터의 말로 이렇게해라 저렇게 해라 명령을 내리는 거예요. 컴퓨터는 그 명령에 의해 이런저런 일들을 처리해요. 이걸 누르면 = 저 페이지로 넘어가게 해.이곳을 채우면 = 다음 칸을 적을 수 있게 해.여길 클릭하면 = 파란색으로 바뀌게 만들어줘.등등 뭔갈 하면 = 결과가 등장하는 거죠. 신기하죠? 네 저도 신기해요. 이렇게 명령어를 입력하면 결과가 짜짠.3. 규칙을 만들 수 있게 되었엉.컴퓨터는 논리에 의해서 움직여요. 뭔가를 누르면 - 계산하고 - 0이면 안하고, 1이면 해요. 사실 되게 단순하게도 '한다/안한다' 로 명확하게 움직여요. 이렇게 명확하기 때문에 사람의 목숨을 담보로 하는 수많은 것들을 만드는 거예요. 비행기도 그렇고, 인공위성, 놀이기구, 자동차 등등... 컴퓨터가 기분따라 오늘은 왠지 일하기 싫어서 땡깡이나 부려버리면 그냥 다 죽는 거잖아요. (물론 가끔 파랗게 질려서 멍청댕청해질 때가 있긴 하지만...)결정장애가 없는 특성 때문에 컴퓨터는 한 번 규칙을 정해주면 그렇게 계속 움직여요. 이런 점에서 보면 인간과 컴퓨터의 가장 큰 특징 중 하나가 '갈등' 이 아닐까 싶어요. 결정장애가 있으신 분들은 엄청 인간적인 매력을 지니신 거예요. 블록체인은 '규칙'이예요. 변하지 않고 계속 그대로 움직이는 규칙이죠.규칙을 컴퓨터에게 명령하는 거예요. 이렇게 하면 이렇게 처리해!~ 알았지? 하고 명령하는 거죠. 이 코드(=명령어)를 누가 짜요? 그렇죠 그걸 블록체인 회사에 있는 개발자님들이 만드는 거예요. 그러니 어떤 블록체인 코드가 만들어지면 처음엔 그 회사 컴퓨터에만 있을 거예요. 4. 사람들을 모아보쟈.명령어를 만들긴 만들었는데, 여튼 이제 돈을 벌어야 하잖아요. 회사니까. 많은 사람들이 우리가 만든 블록체인을 이용해줬으면 좋겠어요. 그래서 사람들을 모아야겠단 생각을 했어요. 사람들에게 막 알리기 시작했어요.블록체인은 다수의 사람들이 이용해야 의미가 있어요. 꼴랑 2명만 쓰고있으면 그 중 한명의 컴터만 털어버려도 장부를 조작할 수 있잖아요. 하지만 수백, 수천만명이 블록체인에 참여하고 있다면 얘기가 달라지죠. 그 많은 사람들의 컴터를 한꺼번에 해킹할 순 없으니까요. 그래서 사람이 많으면 많을수록 블록체인은 튼튼해져요.5. 블록을 만들면 보상을 줄께!가장 단순하고 간단한 방법은 누군가가 블록을 만들도록 하는 거예요. 블록체인은 블록이 우르르르 붙어있다는 소린데, 그 블록이란 건 사실 눈에 보이는 택배박스가 아니라 손으로 적는 기록과 같아요. 롤링페이퍼 아시죠? 딱 그런 느낌인거예요. 돌아가면서 나의 기록을 블록으로 만들어서 열차놀이를 하는거죠. 그리고 블록을 만들면 그에 대한 보상으로 무언갈 주는 거예요! 대부분 그 보상이 바로 암호화폐와 같은 것들이예요. 우린 이걸 '채굴한다.' 라고들 하죠. 열심히 노동했으니 보상을 주는 거예요.6. 블록을 어떻게 만들어? 채굴!그럼 어떻게 블록을 만들까용. 음 생각해봐요. 누구나 그냥 노트북만 있어도 블록을 만들 수 있다면 물론 순식간에 블록들이 엄청나게 만들어져서 온세상 온누리에 우리 블록체인이 아름답게 꽃피긴 하겠지만....'보상'을 줘야하는 걸 생각해보면 소름이 돋을 거에요. 더군다나 화폐의 가치가 있는 것을 만드는 데 아무나 10초만에 만들 수 있다고 하면 이건 복사기에 지폐를 위조해서 그냥 마구 쓸 수 있는 것과 비슷해요. 그래서 블록을 만드는 과정은 어려워야 해요. 개발자들은 그래서 사람들이 엄청 고민을 해야만 풀 수 있는 문제를 명령어로 만들었어요. 그리고 그걸 풀면 블록이 완성되고 보상을 받는 거예요. 물론 종이와 펜으로 푸는 건 아니예요. 인터넷에 떠돌아다니는 '이거 풀면 아이큐150 이상임' 이런 문제와 비슷하긴 하지만....이건 사람이 직접 푸는게 아니라 컴퓨터가 푸는 거에요. 예전에 막 그래픽카드가 없어서 난리가 났다..PC방에서 그래픽카드만 훔쳐갔다더라..이런 뉴스가 한참 떴었잖아요. 맞아요. 마치 영화에나 나올법한 슈퍼컴퓨터같이 엄청나게 엄청난 컴퓨터들을 잔뜩 가져다놓고 계산을 시키는 거예요. 사람은 그냥 엔터만 누르고 가만히 있으면 돼요. 고생은 컴퓨터가 하니까요. 컴퓨터는 미친듯이 계산을 해요. 모터가 탈 정도로 고생을 하죠. 그리고 마침내 문제가 풀리면 짜잔!!! 블록이 완성되었어요!! 물론 블록이 완성이 되었는 지 어쩐지는 눈으로 보지 못해요. 하지만 문제가 풀면 블록이 생기도록 명령어를 짜놓았으니 생겼을 거예요. 컴터는 명확하니까요.(항상 이걸 전제로 해요.) 그리고 약속된 보상이 생겨요. 나에게 암호화폐가 뾱! 생겼어요. 빗썸이나 코인원같은 거래소에서 현금으로 바꿀 수 있도 있어요. 7. 쉬운 방법도 있어요.이렇게 수십대의 컴퓨터와 첨단 장비들이 있어야만 블록을 만들 수 있는 건 아니예요. 일반인들도 블록을 만들 수 있어요. 다만 쉬운 만큼 보상이 굉장히 작겠죠. 단순한 예로 '스팀잇'을 들 수 있어요. 스팀잇은 겉보기엔 브런치같이 그냥 주절주절 글이나 쓰는 플랫폼처럼 보이지만...사실 그건 훼이크예요. 스팀잇에 글을 쓰는 것 자체가 사실 블록을 만드는 것과 같아요. 그래서 그 보상으로 스팀을 주는 거예요. 그래서 정확히 얘기하면 '글을 쓰니 돈을 주더라!!' 가 아니라..'블록을 만드니 보상을 준다!' 가 맞는 거예요. 블록을 만드는 방식이 '콘텐츠' 일 뿐이죠.이처럼 블록을 만드는 방식은 결국 개발사가 정하기 나름이예요. 여행사진을 500장 올릴 때마다 블록을 생성하자! 라고 규칙을 만들면 그렇게 만들어져요. 그리고 보상을 받는거구요. 기부를 하면 블록이 만들어지게 하자! 라고 할 수도 있고하루에 1km씩 뛰어다니면 블록이 만들어지게 하자! 라고 할 수도 있어요.심지어 성인사이트에서 결제를 하면 블록이 만들어지게 할 수도 있어요. 실제로도 있더라구요.규칙은 만들면 되니까요. 그래서 다양한 프로젝트들이 만들어지고 블록체인 회사들이 각자 자신만의 방법으로 사람들을 모으고 있죠. 8. 하지만 사람들은 그 사실을 잘 몰라요.스팀잇에 접속해보신 분이 계신가요?? 사실 그곳은 능력자들 천지라서 다들 블록체인을 어느정도 알고 있는 사람들이 많지만.. 또 많은 사람들은 그런거에 상관없이 그냥 돈 준다니까 가입해서 글을 쓰고 있기도 해요. 사람들은 이게 블록인지 뭔지도 몰라요. 그냥 보상준다니까 열심히 뭘 쓰고 있는거에요.내가 블록을 만드는 걸 눈으로 볼 수도 없고 손에 잡히지도 않아요. 이 모든 건 그냥 컴퓨터가 처리하고 인터넷상에 떠돌아다니는 전기신호로만 존재할 뿐이예요. 우리는 겉으로 드러난 것들만을 보죠. 그래서 수많은 블록체인 회사들이 예쁘고 쉽고 접근하기 좋은 웹페이지를 만들거나 플랫폼을 만들어서 이런저런 활동을 하게 만드는 거예요. 사실 블록체인이 정말 널리고 널려서 이제 공인인증서 등등이 필요없어지게 될 지도 몰라요. 지금도 공인인증서는 폐지수순을 밟고 있고 은행의 인증절차도 간편해지고 있잖아요. 중요한 건 우린 그냥 '우왕 편하다~~' 라는 것만 인지할 뿐 이게 왜 편해졌는지는 관심이 없어요.맞아요. 우린 알게모르게 블록을 만들고 있을 수도 있어요. 당신의 컴퓨터에서 말이죠. 이미 당신은 블록체인에 참여한 거예요. 당신도 장부에 뭔가를 기록했고, 그 블록체인에 참여한 철수란 사람이 그 후에 또 뭔가를 적으면 당신의 컴퓨터에서도 그걸 인식할 수 있어요. 그래서 당신은 철수를 모르지만 당신의 컴퓨터는 철수를 알고 있어요.  이 때문에 P2P거래도 별 인증절차없이 이루어질 수 있는 거예요. 당신의 컴퓨터는 철수를 믿고있거든요. 정리해보면 블록체인은 규칙이예요. 코드로 이루어진 일종의 어떤 규칙이죠. 이걸 블록체인회사에서 만든다음자기들이 어느정도 지분을 가져가요. 자기들이 만들었으니 좀 가지고 있어야 할 거 아니예요. 주로 암호화폐의 형태겠죠.그리고 또 어느 정도는 채굴자들을 모아서 채굴을 시켜요. 대부분은 장비가 충만하신 전문채굴자님들이겠죠. 이 분들은 적극적으로 블록을 만들어내고 많은 보상을 가져가요. 이 때의 보상도 대부분 암호화폐겠죠.나머지는 쪼끄마한 우리들이에요. 우린 그게 뭔진 잘 모르지만 그냥 재밌으니까 막 활동을 해요. 그러면서 블록들을 만들어내요. 우리도 블록체인을 튼튼하게 만드는 역할을 해주었으니 일종의 작은 보상들을 받아요. 이것도 암호화폐겠죠.이렇게 블록체인에 참여하는 컴퓨터수가 많아지면서 블록체인은 더 튼튼해지고 견고해져요. 그리고 겁나 빠르고 편해서 많은사람들이 쓰게 된다면....그게 추후엔 어떤 핵심플랫폼이 될 수도 있겠죠?...다들 그걸 꿈꾸고 열심히 블록체인 코드를 만들고 있는 거예요.여기서 궁금한 게 생겼어요. 그럼... 이런 블록체인 회사들은 돈을 어떻게 버는 걸까요???.... 생각해보면 개발비용이나...홍보나 인건비나..얘네들도 돈이 필요할 텐데 당장 가상화폐는 돈이 안되요. 이제 갓 태어난 화폐는 가치가 거의 없을 거예요. 그러니 마구 가상화폐를 만들어서 팔아도 그건 의미가 없어요. 이분들의 수익은 도대체 어디에서 나는 건지 그게 궁금해졌어요.그래서 3편에선 블록체인 회사들은 뭐 먹고 사는건지 알아보도록 하겠어요 :)어휴 힘들어..이제 저도 규칙에 의해서 자야겠어요.새벽2시가 되면 = 잠을 자라.(규칙)

기업문화 엿볼 때, 더팀스

로그인

/