스토리 홈

인터뷰

피드

뉴스

조회수 954

코인원 크루의 채굴 현장을 포착했다! - ‘코인원 작업증명(PoW)’을 소개합니다

블록체인에서 PoW는 Proof of Work, 즉 작업증명을 말합니다. 블록체인의 암호화된 작업에 대해 참여자가 암호를 풀면, 보상을 제공받는 것이죠.오늘은 코인원의 PoW에 대해서 이야기 해보려고 합니다. '코인원 PoW'의 PoW는 블록체인을 기반으로 금융을 혁신하는 기업답게 블록체인 용어에서 차용했어요. :-)  코인원 크루들이 스스로와 동료들의 회고를 진행하고 피드백을 주고 받는 과정을 통해, 업무 개선과 성과에 대한 보상을 제공받도록 만들어진 일종의 성과관리 시스템이죠. 코인원 피플팀은 코인원 PoW 과정을 다음과 같이 설명하고 있습니다.크루들이 자신들의 업무 성과에 대해 투명하게 풀어놓는 회고를 우선적으로 진행해요. 그 후 함께 업무를 진행한 페어 그룹(pair group)끼리 서로 잘된 업무와 지원이 필요한 부분에 대해 대화를 진행하며, 이를 통해 개선점과 방법을 찾아 업무에 적용합니다.코인원 PoW의 특별한 점은, 대부분의 과정이 정성적으로 진행된다는 것에 있습니다. 물론 숫자로 보이는 결과도 중요하지만, 모든 일은 결과 못지 않게 과정도 중요하다고 판단했기 때문이에요. 그 과정에 충실함을 보인 크루들을 선별해 ‘슈퍼크루'로 지정하고 보상을 제공하는 과정도 여기에 포함됩니다. 이 변화무쌍한, 그리고 결코 쉽지 않은 크립토(crypto) 세계에서 ‘정도'를 걸어가고 있는 ‘코인원스러운' 성과관리 시스템이 아닐까 생각합니다. :-) 우선 코인원 PoW가 어떤 과정으로 진행되는지 한 번 살펴볼까요? 코인원 PoW는 아래와 같은 5가지 단계로 진행됩니다.Self mining셀프마이닝은 지난 6개월 동안 자신이 진행한 업무와 그 과정에 대해 에세이를 작성하는 단계입니다. 에세이를 작성할 때는 자신이 진행한 업무와, 업무를 진행하는 과정에서 본인이 생각하는 잘한 부분 및 아쉬웠던 점들 등에 대해서 작성합니다. ‘잘한 부분'의 경우, 성과가 좋았던 점 외에 성과는 좋지 않았어도 최선을 다한 것에 대해 상세히 작성합니다. Peer mining피어마이닝은 업무적으로 연관된 동료 크루의 셀프마이닝을 토대로 그 동료에 대한 의견을 작성하는 단계입니다. 함께 일했을 때 동료 크루의 좋았던 점, 훌륭한 점, 배워야 할 점 등을 서술하고, 앞으로 더 효율적인 협업을 위해 동료가 개선하면 좋을 것 같은 점도 함께 작성해요. Segwit세그윗 단계에서는 위 두 단계에서 도출된 자기 평가와 동료 평가를 토대로 각 셀의 리더들과 1:1 면담을 진행합니다. 이때 셀 리더들이 꼭 염두해야 하는 것은, 코인원 PoW를 통해 우리가 이끌어내고자 하는 것은 '평소의 관심과 피드백, 그리고 동반 성장'이라는 것이죠. Blue paper세그윗을 통해 최종 작성되는 것이 바로 블루페이퍼에요. 크루들의 면담을 진행한 각 셀의 리더들이 작성하죠. 이 내용은 크루들이 지난 6개월 동안 한 일에 대한 자기 자신과 동료, 그리고 셀 리더의 피드백이 담긴 한 장의 문서죠. Consensus마지막으로 컨센서스 단계에서는 최종 완성된 블루페이퍼를 바탕으로 본부별 슈퍼크루를 선정합니다. 그리고 이렇게 선정된 슈퍼크루에 대해 전체 크루가 동의 가능한지에 대한 적절성 심사가 한 번 더 진행됩니다. 현재 코인원에는 약 120명의 크루들이 일하고 있어요. 사실 모든 크루들의 정성적인 분석 과정을 진행하는 것이 쉬운 일은 아니에요. 코인원 PoW는 셀프마이닝부터 블루페이퍼 작성 및 슈퍼크루 선정까지 약 5주에 걸쳐 진행되는, 길지만 자연스러운 평가와 이를 통한 성장의 과정이라고 생각합니다.이 과정에서 코인원 피플팀 여러분들이 정말 많은 노력과 정성을 기울여주고 계시죠!그렇게 10월의 어느 날, 2018년 상반기의 코인원 PoW가 성공적으로 마무리가 됐습니다. :-)코인원의 모든 크루들이 지난 상반기의 업무에 대해 작업증명을 진행했죠! 그리고 또 다른 6개월 동안 앞으로 다시 힘차게 나아가기 위해 자신의 어떤 좋은 점을 강화하고, 어떤 점은 보완하면 될지를 나 자신, 그리고 동료 크루들과 공유하는 시간이었습니다.또, 이렇게 진행된 2018년 코인원 PoW를 통해 여섯 명의 슈퍼크루가 탄생했어요!2018 코인원 슈퍼크루를 소개합니다 :-)올 한해도 모든 크루가 각자의 분야에서 최선을 다했어요.슈퍼크루는 그 중에서도 특히 다른 크루들에게 좋은 영향을 준 크루들을 선정한 것인데요, 이 분들에게는 코인원의 특별한 추가 보상이 제공될 예정이랍니다. :-)코인원은 앞으로도 크루들이 즐겁게 일하면서 성장할 수 있는 여러가지 재밌고 유익한 도전들을 해보려고 합니다. 코인원이 크립토 세상에서 어떤 즐거운 도전들을 하고 있는지, 앞으로도 코인원 공식 블로그를 통해 지켜봐주세요! :-)#코인원 #블록체인 #기술기업 #암호화폐 #스타트업인사이트 #기업문화 #조직문화 #사내복지 #업무환경 #팀원소개
조회수 3087

Attention is all you need paper 뽀개기

이번 포스팅에서는 포자랩스에서 핵심적으로 쓰고 있는 모델인 transformer의 논문을 요약하면서 추가적인 기법들도 설명드리겠습니다.Why?Long-term dependency problemsequence data를 처리하기 위해 이전까지 많이 쓰이던 model은 recurrent model이었습니다. recurrent model은 t번째에 대한 output을 만들기 위해, t번째 input과 t-1번째 hidden state를 이용했습니다. 이렇게 한다면 자연스럽게 문장의 순차적인 특성이 유지됩니다. 문장을 쓸 때 뒤의 단어부터 쓰지 않고 처음부터 차례차례 쓰는 것과 마찬가지인것입니다.하지만 recurrent model의 경우 많은 개선점이 있었음에도 long-term dependency에 취약하다는 단점이 있었습니다. 예를 들어, “저는 언어학을 좋아하고, 인공지능중에서도 딥러닝을 배우고 있고 자연어 처리에 관심이 많습니다.”라는 문장을 만드는 게 model의 task라고 해봅시다. 이때 ‘자연어’라는 단어를 만드는데 ‘언어학’이라는 단어는 중요한 단서입니다.그러나, 두 단어 사이의 거리가 가깝지 않으므로 model은 앞의 ‘언어학’이라는 단어를 이용해 자연어’라는 단어를 만들지 못하고, 언어학 보다 가까운 단어인 ‘딥러닝’을 보고 ‘이미지’를 만들 수도 있는 거죠. 이처럼, 어떤 정보와 다른 정보 사이의 거리가 멀 때 해당 정보를 이용하지 못하는 것이 long-term dependency problem입니다.recurrent model은 순차적인 특성이 유지되는 뛰어난 장점이 있었음에도, long-term dependency problem이라는 단점을 가지고 있었습니다.이와 달리 transformer는 recurrence를 사용하지 않고 대신 attention mechanism만을 사용해 input과 output의 dependency를 포착해냈습니다.Parallelizationrecurrent model은 학습 시, t번째 hidden state를 얻기 위해서 t-1번째 hidden state가 필요했습니다. 즉, 순서대로 계산될 필요가 있었습니다. 그래서 병렬 처리를 할 수 없었고 계산 속도가 느렸습니다.하지만 transformer에서는 학습 시 encoder에서는 각각의 position에 대해, 즉 각각의 단어에 대해 attention을 해주기만 하고, decoder에서는 masking 기법을 이용해 병렬 처리가 가능하게 됩니다. (masking이 어떤 것인지는 이후에 설명해 드리겠습니다)Model ArchitectureEncoder and Decoder structureencoder는 input sequence (x1,...,xn)<math>(x1,...,xn)</math>에 대해 다른 representation인 z=(z1,...,zn)<math>z=(z1,...,zn)</math>으로 바꿔줍니다.decoder는 z를 받아, output sequence (y1,...,yn)<math>(y1,...,yn)</math>를 하나씩 만들어냅니다.각각의 step에서 다음 symbol을 만들 때 이전에 만들어진 output(symbol)을 이용합니다. 예를 들어, “저는 사람입니다.”라는 문장에서 ‘사람입니다’를 만들 때, ‘저는’이라는 symbol을 이용하는 거죠. 이런 특성을 auto-regressive 하다고 합니다.Encoder and Decoder stacksEncoderN개의 동일한 layer로 구성돼 있습니다. input $x$가 첫 번째 layer에 들어가게 되고, layer(x)<math>layer(x)</math>가 다시 layer에 들어가는 식입니다.그리고 각각의 layer는 두 개의 sub-layer, multi-head self-attention mechanism과 position-wise fully connected feed-forward network를 가지고 있습니다.이때 두 개의 sub-layer에 residual connection을 이용합니다. residual connection은 input을 output으로 그대로 전달하는 것을 말합니다. 이때 sub-layer의 output dimension을 embedding dimension과 맞춰줍니다. x+Sublayer(x)<math>x+Sublayer(x)</math>를 하기 위해서, 즉 residual connection을 하기 위해서는 두 값의 차원을 맞춰줄 필요가 있습니다. 그 후에 layer normalization을 적용합니다.Decoder역시 N개의 동일한 layer로 이루어져 있습니다.encoder와 달리 encoder의 결과에 multi-head attention을 수행할 sub-layer를 추가합니다.마찬가지로 sub-layer에 residual connection을 사용한 뒤, layer normalization을 해줍니다.decoder에서는 encoder와 달리 순차적으로 결과를 만들어내야 하기 때문에, self-attention을 변형합니다. 바로 masking을 해주는 것이죠. masking을 통해, position i<math>i</math> 보다 이후에 있는 position에 attention을 주지 못하게 합니다. 즉, position i<math>i</math>에 대한 예측은 미리 알고 있는 output들에만 의존을 하는 것입니다.위의 예시를 보면, a를 예측할 때는 a이후에 있는 b,c에는 attention이 주어지지 않는 것입니다. 그리고 b를 예측할 때는 b이전에 있는 a만 attention이 주어질 수 있고 이후에 있는 c는 attention이 주어지지 않는 것이죠.Embeddings and Softmaxembedding 값을 고정시키지 않고, 학습을 하면서 embedding값이 변경되는 learned embedding을 사용했습니다. 이때 input과 output은 같은 embedding layer를 사용합니다.또한 decoder output을 다음 token의 확률로 바꾸기 위해 learned linear transformation과 softmax function을 사용했습니다. learned linear transformation을 사용했다는 것은 decoder output에 weight matrix W<math>W</math>를 곱해주는데, 이때 W<math>W</math>가 학습된다는 것입니다.Attentionattention은 단어의 의미처럼 특정 정보에 좀 더 주의를 기울이는 것입니다.예를 들어 model이 수행해야 하는 task가 번역이라고 해봅시다. source는 영어이고 target은 한국어입니다. “Hi, my name is poza.”라는 문장과 대응되는 “안녕, 내 이름은 포자야.”라는 문장이 있습니다. model이 이름은이라는 token을 decode할 때, source에서 가장 중요한 것은 name입니다.그렇다면, source의 모든 token이 비슷한 중요도를 갖기 보다는 name이 더 큰 중요도를 가지면 되겠죠. 이때, 더 큰 중요도를 갖게 만드는 방법이 바로 attention입니다.Scaled Dot-Product Attention해당 논문의 attention을 Scaled Dot-Product Attention이라고 부릅니다. 수식을 살펴보면 이렇게 부르는 이유를 알 수 있습니다.Attention(Q,K,V)=softmax(QKT√dk)V<math>Attention(Q,K,V)=softmax(QKTdk)V</math>먼저 input은 dk<math>dk</math> dimension의 query와 key들, dv<math>dv</math> dimension의 value들로 이루어져 있습니다.이때 모든 query와 key에 대한 dot-product를 계산하고 각각을 √dk<math>dk</math>로 나누어줍니다. dot-product를 하고 √dk<math>dk</math>로 scaling을 해주기 때문에 Scaled Dot-Product Attention인 것입니다. 그리고 여기에 softmax를 적용해 value들에 대한 weights를 얻어냅니다.key와 value는 attention이 이루어지는 위치에 상관없이 같은 값을 갖게 됩니다. 이때 query와 key에 대한 dot-product를 계산하면 각각의 query와 key 사이의 유사도를 구할 수 있게 됩니다. 흔히 들어본 cosine similarity는 dot-product에서 vector의 magnitude로 나눈 것입니다. √dk<math>dk</math>로 scaling을 해주는 이유는 dot-products의 값이 커질수록 softmax 함수에서 기울기의 변화가 거의 없는 부분으로 가기 때문입니다.softmax를 거친 값을 value에 곱해준다면, query와 유사한 value일수록, 즉 중요한 value일수록 더 높은 값을 가지게 됩니다. 중요한 정보에 더 관심을 둔다는 attention의 원리에 알맞은 것입니다.Multi-Head Attention위의 그림을 수식으로 나타내면 다음과 같습니다.MultiHead(Q,K,V)=Concat(head1,...,headh)WO<math>MultiHead(Q,K,V)=Concat(head1,...,headh)WO</math>where headi=Attention(QWQi,KWKi,VWVi)dmodel<math>dmodel</math> dimension의 key, value, query들로 하나의 attention을 수행하는 대신 key, value, query들에 각각 다른 학습된 linear projection을 h번 수행하는 게 더 좋다고 합니다. 즉, 동일한 Q,K,V<math>Q,K,V</math>에 각각 다른 weight matrix W<math>W</math>를 곱해주는 것이죠. 이때 parameter matrix는 WQi∈Rdmodelxdk,WKi∈Rdmodelxdk,WVi∈Rdmodelxdv,WOi∈Rhdvxdmodel<math>WiQ∈Rdmodelxdk,WiK∈Rdmodelxdk,WiV∈Rdmodelxdv,WiO∈Rhdvxdmodel</math>입니다.순서대로 query, key, value, output에 대한 parameter matrix입니다. projection이라고 하는 이유는 각각의 값들이 parameter matrix와 곱해졌을 때 dk,dv,dmodel<math>dk,dv,dmodel</math>차원으로 project되기 때문입니다. 논문에서는 dk=dv=dmodel/h<math>dk=dv=dmodel/h</math>를 사용했는데 꼭 dk<math>dk</math>와 dv<math>dv</math>가 같을 필요는 없습니다.이렇게 project된 key, value, query들은 병렬적으로 attention function을 거쳐 dv<math>dv</math>dimension output 값으로 나오게 됩니다.그 다음 여러 개의 head<math>head</math>를 concatenate하고 다시 projection을 수행합니다. 그래서 최종적인 dmodel<math>dmodel</math> dimension output 값이 나오게 되는거죠.각각의 과정에서 dimension을 표현하면 아래와 같습니다.*dQ,dK,dV<math>dQ,dK,dV</math>는 각각 query, key, value 개수Self-Attentionencoder self-attention layerkey, value, query들은 모두 encoder의 이전 layer의 output에서 옵니다. 따라서 이전 layer의 모든 position에 attention을 줄 수 있습니다. 만약 첫번째 layer라면 positional encoding이 더해진 input embedding이 됩니다.decoder self-attention layerencoder와 비슷하게 decoder에서도 self-attention을 줄 수 있습니다. 하지만 i<math>i</math>번째 output을 다시 i+1<math>i+1</math>번째 input으로 사용하는 auto-regressive한 특성을 유지하기 위해 , masking out된 scaled dot-product attention을 적용했습니다.masking out이 됐다는 것은 i<math>i</math>번째 position에 대한 attention을 얻을 때, i<math>i</math>번째 이후에 있는 모든 position은 Attention(Q,K,V)=softmax(QKT√dk)V<math>Attention(Q,K,V)=softmax(QKTdk)V</math>에서 softmax의 input 값을 −∞<math>−∞</math>로 설정한 것입니다. 이렇게 한다면, i<math>i</math>번째 이후에 있는 position에 attention을 주는 경우가 없겠죠.Encoder-Decoder Attention Layerquery들은 이전 decoder layer에서 오고 key와 value들은 encoder의 output에서 오게 됩니다. 그래서 decoder의 모든 position에서 input sequence 즉, encoder output의 모든 position에 attention을 줄 수 있게 됩니다.query가 decoder layer의 output인 이유는 query라는 것이 조건에 해당하기 때문입니다. 좀 더 풀어서 설명하면, ‘지금 decoder에서 이런 값이 나왔는데 무엇이 output이 돼야 할까?’가 query인 것이죠.이때 query는 이미 이전 layer에서 masking out됐으므로, i번째 position까지만 attention을 얻게 됩니다.이 같은 과정은 sequence-to-sequence의 전형적인 encoder-decoder mechanisms를 따라한 것입니다.*모든 position에서 attention을 줄 수 있다는 게 이해가 안되면 링크를 참고하시기 바랍니다.Position-wise Feed-Forward Networksencoder와 decoder의 각각의 layer는 아래와 같은 fully connected feed-forward network를 포함하고 있습니다.position 마다, 즉 개별 단어마다 적용되기 때문에 position-wise입니다. network는 두 번의 linear transformation과 activation function ReLU로 이루어져 있습니다.FFN(x)=max(0,xW1+b1)W2+b2x<math>x</math>에 linear transformation을 적용한 뒤, ReLU(max(0,z))<math>ReLU(max(0,z))</math>를 거쳐 다시 한번 linear transformation을 적용합니다.이때 각각의 position마다 같은 parameter W,b<math>W,b</math>를 사용하지만, layer가 달라지면 다른 parameter를 사용합니다.kernel size가 1이고 channel이 layer인 convolution을 두 번 수행한 것으로도 위 과정을 이해할 수 있습니다.Positional Encodingtransfomer는 recurrence도 아니고 convolution도 아니기 때문에, 단어의sequence를 이용하기 위해서는 단어의 position에 대한 정보를 추가해줄 필요가 있었습니다.그래서 encoder와 decoder의 input embedding에 positional encoding을 더해줬습니다.positional encoding은 dmodel<math>dmodel</math>(embedding 차원)과 같은 차원을 갖기 때문에 positional encoding vector와 embedding vector는 더해질 수 있습니다.논문에서는 다른 *frequency를 가지는 sine과 cosine 함수를 이용했습니다.*주어진 구간내에서 완료되는 cycle의 개수PE(pos,2i)=sin(pos/100002i/dmodel)<math>PE(pos,2i)=sin(pos/100002i/dmodel)</math>PE(pos,2i+1)=cos(pos/100002i/dmodel)<math>PE(pos,2i+1)=cos(pos/100002i/dmodel)</math>pos<math>pos</math>는 position ,i<math>i</math>는 dimension 이고 주기가 100002i/dmodel⋅2π<math>100002i/dmodel⋅2π</math>인 삼각 함수입니다. 즉, pos<math>pos</math>는 sequence에서 단어의 위치이고 해당 단어는 i<math>i</math>에 0부터 dmodel2<math>dmodel2</math>까지를 대입해 dmodel<math>dmodel</math>차원의 positional encoding vector를 얻게 됩니다. k=2i+1<math>k=2i+1</math>일 때는 cosine 함수를, k=2i<math>k=2i</math>일 때는 sine 함수를 이용합니다. 이렇게 positional encoding vector를 pos<math>pos</math>마다 구한다면 비록 같은 column이라고 할지라도 pos<math>pos</math>가 다르다면 다른 값을 가지게 됩니다. 즉, pos<math>pos</math>마다 다른 pos<math>pos</math>와 구분되는 positional encoding 값을 얻게 되는 것입니다.PEpos=[cos(pos/1),sin(pos/100002/dmodel),cos(pos/10000)2/dmodel,...,sin(pos/10000)]<math>PEpos=[cos(pos/1),sin(pos/100002/dmodel),cos(pos/10000)2/dmodel,...,sin(pos/10000)]</math>이때 PEpos+k<math>PEpos+k</math>는 PEpos<math>PEpos</math>의 linear function으로 나타낼 수 있습니다. 표기를 간단히 하기 위해 c=100002idmodel<math>c=100002idmodel</math>라고 해봅시다. sin(a+b)=sin(a)cos(b)+cos(a)sin(b)<math>sin(a+b)=sin(a)cos(b)+cos(a)sin(b)</math>이고 cos(a+b)=cos(a)cos(b)−sin(a)sin(b)<math>cos(a+b)=cos(a)cos(b)−sin(a)sin(b)</math> 이므로 다음이 성립합니다.PE(pos,2i)=sin(posc)<math>PE(pos,2i)=sin(posc)</math>PE(pos,2i+1)=cos(posc)<math>PE(pos,2i+1)=cos(posc)</math>PE(pos+k,2i)=sin(pos+kc)=sin(posc)cos(kc)+cos(posc)sin(kc)=PE(pos,2i)cos(kc)+cos(posc)sin(kc)<math>PE(pos+k,2i)=sin(pos+kc)=sin(posc)cos(kc)+cos(posc)sin(kc)=PE(pos,2i)cos(kc)+cos(posc)sin(kc)</math>PE(pos+k,2i+1)=cos(pos+kc)=cos(posc)cos(kc)−sin(posc)sin(kc)=PE(pos,2i+1)cos(kc)−sin(posc)sin(kc)<math>PE(pos+k,2i+1)=cos(pos+kc)=cos(posc)cos(kc)−sin(posc)sin(kc)=PE(pos,2i+1)cos(kc)−sin(posc)sin(kc)</math>이런 성질 때문에 model이 relative position에 의해 attention하는 것을 더 쉽게 배울 수 있습니다.논문에서는 학습된 positional embedding 대신 sinusoidal version을 선택했습니다. 만약 학습된 positional embedding을 사용할 경우 training보다 더 긴 sequence가 inference시에 입력으로 들어온다면 문제가 되지만 sinusoidal의 경우 constant하기 때문에 문제가 되지 않습니다. 그냥 좀 더 많은 값을 계산하기만 하면 되는거죠.Trainingtraining에 사용된 기법들을 알아보겠습니다.Optimizer많이 쓰이는 Adam optimizer를 사용했습니다.특이한 점은 learning rate를 training동안 고정시키지 않고 다음 식에 따라 변화시켰다는 것입니다.lrate=d−0.5model⋅min(step_num−0.5,step_num⋅warmup_steps−1.5)warmup_step<math>warmup_step</math>까지는 linear하게 learning rate를 증가시키다가, warmup_step<math>warmup_step</math> 이후에는 step_num<math>step_num</math>의 inverse square root에 비례하도록 감소시킵니다.이렇게 하는 이유는 처음에는 학습이 잘 되지 않은 상태이므로 learning rate를 빠르게 증가시켜 변화를 크게 주다가, 학습이 꽤 됐을 시점에 learning rate를 천천히 감소시켜 변화를 작게 주기 위해서입니다.RegularizationResidual ConnectionIdentity Mappings in Deep Residual Networks라는 논문에서 제시된 방법이고, 아래의 수식이 residual connection을 나타낸 것입니다.yl=h(xl)+F(xl,Wl)<math>yl=h(xl)+F(xl,Wl)</math>xl+1=f(yl)<math>xl+1=f(yl)</math>이때 h(xl)=xl<math>h(xl)=xl</math>입니다. 논문 제목에서 나온 것처럼 identity mapping을 해주는 것이죠.특정한 위치에서의 xL<math>xL</math>을 다음과 같이 xl<math>xl</math>과 residual 함수의 합으로 표시할 수 있습니다.x2=x1+F(x1,W1)<math>x2=x1+F(x1,W1)</math>x3=x2+F(x2,W2)=x1+F(x1,W1)+F(x2,W2)<math>x3=x2+F(x2,W2)=x1+F(x1,W1)+F(x2,W2)</math>xL=xl+L−1∑i=1F(xi,Wi)<math>xL=xl+∑i=1L−1F(xi,Wi)</math>그리고 미분을 한다면 다음과 같이 됩니다.σϵσxl=σϵσxLσxLσxl=σϵσxL(1+σσxlL−1∑i=1F(xi,Wi))<math>σϵσxl=σϵσxLσxLσxl=σϵσxL(1+σσxl∑i=1L−1F(xi,Wi))</math>이때, σϵσxL<math>σϵσxL</math>은 상위 layer의 gradient 값이 변하지 않고 그대로 하위 layer에 전달되는 것을 보여줍니다. 즉, layer를 거칠수록 gradient가 사라지는 vanishing gradient 문제를 완화해주는 것입니다.또한 forward path나 backward path를 간단하게 표현할 수 있게 됩니다.Layer NormalizationLayer Normalization이라는 논문에서 제시된 방법입니다.μl=1HH∑i=1ali<math>μl=1H∑i=1Hail</math>σl= ⎷1HH∑i=1(ali−μl)2<math>σl=1H∑i=1H(ail−μl)2</math>같은 layer에 있는 모든 hidden unit은 동일한 μ<math>μ</math>와 σ<math>σ</math>를 공유합니다.그리고 현재 input xt<math>xt</math>, 이전의 hidden state ht−1<math>ht−1</math>, at=Whhht−1+Wxhxt<math>at=Whhht−1+Wxhxt</math>, parameter g,b<math>g,b</math>가 있을 때 다음과 같이 normalization을 해줍니다.ht=f[gσt⊙(at−μt)+b]<math>ht=f[gσt⊙(at−μt)+b]</math>이렇게 한다면, gradient가 exploding하거나 vanishing하는 문제를 완화시키고 gradient 값이 안정적인 값을 가짐로 더 빨리 학습을 시킬 수 있습니다.(논문에서 recurrent를 기준으로 설명했으므로 이에 따랐습니다.)DropoutDropout: a simple way to prevent neural networks from overfitting라는 논문에서 제시된 방법입니다.dropout이라는 용어는 neural network에서 unit들을 dropout하는 것을 가리킵니다. 즉, 해당 unit을 network에서 일시적으로 제거하는 것입니다. 그래서 다른 unit과의 모든 connection이 사라지게 됩니다. 어떤 unit을 dropout할지는 random하게 정합니다.dropout은 training data에 overfitting되는 문제를 어느정도 막아줍니다. dropout된 unit들은 training되지 않는 것이니 training data에 값이 조정되지 않기 때문입니다.Label SmoothingRethinking the inception architecture for computer vision라는 논문에서 제시된 방법입니다.training동안 실제 정답인 label의 logit은 다른 logit보다 훨씬 큰 값을 갖게 됩니다. 이렇게 해서 model이 주어진 input x<math>x</math>에 대한 label y<math>y</math>를 맞추는 것이죠.하지만 이렇게 된다면 문제가 발생합니다. overfitting될 수도 있고 가장 큰 logit을 가지는 것과 나머지 사이의 차이를 점점 크게 만들어버립니다. 결국 model이 다른 data에 적응하는 능력을 감소시킵니다.model이 덜 confident하게 만들기 위해, label distribution q(k∣x)=δk,y<math>q(k∣x)=δk,y</math>를 (k가 y일 경우 1, 나머지는 0) 다음과 같이 대체할 수 있습니다.q′(k|x)=(1−ϵ)δk,y+ϵu(k)<math>q′(k|x)=(1−ϵ)δk,y+ϵu(k)</math>각각 label에 대한 분포 u(k)<math>u(k)</math>, smooting parameter ϵ<math>ϵ</math>입니다. 위와 같다면, k=y인 경우에도 model은 p(y∣x)=1<math>p(y∣x)=1</math>이 아니라 p(y∣x)=(1−ϵ)<math>p(y∣x)=(1−ϵ)</math>이 되겠죠. 100%의 확신이 아닌 그보다 덜한 확신을 하게 되는 것입니다.Conclusiontransformer는 recurrence를 이용하지 않고도 빠르고 정확하게 sequential data를 처리할 수 있는 model로 제시되었습니다.여러가지 기법이 사용됐지만, 가장 핵심적인 것은 encoder와 decoder에서 attention을 통해 query와 가장 밀접한 연관성을 가지는 value를 강조할 수 있고 병렬화가 가능해진 것입니다.Referencehttp://www.whydsp.org/280http://mlexplained.com/2017/12/29/attention-is-all-you-need-explained/http://openresearch.ai/t/identity-mappings-in-deep-residual-networks/47https://m.blog.naver.com/PostView.nhn?blogId=laonple&logNo=220793640991&proxyReferer=https://www.google.co.kr/https://www.researchgate.net/figure/Sample-of-a-feed-forward-neural-network_fig1_234055177https://arxiv.org/abs/1603.05027https://arxiv.org/abs/1607.06450http://jmlr.org/papers/volume15/srivastava14a.old/srivastava14a.pdfhttps://arxiv.org/pdf/1512.00567.pdf
조회수 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 #텍스트마이닝
조회수 2766

야놀자 기술 블로그 만들기

Hello world!저는 CX서비스실에서 기획을 담당하고 있는 강미경입니다. R&D 그룹의 기술 블로그, 그 영광의 첫 포스트로 개발의 보람을 대신할 수 있어 기쁩니다. 오늘은 ‘기획자가 어쩌다가’ 기술 블로그를 만들게 되었는지 얘기해보려고 합니다.왜 기술 블로그인가제가 야놀자에 입사한 지 만 1년이 되었습니다. 입사하면서 가진 개인적인 목표 중의 하나는 블로그를 운영하는 것이었습니다. 저는 오래전부터 개인 블로그를 운영하고 있고, 외부 커뮤니티 활동에서도 팀 블로그를 운영합니다. 그래서 개발자에게는 기술 블로그에 쓸 글을 작성하는 것보다 코딩을 하는 게 더 쉬울 정도로, 글 쓰는 고통이 남다르다는 것도 알고 있지요.하지만 ‘알고 있다’고 생각하는 정보를 정리하고 그것이 잘 전달될 수 있도록 하는 것은 개발실력과는 약간은 다른 영역의 것이기도 합니다. 그래서 테크 스웩이 넘치는 블로그가 아니더라도, 꾸준히 스토리를 전달하면 그게 개인과 조직의 히스토리로써의 가치가 충분하다고 생각했습니다. 무엇보다 조직 자체의 성장에 큰 밑거름이 되고요.블로그를 시작해보자기술 블로그를 하자는 말에, 놀랍게도 한결같이 ‘관심만’ 주더군요(…) 평소 업무가 많고 바쁨을 떠나서, 보람보단 책임만 남아 유지보수 대상이 되어버릴 가능성이 무궁하지 않겠습니까. 하지만 목마른 사람이 우물을 파라고, 개발자의 도움 없이 블로그를 만들 각오를 하기에 이르렀습니다.(과거의 나를 규탄…#야놀자 #개발팀 #블로그 #인사이트 #경험공유
조회수 4614

신입 개발자를 위한 코드의 정석

Overview대학을 수석으로 졸업했지만, 정작 회사에서는 A부터 Z까지 제대로 할 줄 아는 게 없었습니다. 실수를 남발할 때마다 느꼈던 좌절감은 아직도 생생하지만 되돌아보면 그때의 삽질이 소중한 피와 살이 되었지요. 오늘은 헤매고 있는 신입 개발자를 위한 글을 쓰려고 합니다. 신입 개발자, 당신! 내 이야기를 편하게 듣고 가지 않으실래요? 남을 위한 코드, 클-린 코드“너랑 같이 일하는 사람은 어떻게 보라는 거야?” “한 명이 짠 코드인데, 어째 한 사람이 짠 것 같지가 않다..” “이게 네 스타일이냐?” 대학생이었을 땐, 대부분 혼자서 프로젝트를 진행했습니다. 다른 사람이 제 코드를 보는 일도 거의 없어서 띄어쓰기나 들여쓰기 등에 통일이 없었고, 함수의 네이밍도 전혀 고려하지 않았습니다. 이게 나쁜 습관이었다는 걸 입사하고 알게 되었죠. 이 습관을 고치려고 코딩 컨벤션(coding convention)을 지키는 것에 꽤 오랜 시간을 들여야만 했습니다. 우리는 협업을 하는 사람들입니다. 사람들이 더러운 방보다 깨끗한 방을 좋아하는 것처럼, 당신과 협업하는 개발자도 보기 어려운 코드보다 깨끗한 코드를 더 좋아합니다. 클린 코드를 작성하기 위한 세 가지 기본 원칙을 잠시 소개합니다. 클린 코드를 위한 세 가지 기본 원칙 코드를 최초로 작성한 사람이 끝까지 유지보수를 한다는 보장은 없다.이미 잘 정리된 코드는 효율성이 증가한다. 정리할 시간에 코드 한 줄을 더 분석할 수 있으니까!리팩토링은 미루었다가 한꺼번에 하는 것이 아니다. 코드를 작성하는 매순간 함께 하는 활동이다.작은 것 하나부터 습관을 들여보세요. 분명 깔끔하고 보기 좋은 코드를 만드실 수 있을 겁니다. 머지 않아 “남을 위한 코드는 곧 나를 위한 코드”라는 것도 알게 될 거고요. 책의 한 구절이 떠오르네요. “우리는 저자이다. 저자에게는 독자가 있다. 그리고 저자에게는 독자와 잘 소통해야할 책임이 있다.”⌈Clean Code⌋의 저자, Robert C. Martin 설마가 사람 잡는다, 철저한 검증만약 누군가 검증 단계에서 잊지 말아야할 것이 뭔지 묻는다면 이렇게 대답하고 싶습니다. “절대 사용자가 입력한 값을 신뢰하지 말라. 프론트엔드에서도, 백엔드에서도.” 모든 사용자가 각 항목에 맞게 올바른 정보만 입력해준다면 얼마나 좋을까요? 세상에는 다양한 사용자가 있습니다. 너무 바빠서 얼른 회원가입을 해야하는 사용자는 항목을 채우지도 않고 신청 버튼을 누를 수도 있습니다. 영어로 입력해야 하는 항목엔 한글을 입력한 사용자도 있을 겁니다. 이런 휴먼 에러(human error)뿐만 아니라 의도적으로 비정상적인 요청을 시도하는 사용자도 분명 있습니다. 이 때문에 개발자는 기능에 대해 항상 검증해야 합니다. 바로 이렇게요!그런데 프론트엔드에서 유효성 검사를 하면, 백엔드에는 유효한 값만 넘어온다고 보장할 수 없습니다. 자바스크립트는 브라우저 엔진에 따라 다르게 동작할 수도 있습니다. 또 자바스크립트에서 다루는 값들은 크롬의 개발자도구(option + command + i)를 이용하면 얼마든지 값을 변조하거나 검증을 회피할 수 있습니다. 또 불온한 시도가 아니더라도 다양한 예외 케이스들이 존재하기 때문에 백엔드에서도 무조건 검증해야 합니다.페이스북 페이지의 개발자 도구를 열었을 때 노출되는 화면입니다. 얼마나 나쁜 사람들이 많으면 경고화면까지 만들었을까요?누군가 질문할 수도 있겠군요. “프론트엔드의 검증이 의미가 없다면, 백엔드에서만 검증을 해도 되지 않을까요?” 네, 아닙니다.(단호) 많은 양의 일을 한꺼번에 하는게 힘든 것처럼 무분별한 요청이 서버에 쏟아지면 서버도 사람처럼 지치고 말 겁니다. 응답이 느려지는 등의 문제가 생길 수도 있고, 결국 사용자가 불편해질 것입니다. 그러므로 가장 좋은 검증 방식을 3단계로 정리하면 아래와 같습니다. 고수가 되는 검증 방식 3단계프론트엔드에서 먼저 값 검증을 하여 빠른 사용자 경험을 제공한다.백엔드에서 다시 한 번 더 검증을 거쳐 상황에 적절한 응답 코드를 내려준다.프론트엔드는 상황에 맞게 적절한 UX와 메시지를 보낸다. 동작 그만! 정리는 하고 코딩하자!예전에는 요구사항이 있으면 바로 키보드 위에 손부터 올렸습니다만, 그건 좋은 태도가 아니었습니다. 팀장님이 “이 경우엔 어떻게 하지?”라고 질문하면 아무 대답도 하지 못했기 때문이죠. 팀장님은 늘 “항상 먼저 생각하고 코딩하자!“라고 조언하십니다. 맞습니다. 최대한 모든 경우의 수를 머릿속에 정리하고 코딩을 시작해야 합니다. 시간이 없다는 핑계로 무작정 시작하면 분명 문제가 발생합니다. 또 구현할 기능만 몰두하지 말고, ‘이 기능이 다른 기능에 영향을 미칠 수 있을까?’를 고민하면 훨씬 좋은 코드를 만들 수 있을 겁니다. “이런 거 다 생각하고 짜면 도대체 코딩은 언제 하라고?” “얼른 선임 분들에게 코딩하는 내 모습을 보여줘야 하는데!” “당장 코드 안 짜고 있으면 노는 것처럼 보이지 않을까?” 혹시 이런 생각을 하고 계신가요? 나도 그런 생각을 했던 적이 있습니다. 하지만 요구사항을 확실하게 정리한 후, 코드를 짜는 게 더 효율적입니다. (그렇지 않으면.. ‘수정’이란 이름 아래 모든 것을 뒤엎고 처음부터 다시 시작해야할 수도 있습니다.) ‘더 나은 개발자가 되는 8가지 방법(8 Ways to Become a Better Coder)’이란 글에는 이런 내용이 있습니다. “동작하는 코드는 끝이 아니라 시작이다.” 신입 개발자는 종종 요구사항에 따라 동작하는 코드만 짜면 된다고 여길 때가 있습니다. 물론 사회생활에 적응하느라 정신 없는 와중에 그나마 자신의 코드가 요구사항대로 동작하면 무척 뿌듯할 겁니다. 하지만 동작만 한다고 절대 지나치지 말아주세요. 위에서 언급한 것처럼 깨끗한 코드가 되도록 리팩토링을 하고, 검증하고, 동작이 제대로 되는 것인지 의심하면서 꾸준히 노력해야 합니다. 마지막으로 항상 중요하게 생각하는 문장 하나를 남기고 글을 마치겠습니다.“진정으로 훌륭한 프로그래머는 적극적으로 어디가 잘못되었지를 찾는다. 자기가 놓친 결함은 결국 ‘사용자’가 발견하게 된다는 것을 알고 있기 때문이다.” Esther SchindlerConclusion지금까지 다룬 내용은 결국 같은 맥락입니다. 모든 개발조직은 좋은 품질의 소프트웨어를 개발할 줄 아는 개발자, 협업할 줄 아는 개발자를 원합니다. 누군가 “당신은 잘 지키고 있는가”라고 질문한다면, “저 또한 노력하고 있습니다.”라고 답변하고 싶습니다. 같은 자리에 머무르는 개발자가 될 것인지, 부족함을 알고 항상 배우고 나아가는 개발자가 될 것인지는 스스로의 몫이라고 생각합니다. 이 글을 끝까지 읽은 신입 개발자 당신! 같이 노력하지 않으실래요? :-) 참고 Robert C. Martin, 「Clean Code」, 케이엔피북스(2010)Esther Schindler, 8 Ways to Become a Better Corder, New Relic, 2018.03.02.유석문, 「프로그래머 철학을 만나다 - 소프트웨어를 사랑하는 기술」, 로드북(2014)임백준, 「읽기 좋은 코드가 좋은 코드다」, 한빛미디어(2012)팀장들이 꼽은 신입 PHP 개발자가 가급적 빨리 알았으면 하는 것들프론트에서”만” 유효성 검사가 문제인 경우남을 위한 코드 만들기 - 클린코드글김우경 대리 | R&D 개발1팀kimwk@brandi.co.kr브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 2632

Good Developer 2 | 커뮤니케이션 잘하는 개발자가 되는 방법

프로그래머와 개발자는 다르다.커뮤니케이션에 대한 이야기를 하기 전에 프로그래머와 개발자의 차이에 대해 명확히 하려 한다. 먼저 프로그래머는 컴퓨터를 이용해서 프로그램을 만들거나 수정하는 일을 하는 사람이다. 프리랜서로 일하면서 외주 프로젝트를 맡거나 학교 과제를 하면서 프로그래밍을 하는 사람들 모두 프로그래머라 할 수 있겠다.반면, 개발자는 회사나 조직에 소속이 돼서 다른 사람들과 함께 일하면서 개발을 사는 사람이다. 즉 어딘가에 소속이 돼서 규칙이나 규율 혹은 그 조직의 원칙을 가지고 일을 한다면 개발자로 볼 수 있는 것이다. 정리해 보자면 모든 개발자는 프로그래머지만 모든 프로그래머는 개발자는 아니다. 프로그래머와 개발자를 굳이 나누어서 말하는 이유는 개발자에게는 커뮤니케이션 능력이 절대적으로 필요하기 때문이다. 이와 관련해 아주 적절한 비유를 소개하려고 한다. 이 비유는 칼럼니스트 임백준 님의 '개발자의 생명은 커뮤니케이션 능력'에서 가져왔다.(이 글도 아주 좋으니 읽어보는 것을 추천)비유를 해보자면 이렇다. 프로그래머나 해커는 강호를 떠돌면서 혼자서 행동하는 무사라고 한다면 개발자는 군대에 소속되어 있는 정규군이다. 칼럼에서는 정확이 이렇게 표현한다.외톨이 무사에게 생명은 칼 솜씨고 정규군의 생명은 규칙과 규율이다.칼 솜씨는 코딩 실력이 되겠고, 규칙과 규율은 다른 사람과의 커뮤니케이션 능력이라 볼 수 있겠다. 이것이 개발자에게 있어 코딩 실력이 중요하지 않다는 것은 아니다. 코딩 실력은 기본이요. 커뮤니케이션 능력도 반드시 필수적이라는 뜻이다. 군대에 속해서 전투를 치르기 위해서는 기본적인 전투능력이 필요하다. 즉, 개발자는 자기가 맡은 프로그래밍 업무를 성공적으로 수행할 수 있는 능력을 가져야 하고 이것 은 기본이다!좋은 개발자가 되기 위한 첫 번째 방법, '소통'많은 시니어 개발자들이나 개발 관련된 직종에서 오래 근무한 사람들이 가장 많이 하는 말 중 하나가 바로 커뮤니케이션에 대한 이야기다.  개발자를 뽑을 때 중요한 것이 커뮤니케이션 능력이라고 한다. 커뮤니케이션이 원활하지 않아 개발 업무에 차질이 생기는 일이 다반사며 원활한 커뮤니케이션은 막혔던 문제를 훨씬 더 빠른 속도로 풀릴 수 있게끔 만든다.그럼 구체적으로 좋은 커뮤니케이션을 하기 위해 어떻게 해야 하는지 알아보자. 한 번쯤 들어봤을 이야기들이긴 하지만 구체적인 실행방안들을 추가해서 실제 기업이나 조직에서 바로 적용할 수 있도록 했다.건설적인 대화를 하라!너무나 당연한 말이지만, 이 말이 얼마나 업무 현장에서 지켜지고 있는지는 의문이다. 먼저 건설적인 대화의 방법들을 살펴보기 전에 어떤 대화들이 건설적인 대화가 아닌지를 살펴보자. 그리고 그것을 어떻게 건설적인 대화로 바꿀 것인지 말할 것이다.(1) 대화가 끝났어도 명확한 합의점이나 결과, action item, 해결책이 나오지 않았다.- > 이 문제는 두 가지 이유에서 비롯된다. 첫 번째는 대화의 목적(대화를 하는 이유)이나 목표(해결하고자 하는 것)가 불문명해서 대화가 어느 방향을 전개되야 하는지 갈피를 못 잡기 때문이다. 그리고 두 번째는 대화가 끝난 후 테스크로 전환하는 일을 하지 않은 것이다.==> 대화의 목적과 목표를 분명히 하라! 이야기를 시작할 때는 목적과 목표를 분명히 하라. '우리 지금 이 문제를 해결하기 위해 이야기하는 거죠?' '이 문제를 어떻게 처리할지에 대해 이야기해 봐요.' 일차원적일 수도 있겠지만 이렇게 직접적으로 이야기하는 것이 원활한 커뮤니케이션을 하는데 더 효과적이다. 목적과 목표를 정하지 않고 이야기를 하게 되면 이야기가 중간에 표류할 공산이 크다.==> 대화가 끝난 후에는 반드시 대화에서 얻어낸 결과물들을 테스크로 전환하고 각자에게 배분하라! 업무적 성격의 대화인 경우 문제 해결에 대한 이야기일 가능성이 크다. 이때 액션 아이템이나 합의점이 도출되지 않았다면 건설적인 대화가 이루어지지 않은 것이다. 업무 관련 일이 아닐 경우, 단순 아이디어 회의일 경우에는 대화하면서 나온 아이디어를 적고 문서화시켜야 한다. 그래야 나중에 '너 그때 이렇게 말했잖아!' 하면서 싸우는 일이 없다. 결론이나 결과가 없는 대화는 나중에 그 문제로 인해 다시 대화하게 될 가능성이 크다. 그리고 그것은 곧 리소스의 낭비다.(2) 논쟁을 하다 삼천포로 빠지고, 논쟁이 논쟁을 위한 논쟁으로 변질된다.-> 대화를 하다 보면 항상 좋게 좋게만 흘러가는 것이 아니다. 또 원활한 커뮤니케이션이 의견 충돌이 없는 소통을 의미하는 것도 아니다. 의견이 충돌하되 그것을 건설적이고 긍정적인 방향으로 풀어내는 것이 커뮤니케이션 능력이다. 이 케이스는 목적과 목표의 설정이 제대로 이루어지지 않아서이기도 하지만 대화를 하는데 있어서 서로가 명확히 해야 할 부분을 하지 않아서이기도 하다.==> 논쟁의 지점을 분명히 하라! 특히, 논쟁 지점이 여러 가지라면 뒤죽박죽 이 얘기 저 얘기 다 하면서 시간 소모를 할 공산이 크다. 건설적인 논쟁을 위해서는 우리가 어떤 포인트 때문에 논쟁을 하는지 서로 동의하는 부분은 무엇이고 동의하지 않는 부분은 무엇인지 명확히 해야 한다. ==> 용어를 분명히 하라! 서로 쓰는 용어의 의미가 달라서 논쟁이 되는 경우도 많다. 같은 문제를 바라봐도 다르게 말할 수 있고, 다른 문제를 이야기하는데 같은 용어를 통해 이야기할 수 있다. 원활한 커뮤니케이션의 기본은 용어 통일, 논의의 통일이다. 같은 수준에서 이야기할 때 비로소 원활한 소통을 할 수 있다.커뮤니케이션에 있어서 핵심은 '당신'이다.물론, 커뮤니케이션은 쌍방의 문제다. 내가 문제일수도 있고 상대방이 문제일 수도 있다. 하지만, 원활한 커뮤니케이션에 있어서 상대방을 바꾸는 것은 매우 어렵지만, 나를 바꾸는 것은 상대방을 바꾸는 것보다는 수월하다. 그리고 진정으로 커뮤니케이션을 잘하는 사람은 커뮤니케이션을 못하는 사람과도 '잘' 하는 사람이다. 커뮤니케이션을 잘하는 개발자로 인정받고 싶다면 그 누구와도 잘 할 준비가 되어 있어야 한다.그럼 어떻게 바뀌어야 커뮤니케이션을 잘 할 수 있게 되는지 세 가지 조건을 통해서 알아보자.(1) 자신과 상대방의 커뮤니케이션 스타일을 파악한다.서로 누구의 잘못이라기보다는 방식의 차이 때문에 싸우는 경우가 다반사다. 말투, 어투, 말하는 방식, 시기 등 자신의 스타일을 모르고 상대방의 스타일을 이해하지 못할 때 커뮤니케이션은 막혀버린다. 가장 좋은 것은 글로 적어보는 것이다. 나는 이렇고 상대방은 이렇다. 직접적으로 적어본다면 보다 커뮤니케이션 스타일을 이해하기 쉬워진다. 그리고 커뮤니케이션 스타일을 이해하는 것만으로도 커뮤니케이션을 할 때 많은 도움이 된다.(2) 상대방이 당신에게 망설임 없이 커뮤니케이션할 수 있게 하라!어떤 사람과는 커뮤니케이션 시작 자체를 하기가 어려운 사람들이 있다. 바쁘거나 시작하면 논의가 이루어지지 않거나 많은 조건들이 있을 것이다. 특히, 이 부분에 대해서는 스스로를 돌아보기가 매우 힘들다. 이때는 딱 두 가지의 것을 확인하면 된다.첫 번째로는 주변에 커뮤니케이션하기 망설여지는 상대를 찾아보라. 그리고 그 사람과는 왜 커뮤니케이션이 망설여지는지 생각해 보고 나를 돌아보면 된다. 타산지석(他山之石)이라 했던가. 혹시 내가 커뮤니케이션이 망설여지는 사람이 아닌지 다른 사람을 통해 되돌아보자.두 번째로는 다른 사람에게 솔직하게 물어보는 것이다. 이 방법이 사실 제일 중요하다. 내가 커뮤니케이션에 있어서 부족한 점은 없는지 상대방에게 물어보는 것이 가장 효과적인 방법이다. 물론, 솔직한 말을 듣는 것이 처음에는 두렵고 상처가 될 수도 있다. 하지만, 이것은 당신을 가장 성장시켜줄 대화 중 하나다. 동료만큼 당신과 커뮤니케이션을 많이 하는 사람도 없을 테니 바로 옆자리의 동료에게 자신의 커뮤니케이션에 있어서 부족한 점을 솔직히 말해달라고 부탁하라!(3) 동료와 친밀한 관계를 형성하고 공감하는 것은 중요하다.여기 회사 동료와 친할수록 일의 효율이 올라간다는 연구결과가 있다. 커뮤니케이션의 기본은 열린 마음이다. 그리고 마음은 상대방에게 호의가 있을 때 더 쉽게 열린다. 좋은 커뮤니케이션을 위해서라면 사전에 좋은 관계를 형성하는 것도 중요하다. 좋은 관계와 좋은 커뮤니케이션은 서로 밀접한 상관관계가 있다.대화가 커뮤니케이션의 전부가 아니다.대화만으로 모든 커뮤니케이션을 할 수는 없다. 효율적이지도 않고 물리적으로 불가능한 상황이 있을 수도 있다. 원활한 커뮤니케이션을 위해서라면 적절한 도구의 사용이 필요하다. 즉, 협업 툴을 효과적으로 사용하여 자신이 하고 있는 일들을 상대방에게 알려주고 상대방의 업무를 파악하려고 노력하라!도구의 사용은 커뮤니케이션에 사용하는 비용을 엄청나게 절감해 준다. 자신이 커뮤니케이션에 자신이 없고 언변이 부족하다 생각한다면 도구를 잘 쓰는 방식으로 커뮤니케이션 능력을 향상시킬 수 있다. 지금까지 위에서 언급한 것들은 쉽게 바뀔 수 있는 것들이 아니다. 왜냐하면 지금까지 몸에 체화된 자신만의 대화 방식을 바꾸는 것이기 때문이다. 하지만 커뮤니케이션 도구의 사용은 프로그램이다. 프로그램은 사용법을 배우면 된다.예를 들어, ASANA라는 협업 툴로 자신과 동료의 업무를 리스트화하고 체크할 수 있다. 또는, 구글 캘린더에 자신의 스케줄을 올려서 일정을 공유할 수 있다. 협업 툴을 이용하면 일의 진행사항들을 쉽게 공유하고 상대방의 일정을 파악할 수 있다. 그리고 이런 정보의 공유는 원활한 커뮤니케이션의 기본이다. 이런 도구들을 통해 커뮤니케이션이 부족한 사람들도 충분히 좋은 '커뮤니케이터'가 될 수 있다.커뮤니케이션도 실력이다.다시 처음으로 돌아가 커뮤니케이션의 필요성에 대해 다시 강조하려고 한다. 어떤 사람은 개발자의 핵심은 개발 능력이고 커뮤니케이션은 잘하면 좋은 것이라 생각한다. 위에서도 언급했지만, 개발자는 떠돌이 무사나 용병이 아니다. 조직에 소속되어 있는 개발자라면 소통하고 커뮤니케이션을 하는 능력이 핵심이다.그래서 개발자가 되려는 사람들에 항상 하는 말 중 하나가 다른 사람과 함께한 협업 프로젝트를 해보라는 것이다. 함께 프로젝트를 하는 경험은 프로그래밍 능력을 향상시킬 뿐만 아니라 어떻게 함께 개발하는지에 대해 많은 고민을 할 수 있게 해준다. 단순히 프로그래머가 되려면 코딩 실력에만 집중하라! 그러나, 다른 사람들과 함께 개발을 하는 개발자를 지향한다면 반드시 커뮤니케이션 역량도 향상시켜라!Good Developer 두 번째는 커뮤니케이션에 대해서 다루었다. 다음 Good Developer 는 나쁜 개발자에 대해서 알아볼 것이다.
조회수 1632

[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이 근간이 됩니다. 이제는 프로젝트 방향이 달라질 때마다 컨셉을 새로 설계하는 방식을 벗어나, 그간의 자산을 하나도 잃지 않은 상태에서 지금 가장 효과적인 방식의 매핑 디바이스를 만들 수 있습니다. 이러한 결과를 위해 필요했던 과거의 실패들이었던 것 같습니다.
조회수 2131

비트윈 PC 버전 개발기 - VCNC Engineering Blog

 지난 10월 20일, 비트윈 PC 버전의 오픈 베타 테스트를 시작했습니다. PC 버전 덕분에 컴퓨터 앞에서 일과 시간을 보내는 직장인들도 편리하게 비트윈으로 연인과 대화할 수 있게 되었습니다. 이 글에서는 PC 버전에 어떤 기술이 사용되었는지 소개하고 약 4개월의 개발 기간 동안 겪은 시행착오를 공유합니다.비트윈 PC 버전 스크린샷개발 플랫폼 선택PC 버전 개발을 본격적으로 시작하기 전에 어떤 개발 플랫폼을 선택할 것인지 많은 고민을 했습니다. MFC나 WinForms 같은 네이티브 플랫폼, Qt 등의 크로스 플랫폼 라이브러리, 그리고 웹 기반 앱 등의 여러 후보를 가지고 토론을 거쳐 웹 앱으로 개발하기로 했습니다.웹 기반으로 개발하게 된 가장 큰 이유는 생산성입니다. PC 버전 팀이 웹 기술에는 이미 익숙하지만 다른 플랫폼은 경험이 많지 않았습니다. 또한, 비교적 자유롭게 UI를 구성할 수 있으며 기존의 각종 개발 도구를 이용하면 빠른 이터레이션이 가능할 것으로 예상했습니다.단, 사용자가 기존에 설치한 웹 브라우저를 통해 접속하는 방식이 아니라 브라우저 엔진을 내장한 실행 파일을 배포하는 방식을 택하기로 했습니다. 여러 브라우저 환경에 대응하지 않아도 되고, 브라우저에서 지원하지 않는 일부 시스템 기능을 직접 확장해서 사용할 수 있기 때문입니다.서버 아키텍처의 변화비트윈 서버의 서비스 로직은 Thrift 서비스로 구현되어 있습니다. 그리고 Alfred라는 자체 개발 라이브러리를 사용하여 Thrift 서비스를 Netty 기반의 서버로 구동합니다.기존의 비트윈 모바일 클라이언트는 채팅 서버와 Thrift의 바이너리 프로토콜로 통신하고 있습니다.1 그러나 웹 플랫폼에서는 서버와 지속적으로 양방향 연결을 유지하려면 WebSocket 프로토콜을 사용해야 하므로 Alfred에 WebSocket 프로토콜 지원을 추가하였습니다. 애플리케이션이 아닌 라이브러리 수준의 변화였기 때문에 기존 서비스 코드에 영향을 거의 주지 않고 새로운 프로토콜을 지원할 수 있었습니다.Alfred에 웹소켓 지원을 추가하였습니다.비트윈 PC 버전 셸비트윈 PC 버전은 크게 HTML과 자바스크립트로 작성된 웹 앱 부분과 웹 앱을 브라우저 엔진으로 구동해주고 플랫폼 API를 제공하는 셸 (Shell) 부분으로 구성되어 있습니다.비트윈 PC 버전 구조PC 버전 셸은 Chromium Embedded Framework (CEF)를 사용합니다. 이름에서도 알 수 있듯이 Chromium 브라우저 엔진을 애플리케이션에 내장하기 쉽도록 감싸놓은 라이브러리입니다. CEF는 Evernote나 Steam 등 웹 브라우저를 내장한 애플리케이션에서 널리 사용되고 있어 선택하게 되었습니다.2자바스크립트에서 셸이 제공하는 플랫폼 API를 호출할 때는 CEF의 Message Router를 사용하였습니다. Chromium은 멀티 프로세스 구조로 이루어져 있어, 렌더 프로세스에서 작동하는 자바스크립트 코드가 브라우저 프로세스에서 작동하는 C++ 코드를 호출하고 결과를 돌려받기 위해서는 별도의 처리가 필요합니다. Message Router는 이 두 프로세스 사이의 비동기 통신을 지원합니다. 이를 통해 창 투명도 조절이나 트레이 알림 표시 등 원래는 웹 플랫폼에서 지원하지 않는 기능을 확장하여 지원할 수 있었습니다.CEF에서는 Chrome 개발자 도구를 사용할 수 있어 디버깅이 용이했고, 디자이너 옆에서 바로바로 좌표나 색상 등을 바꿔볼 수 있어 협업에도 도움이 되었습니다.그러나 PC 버전을 개발하면서 가장 많은 시행착오를 겪은 부분이 CEF를 다루는 것이었습니다.문서화가 잘 되어있지 않습니다. 그래서 실제 작동 방식을 확인하기 위해 직접 소스 코드를 읽어야 하는 경우가 많았습니다일반적인 웹 브라우저에서는 잘 작동하는 API를 CEF가 자원하지 않거나 버그가 있어 다른 방식으로 구현해야 할 때가 있습니다.CEF에 노출된 API에만 접근할 수 있어 Chromium에서 제공하는 플랫폼 추상화 레이어를 활용할 수 없었습니다.비트윈 PC 버전 웹 앱비트윈 PC 버전의 주요 애플리케이션 코드는 HTML과 자바스크립트로 작성되어 있습니다. 자바스크립트로 큰 규모의 애플리케이션을 작성할 때 발생하는 여러 가지 어려움을 피하고자 React 라이브러리 및 최신 자바스크립트 기술을 적극적으로 활용하였습니다.ReactReact는 Facebook에서 개발한 오픈 소스 자바스크립트 UI 라이브러리입니다. 일반적인 웹사이트보다는 비교적 복잡한 인터페이스를 구현해야 했기 때문에 jQuery처럼 간단한 라이브러리로는 부족할 것으로 생각하여 비트윈 PC 버전은 처음부터 React를 사용하였습니다.전통적인 개발 방식에서는 UI를 변경해야 할 때 기존에 렌더링 된 DOM 요소에 명령을 내립니다. 예를 들어 어떤 항목을 삭제하려면 그 요소를 찾아서 삭제 명령을 내리게 됩니다. React를 사용할 때는 이와 달리 해당 요소가 사라진 DOM 트리 전체를 다시 생성하면 React가 이전 트리와 새 트리를 비교하여 바뀐 부분만 반영해줍니다. 전체를 다시 렌더링하기 때문에 기존에 DOM 트리가 어떤 상태였는지 신경 쓰지 않고도 원하는 상태로 쉽게 변경할 수 있어 UI 코드의 복잡도를 줄일 수 있습니다.또한, React의 컴포넌트 시스템은 독립적인 UI 요소들을 서로 영향을 주지 않고 조합할 수 있도록 해주어, 한가지 컴포넌트를 수정했을 때 의도하지 않은 다른 컴포넌트와 간섭하는 문제가 적게 발생합니다. 비트윈 PC 버전에는 약 40가지의 React 컴포넌트가 쓰이고 있습니다.자바스크립트 모듈 시스템모든 코드를 한 파일에 넣으면 코드를 관리하기가 힘들어집니다. 따라서 서로 관련 있는 코드끼리 모듈로 나누어야 하는데, 자바스크립트에는 모듈 시스템이 기본적으로는 제공되지 않습니다. 비트윈 PC 버전에서는 CommonJS 표준을 따라서 모듈을 나누고, 이를 웹 브라우저가 해석할 수 있는 형태로 합쳐주는 Webpack 빌드 툴을 사용했습니다.Webpack은 자바스크립트뿐만 아니라 CSS나 이미지, JSON 파일 등도 모듈로 취급할 수 있고, 플러그인으로 지원하는 모듈 종류를 추가할 수 있습니다. 비트윈 PC 버전을 빌드할 때 실제로 사용하는 플러그인은 다음과 같은 것들이 있습니다.jsx-loader: React에서 사용하는 JSX 코드를 자바스크립트로 변환합니다. 또한, 미래의 자바스크립트 문법을 현재 브라우저에서 지원하는 형태로 변환합니다.less-loader: LESS 파일을 CSS 파일로 변환합니다.css-loader: CSS에서 참조하는 외부 리소스를 인식하여 의존성을 파악해줍니다.url-loader: 파일 크기가 일정 이하인 리소스를 Base64 인코딩으로 내장해줍니다.ECMAScript 6ECMAScript 6는 차기 자바스크립트 표준입니다. 현재 자바스크립트의 불편한 점을 많이 해소하기 때문에 장점이 많이 있습니다. 일부 기능은 이미 브라우저에 구현되어 있지만, 아직 지원되지 않는 기능도 있어서 jstransform을 통해 ECMAScript 5 코드로 변환하여 사용하였습니다.화살표 함수: 익명 함수를 (a, b) => a + b와 같은 문법으로 훨씬 간단하게 선언할 수 있습니다. 또한, this 변수의 스코프를 현재 코드 상의 위치에 따라 결정해줍니다.클래스: 다른 언어와 유사한 클래스 문법을 제공합니다. 상속이나 접근 제한도 가능합니다.해체(destructuring) 대입: 객체의 필드를 바로 같은 이름의 변수에 대입할 수 있습니다. 예를 들어, var {a, b} = {a: 1, b: 2}; 같은 코드를 작성할 수 있습니다.기타 사용된 패키지RSVP.js: Promise/A+ 구현을 제공하는 라이브러리로, Promise 패턴을 사용하여 비동기 로직을 알아보기 쉬운 형태로 작성했습니다.FormatJS: 다국어, 국제화 지원을 위한 라이브러리입니다. UI 메시지 번역이나 날짜, 시간 등의 포매팅에 사용했습니다.정리비트윈 PC 버전은 개발 비용을 줄이기 위해 웹 플랫폼 기반의 네이티브 애플리케이션으로 개발되었습니다.비트윈 서버에서 사용하는 Alfred 라이브러리에 WebSocket 프로토콜 지원을 추가하였습니다.Chromium Embedded Framework를 브라우저 엔진으로 사용하여 웹 앱을 구동하고 웹 플랫폼에서 제공하지 않는 기능을 확장하여 사용했습니다.자바스크립트 코드의 복잡도를 줄이기 위해 React, CommonJS, ECMAScript 6 등의 기술을 활용하였습니다.VCNC Engineering Blog, 비트윈 시스템 아키텍처, 2013년 4월↩Wikipedia, Chromium Embedded Framework - Applications using CEF↩
조회수 1123

깃발 올려, Git Effect!

안녕하세요, 개발 2팀에서 단아함을 맡고 있는 오연주입니다. 평소에 관심이 많았던 깃(Git)을 공부하면서 알게 된 내용들을 글로 쓰려고 합니다. ‘어떤 닝겐이 만들었나’ 궁금할 정도로 천재적인 깃은 도대체 누가 만든 것일까요? 바로 리누스 토발즈(Linus Torvalds)입니다. 이름에서부터 OS의 느낌이 가득합니다. 네, 맞습니다. 그는 리눅스(Linux)의 창시자이기도 합니다. 리누스는 말했죠. “My name is Linus, and I am your God.” 리누스 토발즈 (Linus Torvalds)그가 깃을 만들기 전에는 보통 중앙집중식 VCS(Version Control System)를 사용했었습니다. 예를 들면 다음과 같은 도구들로요. CVSSVN(Subversion)…반면에 깃은 분산 버전 관리 시스템(DVCS, Distributed Version Control System)입니다. 그렇다면 중앙집중식의 대표주자인 Subversion(VCS)에 비해 무엇이 더 좋을까요? 속도가 빠르다. snv log svn diff -rN svn commit 등 대부분의 명령어가 네트워크 연결이 되어야 실행 가능한 명령어입니다. 그러나 git push git clone 등 몇몇 명령어를 제외하고는 네트워크에 연결되어 있지 않아도 로컬에서 실행할 수 있습니다. 용량이 적다. Mozilla의 SVN Repository는 126GB인데 반해 Git Repository은 420MB입니다. 왜냐하면 해쉬, 스냅샷을 이용한 효율적인 파일 변화 관리가 가능하기 때문입니다. 브랜치를 만드는 작업이 수월하다. SVN은 diff를 전부 적용해서 파일을 생성한 뒤 네트워크에서 내려받는 반면, 깃은 스냅샷을 가리키는 링크(Commit Object)만 만들면 됩니다.어떠한 특징을 가지고 있길래 이런 차이점이 생기는 걸까요?분산 저장소로, 로컬에서도 중앙 저장소와 연결되지 않은 상태에서 지지고 볶기가 가능하다니! 여러 개의 다른 저장소를 생성할 수 있고 서로서로 연결되어 독립적으로 개발 프로젝트를 진행할 수 있고 유기적인 업데이트가 가능합니다. 델타 기법이 아닌 스냅샷 방식을 사용합니다. SVN의 경우 파일 변화를 diff로서 추적한 반면, Git은 각 시점의 파일 상태를 모두 스냅샷을 찍어 관리합니다.변화를 기억했던 기존 방식변화된 소스를 커밋할 때 스냅샷을 찍는 방식두 가지 특징을 살리려면 깃이 여타 다른 VCS와는 다른 방식으로 정보를 관리할 필요가 있습니다. 예를 들어 Revision number로 히스토리를 관리했던 Subversion으로 분산된 저장소의 히스토리를 관리하려고 하면 ‘시점 충돌’ 문제가 발생합니다.그..그려봤습니다..금융 프로젝트에 참여했을 때의 일입니다. VCS 중 H사 툴을 사용하였는데 한 소스의 버전을 받고 개발하는 과정에서 커밋의 횟수가 많아지니 중앙 저장소 입장에서는 ver 1 → ver 9로 갑자기 타임워프하는 일이 생겼습니다. 그래서 개발자 스스로 본인의 버전을 모두 삭제한 후 ver 9였던 파일을 수동으로 ver 2로 바꿔주는 것이 관례였습니다. 소스가 모두 날아가는 경우가 있어 소스 commit 과정이 공포스러웠죠. 깃은 해쉬(hash)를 이용한 정보 관리를 통해 이런 문제를 말끔하게 해결합니다.Git의 핵심, 정보 Hashing! git reset --hard 3269aecad9ffea81763a42b9fff34c76a0aa4cf0 브랜디 소스 코드를 pull 했는데 특정 시점으로 돌아가 할 일이 생겨 위의 명령어를 입력했던 적이 있습니다. 명령어로 깔끔하게 원하는 시점으로 되돌아올 수 있었죠. 뒤에 붙는 40자리의 기괴한 문자열은 바로 깃이 정보를 관리하는 데에 사용하는 해쉬값입니다. 해쉬값이 제일 많이 보이는 곳은 git log 가 아닐까 싶은데요. commit 옆에 나열된 일련번호같은 문자열이 궁금하진 않으셨나요?깃은 소스 코드를 포함해서 히스토리를 관리하는데 필요한 모든 정보를 이런 해쉬로 저장 및 관리합니다. 이 해쉬값은 40자리 16진수 숫자이며 SHA-1 알고리즘으로 생성됩니다. SHA-1 알고리즘은 보안 표준 해쉬 알고리즘 중 하나입니다. 충돌할 확률은 1 / 10^45로, 매우 매우 낮기 때문에 수많은 정보를 저장 및 관리하기에 안전하고 적합합니다. 4GHz CPU로 SHA-1 해쉬 중복값을 찾아내려면 4000년이 걸린다.앞서 SHA-1 해쉬값으로 모든 정보를 저장한다고 말씀드렸는데, 과연 어떤 정보를 어디에, 어떻게 저장하고 있는 것일까요? 각 해쉬 값은 깃이 내부적으로 저장하는 파일 이름이 되기도 하는데, 이 파일들은 .git/objects 경로에서 전부 찾아볼 수 있습니다. 해쉬값 40자리 중 앞 2자리를 디렉토리 이름으로 따고, 뒤 38자리를 파일 이름으로 지정합니다. 각 파일 안에는 서로 다른 정보가 담겨 있습니다. 해쉬값으로 표현되는 이 파일들은 정보의 종류에 따라 3가지 객체로 분류됩니다. Blob ObjectTree ObjectCommit Object폴더나 파일명이 어떤 오브젝트인지 힌트를 주지 않기 때문에 세 가지의 오브젝트 파일 내용의 캡처를 위해 복불복으로 열어봤는데요, 하나의 파일을 열 때마다 포춘쿠키를 까듯 심장이 쫄깃쫄깃했습니다. Blob Object란 실제 파일을 뜻하며, 실제 소스파일을 가지고 있는 실세 오브젝트같은 느낌입니다. Blob Object - 열어보면 내가 작성한 소스 코드가 들어있다.Tree Object 내부에는 프로젝트 구조의 각 디렉토리에 대한 정보가 담겨 있습니다. 하위에 어떤 폴더와 파일을 가지고 있는지 알려주고, 객체 해쉬 값을 저장하고 있습니다. 이 Tree Object의 제일 상위 객체는 root이며, 프로젝트의 최상위 폴더에 대한 정보를 담게 됩니다.앞서 깃은 각 시점별 스냅샷을 찍어 관리한다고 했습니다. 스냅샷을 찍는 행위는 새로운 Root Tree Object를 만들고, 각 시점에 가지고 있는 Tree Object와 Blob Object로 새로운 트리 구조를 만드는 과정입니다. Tree Object - 하위에 php라는 폴더와 README.md라는 파일이 들어있는 것을 볼 수 있다.Commit Object는 커밋 시점의 Repository Root Directory의 해쉬 값을 가지고 있는 녀석입니다. Parent는 내 커밋 전에 커밋이 누구인지를 뜻하는데요. 또한, 커밋할 때의 committer(user), commit message등의 정보도 가지고 있습니다.Commit Object - 해당 commit 시점의 root tree object와 이전 커밋, 작성자 등에 대한 정보를 담고 있다.세 종류의 객체는 깃이 분산된 Repository 간의 소스 히스토리를 쉽게 관리하도록 도와줍니다. 해쉬값으로 관리되기 때문에 특정 스냅샷에 이동하거나, 히스토리를 변경 또는 추가하는 데에 적은 리소스만 필요합니다. 또 분산된 저장소 사이에 상호 시간 순서에 대한 모호함도 해결할 수 있었습니다. 이 정도면 갓누스….깃을 공부하기 시작한 이유는 Git UI Tool을 쓰면서 습관적으로 commit, push 버튼을 눌렀기 때문입니다. 깃에 대한 이해도가 있는 상태에서 사용한다면 실수가 줄어들 거라 생각합니다. 다음 글은 Git branching Model을 다루겠습니다. ps. Git, 협업과 원활한 커뮤니케이션을 위해 알고 씁시다! 우리 함께 깃빨 받읍시다!! 참고 Scott Chacon and Ben Straub, ⌈Pro Git, 2nd Edition⌋, Apress(2014)Schneier on SecurityProbability of SHA1 collisions, stack overflowSVN 능력자를 위한 git 개념 가이드, Insub Lee, Slide Share글오연주 사원 | R&D 개발2팀ohyj@brandi.co.kr브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 2245

사운들리 코드 품질 관리 이야기

안녕하세요 "사운들리"입니다 :)오늘은 사운들리의 코드 품질 관리에 대해 이야기 해보려 합니다.몇몇 개발자에게는 지루하고 악몽같은 이야기일 수 있겠네요.제 경우에는 예전에는 이런 품질이라는 단어를 멀리했지만 결국 제가 작성한 코드에 발목을 많이 잡히다 보니, 자연스레 관심을 갖게 되었습니다.일단, 어떤 소프트웨어가 좋은 품질의 소프트웨어일까요?좋은 품질이란? 책에 나올법한 내용을 보면, 아래와 같은 항목을 토대로 소프트웨어 품질을 판단한다고 합니다.ISO/IEC 9126 : Software engineering - Product qualityFunctionality: 명시된 요구사항을 잘 충족했는지Reliability: 명시된 조건과 시간 아래에서 일정 성능을 유지 하는지Usability: 사용하기 위해 어느정도의 노력과 자원이 필요한지Efficiency: 소모 자원과 성능간의 효율Maintainability: 수정하기 위해 어느정도의 노력이 필요한지Portability: 다른 환경에서도 사용 할수 있는지출처: https://en.wikipedia.org/wiki/ISO/IEC_9126 뭔가 복잡해 보이지만, 결국 개발자라면 위의 항목은 누구나 추구하게 되는 가치라고 생각 합니다.그런데 말입니다. 이런 좋은 내용을 마음 속으로만 간직한 채 코드를 작성하면 정말 좋은 소프트웨어를 만들 수 있을까요? 저는 객관적인 방법으로 코드를 평가한다면 좋은 피드백이 될 것이라고 생각합니다. (물론 이 성적표를 남에게 보여주는 것과는 다른 문제에요 ㅎㅎ)어떻게 품질을 체크하는가 소프트웨어의 품질을 체크하는 데에 다양한 방법과 툴이 제시되고 있는데요, 저는 크게 두 가지로 분류 해보겠습니다.유저 입장의 품질: 유저의 요구사항에 맞는 소프트웨어인지 체크개발자 입장의 품질: 내가 지금 이 코드를 의도한 대로 잘 작성하고 있는지 체크 유저 입장의 품질은 언급하지 않아도 중요함을 누구나 알고 있습니다. 이 부분이 만족이 되지 않으면 제품이 아니죠! 그래서 저는 개발자 입장에서 스스로 챙길수 있는 품질을 사운들리는 어떻게 챙겨보고 있는 지 이야기 해보도록 하겠습니다. 실은 제가 개발자 입니다 ㅎㅎ사운들리 개발자의 코드는 아래와 같이 흘러갑니다.<그림1> 사운들리 코드 개발상의 품질 관리 순서도간단히 각 항목을 훑어 보겠습니다.Local Machine 각자 갖고 있는 맥북으로, 다양한 IDE를 사용해 코딩합니다. 그리고 git 을 이용해 commit 하고, github 에 push 하죠.Github push 된 수정사항은 pull request 를 통해 동료에게 알려집니다. 이후 코드리뷰를 통해 merge 하게 됩니다. 코드리뷰는 많은 사람들에 의해 그 중요성이 부각되고 있습니다. 사운들리는 같은 모듈을 만드는 개발자끼리, 그리고 다른 모듈에 영향을 주는 코드일 경우에는 해당 모듈의 개발자도 리뷰를 합니다. 코드리뷰를 통해 다른 사람이 어떤 기능을 작성했는지 보고, 오류도 찾고, 더 좋은 방법이 있으면 공유도 하고, 칭찬도 하고, 훈수도 두고 합니다. 참고로 사운들리는 git-flow 정책에 따라 git branch를 운영하고 있습니다.Jenkins  Github 에 commit 이 등록되면 Jenkins 는 자동으로 빌드를 시작 합니다. Jenkins 는 단순 빌드 성공 실패를 떠나서, 코드 품질에 대한 몇가지 report 를 발생 시킵니다. 아래에서 좀더 자세히 다뤄보겠습니다.SonarQube Jenkins 에서 빌드하면서 SonarQube 에 포함된 분석 기능을 사용하게 됩니다.그렇다면, 코드 품질의 지표는 무엇일까요?Jenkins가 발생시키는 레포트를 통해서 알 수 있는 내용은 아래와 같습니다.코딩 스타일 체크 결과: 작성된 코드가 미리 정의된 코딩 스타일에 맞게 작성되어 있는지?Unit Test 결과: 유닛 테스트 결과 (당연히 전부 pass 해야겠죠)Test code coverage 결과: 테스트 코드가 전체 코드의 몇 % 를 커버 하고 있는지 (우리의 최종목표는.. 60%.. 덜덜덜)정적 분석 결과: 코드를 실행하지는 않지만, 코드 그 자체에서 발생할 수 있는 결함을 찾아줍니다. 이 네 가지 레포트는 객관적 수치를 나타내주기 때문에 일종의 코드 품질 지표로 삼을 수 있습니다. 물론 이 지표만 잘 관리 했다고 해서 좋은 코드를 작성했다고 말할 수는 없습니다. 다만 좋은 코드를 작성하기 위한 기초 중의 기초라고 볼 수 있겠죠 :)품질 체크를 위한 툴(tool)은 개발 언어에 따라 다를 수 있습니다. 사운들리에서는 다양한 언어로 소프트웨어가 작성되어 있습니다. 따라서 언어마다 위의 결과를 얻기 위해서 서로 다른 툴을 사용하고 있습니다. AndroidJavaJavascriptC/C++코딩 스타일checkstylecheckstyle jshintcppcheckUnit testjunitjunitmochagoogletestCode coveragejacococoberturamocha-covgcov정적 분석sonarqubesonarqube sonarqubecppcheck 각 개발자는 위의 네 가지 결과를 얻기 위해서 빌드 시스템에 툴을 포함하여 개발하고 있습니다. 제가 주로 개발하고 있는 java 언어에 해당하는 툴들을 좀 더 자세히 살펴보겠습니다.checkstyle코딩 스타일을 체크 해줍니다. xml 파일로 미리 정의 되어있고요. 매번 빌드할때마다 스타일이 틀린것을 지적해 줍니다.코딩 스타일은 중요합니다. 같이 개발하는 개발자와 코딩 스타일이 같다면 마치 내가 작성한 코드처럼 쉽게 읽을 수 있죠.junitjunit 은 자바 유닛 테스트 프레임워크 입니다. 유닛 테스트 코드를 편하게 작성하게 해주고, 쉽게 테스트 결과를 볼 수 있습니다.유닛 테스트 코드를 작성하면 내가 작성한 모듈을 작은 단위로 테스트 해서, 작은 로직에서 발생하는 시시콜콜한 문제를 방지 할 수 있습니다. 테스트 코드를 작성해서 검증한 부분은 스스로도 신뢰가 갑니다.기능 수정간에 유닛 테스트에서 fail 이 나는 경우가 발생하는데, 모르는 사이에 다른 모듈에 영향을 준 것을 알게 됩니다. 다른 모듈에 모르고 영향을 주게 되면 뒷처리가 어려워지잖아요~coberturacode coverage 를 계산해 주는 툴입니다.유닛 테스트 코드가 실행되면, 작성된 코드의 각 부분을 실행하게 됩니다. cobertura 는 이때 각 코드의 어느부분이 실행되었는지 확인해서 통계를 내줍니다.주로 line coverage / branch coverage 두 지표를 보는데요, line coverage 는 해당 라인이 한번이라도 실행 되면 check 되고, branch coverage 는 각 라인에 있는 조건문을 다 따로 check 합니다. 당연히 branch coverage 를 달성하는게 어렵겠죠?sonarqube소나큐브는 다양한 plug-in 을 통해서 정적 분석을 하고, 시각화를 해주는 툴입니다.사운들리는 주로 정적 분석 용도로만 소나큐브를 사용하고 있습니다. (지원하는 plug-in 을 보면 젠킨스와 기능이 겹치는 부분이 있습니다.)정적분석으로 실제 문제가 되는 부분을 찾는 경우도 있고, minor 한 부분에 대한 지적을 하는 경우도 있습니다. 그러나 이런 minor 한 부분도 꼼꼼하게 잘 챙겨야 좋은 개발자가 된다고 믿고 있습니다.마치며 여기까지 사운들리의 코드 품질 관리에 대해 이야기 해보았습니다. 품질 관리를 해보신 분은 아시겠지만, 이런 툴을 쓰다보면 항상 행복하게 코드 품질을 관리할 수는 없습니다. 매달 세워놓은 목표를 달성하기 위해서 뼈를 깎는 노력으로 테스트 코드를 작성해야 되고, 당장 기능 수정해서 배포해야 되는데, 작성해 둔 테스트 케이스가 Fail 되어 말썽을 부릴 수도 있습니다. 그렇지만 객관적 기준으로 코드 품질을 관리하다보면 어느샌가 큰 노력없이 좋은 코드를 작성하는 개발자가 되지 않을까 생각해 봅니다. 코드 졸면서 막 짜도 style warning 0건/ 정적분석 오류없음 / 테스트 코드 기본 탑재 뭐 이런 개발자 말입니다 ㅎㅎ 다른 개발자분들은 어떻게 자신이 작성한 코드의 품질을 관리하고 있는지 궁금하네요.알고 계신 좋은 방법이 있다면 언제든지 공유 부탁드리겠습니다~!#사운들리 #개발자 #개발 #인사이트 #조언 #개발후기 #후기
조회수 911

국내 IT 산업을 주무르는 첫눈 마피아

업계에서 페이팔 마피아(PayPal mafia)에 대한 이야기를 듣는 건 어렵지 않다. 전세계 IT 산업의 핵심인 실리콘밸리를 장악하고 있는 페이팔 마피아를 탄생시킨 회사는 컨피니티(Confinity)라는 회사다. 이 회사의 이름은 낯설지 몰라도 이 회사가 개발한 페이팔(PayPal)이라는 전자 송금 서비스의 이름은 낯설지 않을 것이다. 1998년 시작된 컨피니티는 페이팔을 만들어 2002년 상장한 뒤 얼마 지나지 않아 이베이(eBay)에 매각된 닷컴 버블 폭풍의 몇 안되는 생존자 중 하나였다. 페이팔 마피아란 페이팔의 초기 임직원들을 일컫는 말로, 이들은 이후에 또 다른 혁신적인 회사들(Tesla Motors, LinkedIn, Palantir Technologies, SpaceX, YouTube, Yelp, Yammer 외 다수)을 계속 만들어 내고 있다. 이들의 모습이 마치 사회 모든 곳에 얽혀 있는 마피아 조직을 연상시킨다는 것에 비유해, 이들을 페이팔 마피아라고 부르기 시작했다. 심지어 포춘지(Fortune)에서는 2007년 이들을 한데 모아 마피아 같은 옷을 입히고 재미있는 사진을 남기기도 했다. 출처 : Fortune Magazine, 2007년 11월페이팔 마피아들의 성공은 절대 우연이 아니라고 생각한다. 이들이 닷컴 버블의 위기를 이겨낼 수 있었던 밑바닥에는 페이팔이라는 회사가 가진 확고한 고유의 문화(culture)가 존재했다. 자신들이 만들어 낸 본연의 문화가 몸에 배인 초기 구성원들이 새로운 회사를 시작하고, 또 다시 새로운 그들만의 확고한 문화를 만들어 가면서 또 다른 페이팔이 만들어 질 가능성이 높아졌다고 할 수 있다. 또한 각자가 가진 강력한 인적 네트워크를 통해 서로 도움을 주고 받으며 새로운 회사를 만들고 함께 성장할 수 있도록 하는 노력을 아끼지 않았다. 실리콘밸리에 또 다른 닷컴 버블이 터진다 하더라도 이들 페이팔 마피아의 생존 가능성은 의심할 여지가 없을 것이다. 정부 시스템이 무너져도 마피아 조직의 견고함은 무너지지 않는 영화 같은 이야기가 실리콘밸리에서 실제로 일어나고 있는 것이다.출처 : jamesaltucher.com한국에서는 이런 사례가 없는지 늘 궁금했다. 얼마 전 알토스벤처스의 한킴 대표님 페이스북에서 ‘네오위즈 마피아'에 대한 이야기를 본적이 있다. 그런데 나는 이 이야기를 읽으면서 네오위즈보다 주목해야 할 회사는 첫눈이 아닌가 하는 생각이 들었다. 네오위즈, 넥슨, NHN 같은 회사보다 훨씬 더 마피아의 밀집도가 높은, 미국의 페이팔을 연상시킬만한 작은 조직이었기 때문이다.첫눈은 2005년 6월 네오위즈에서 분사하며 설립되었던 검색 회사다. 가장 큰 특징은 자사의 내부 DB를 통해 검색 결과를 제공하는 경쟁사들과 차별화하여 인터넷 전체를 검색 대상으로 삼는다는 점이었다. 이후 설립 1년 만에 NHN에 350억원 규모로 매각되었고, NHN의 당시 보도자료에 따르면 임직원은 총 55명이었다. ‘첫눈 마피아’에 대해 정리하려고 마음 먹고 그간 나왔던 첫눈에 대한 기사들을 많이 읽어 봤다. 간간이 첫눈을 페이팔 마피아에 비유했던 기사들도 있었다. 또 마침 우리 회사 렌딧의 홍보 담당인 꼬날이 첫눈의 홍보 담당이었던 덕분에 생생한 이야기를 직접 들을 수 있었다. 정리해 본 첫눈 마피아들은 아래와 같다 (존칭 생략):장병규 : 지난 9월 25일 4차산업혁명위원장에 임명되어 국가적 화제의 인물로 떠오른 장병규 블루홀스튜디오 의장이 첫눈의 창업자. 2005년 6월 네오위즈에서 검색엔진 개발팀 인력들을 이끌고 분사해 첫눈을 창업했다. 2006년 6월 첫눈 설립 1년 만에 NHN 과 350억원 규모로 매각. 이렇게 NHN에 들어간 첫눈의 인재들이 주축이 되어 개발한 서비스가 라인(LINE)이다. 장병규 대표는 첫눈의 NHN 인수 후 초기 기업에 전문적으로 투자하는 벤처캐피털 본엔젤스벤처파트너스를 설립해 우수한 창업자와 스타트업을 발굴하고 지원하는 일에 힘써왔다. 2007년에는 게임개발사인 블루홀스튜디오를 창업해 현재까지 의장직을 맡고 있다.신중호 : 신중호 라인 CGO(Chief Global Officer)는 첫눈의 CTO였다. 2005년에 첫눈 창업 시 장병규 대표와 함께 네오위즈에서 나왔다. 2006년 NHN 인수합병 시 NHN에 합류, NHN 재팬의 검색서비스를 책임지고 일본에 건너가 있던 중 라인을 개발했다. 일본과 동남아시아 여러나라에서 현지화에 성공, 2016년 7월 라인의 나스닥 상장을 견인했다. 최근에는 WAVE, Clova 등 네이버의 AI 사업을 총괄하며 미래를 이끌어 가고 있다.이상호 : SK텔레콤 AI사업단장 역시 첫눈 출신이다. 자연언어처리와 음성합성, 음성검색 분야의 국내 최고 권위자로 알려졌다. 첫눈에 합류하기 전에는 LG전자 연구원을 거쳐 서울산업기술대학 교수를 지냈다. 당시 이상호 교수를 첫눈에 영입하기 위해 장병규 대표가 오랜 시간 공을 들인 것으로 알려졌다. 이상호 단장 역시 첫눈의 NHN 인수합병으로 NHN에 합류한 후 음성 검색 서비스 등 검색 개발에 집중하다, 2011년 다이알로이드라는 음성 인식 개발사를 창업했다. 국내 최고의 음성 검색 전문가 4인으로 구성되었던 다이알로이드는 2012년 9월 국내 최초로 음성으로 문자를 전송하는 앱 ‘다이알로이드'를 선보였다 (관련 내용 : http://limwonki.com/536). 이상호 대표는 2012년 말 다음이 다이알로이드를 인수하며 다음을 거쳐 카카오에서 음성 검색 연구를 지속했으며, 이후 SK플래닛에 입사, CTO 로 기술을 책임지다 2017년 4월부터 SKT AI 사업단장을 맡아 누구 (NUGU) 등 AI 부문 사업을 총괄하고 있다.노정석 : 잘 알려지지 않은 사실이지만 노정석 리얼리티 리플렉션 대표 역시 첫눈 출신이다. 첫눈 창업 초기 약 4개월 간 글로벌 사업 담당으로 일하다, 2005년 9월에 블로그 개발사인 태터앤컴퍼니를 창업했다. 노정석 대표는 1996년 카이스트-포항공대 해킹 전쟁의 주인공으로 유명하다. 이후 1997년 선배들과 창업한 보안회사 인젠이 2002년 코스닥 상장에 성공. 2005년에 설립한 태터앤컴퍼니는 2007년 9월 구글이 인수하며 국내 스타트업으로는 드물은 글로벌 M&A 성공 사례로 기록 되었다. 이후 구글에서 2년여 간 프로덕트 매니저로 일하다 2010년에 설립한 파이브락스(설립 시 사명은 아블라컴퍼니)가 2014년 8월 다시 미국의 모바일 광고 플랫폼 회사인 탭조이에 매각되며, 국내 스타트업에서 드물은 글로벌 M&A 성공 사례를 다시 남긴 주인공이 되었다. 2015년 5번째 회사인 리얼리티 리플렉션을 창업해 국내 대표적인 ‘연쇄 창업가'로 불리운다. 창업과 더불어 엔젤투자자로서 좋은 창업가들을 발굴하고 후배 창업가들과 함께 호흡하는 것을 좋아한다. 티몬, 비트파인더, 미미박스, 다이알로이드, 다노, 다이알로이드(다음이 인수), 파프리카랩(일본 그리 인수), 울트라캡숑(카카오 인수) 등에 투자했다. 나 역시 2011년 미국에서 창업했던 두번째 회사인 스타일세즈 창업 때 노정석 대표의 엔젤투자를 받았다.그 외 2011년 모바일 메신저 ‘틱톡'을 개발해 카카오톡의 강력한 경쟁자로 부상했던 매드스마트의 김창하 대표 역시 첫눈 개발자 출신이다. 김창하 대표는 2012년 매드스마트를 SK플래닛에 매각하며 SK플래닛에서 일하다, 현재는 라인에 합류해 신중호 CGO와 함께 일하고 있는 것으로 알려져 있다. 라인의 박의빈 CTO 역시 첫눈 출신으로 오랜 기간 신중호 CGO 와 함께 하고 있는 핵심 인물이다. 천재 개발자로 유명한 보이저엑스 남세동 대표 역시 장병규 대표와 오랫동안 함께 한 개발자다. 19살에 네오위즈 인턴으로 시작해서 세계 최초의 웹기반 채팅 서비스인 ‘세이클럽 채팅' 개발을 주도하였고, 이후 첫눈을 거쳐 라인에서 일했다. 카카오의 AI 사업을 총괄하고 있는 김병학 부사장 역시 첫눈 출신이다.    대기업과 스타트업을 오가며 활약 중인 첫눈의 인재들도 있다. 이은정 라인플러스 이사는 베인앤컴퍼니 등에서 컨설턴트로 일하던 중 장병규 대표에게 스카우트되어 첫눈에 입사. 첫눈이 NHN에 인수된 후 현대카드, GS홈쇼핑, 삼성카드 등 대기업에서 승승장구 하던 중 2014년 라인플러스에 입사해 글로벌 사업의 중추 역할을 하며 다시 신중호 CGO와 일하고 있다. 엘지생활건강에서 모바일 플랫폼 혁신을 주도하고 있는 권도혁 상무 역시 첫눈 출신이다. 첫눈 합류 전 베인앤컴퍼니와 NHN에서 경력을 쌓았던 권도혁 상무는, 첫눈이 NHN에 인수된 후 다시 전직장 NHN에 합류하지 않고 스타트업인 큐박스에 합류했다. 이후 2011년 ‘울트라캡숑' 이라는 재미있는 이름의 스타트업을 창업, 대학생들의 익명 커뮤니티인 ‘클래스메이트', 소셜미디어 서비스 ‘너 말고 니 친구', ‘마티니', 다이어트 앱 ‘다이어터' 등을 개발해 서비스 하던 중 2014년 카카오에 매각하고 엘지생활건강에 합류했다.   스타트업 홍보를 열심히 하고 있는 우리 회사 꼬날도 첫눈 출신이다. 첫눈 (NHN 매각) - 태터앤컴퍼니 (구글 매각) - 엔써즈 (KT 매각, 이후 닐슨에 재매각됨) - 파이브락스 (탭조이 매각) 등 성공적인 엑시트로 평가되는 스타트업에 연이어 렌딧에 합류. 스타트업 홍보의 미다스 손으로 불리는 국내 유일무이한 이력의 홍보전문가다.첫눈이 NHN에 인수되면서 첫눈의 새로운 검색 정책과 혁신적인 서비스에 기대를 많이 했던 초기 사용자들이 '첫눈이 녹아 버렸다'며 아쉬워했었다고 한다. 하지만 첫눈은 매각 당시 보도했던대로 NHN과 함께 글로벌 서비스 개발에 힘썼고, 메신저 서비스 라인을 만들어 글로벌 시장 진출에 성공했다. 또한 다양한 첫눈 마피아들이 여전히 창업 전선에서 맹활약 중이다. 내가 창업에 뛰어든지 이제 만 12년이 되었고 세번째 회사인 P2P금융 렌딧을 시작한지 2년 반이 지났다. 렌딧은 기술 혁신을 통한 금융 서비스의 효율화라는 미션을 갖고 시작되었다. 혁신적인 서비스를 통해 우리 삶에 긍정적인 영향을 주는 것만큼이나 내게 강한 동기가 되는 것은 함께 일하는 사람들과의 동반 성장이다. 렌딧의 성장 뿐만 아니라 우리 고유의 문화가 몸에 배인 렌딧맨들이 미래에 또 다른 곳에서 새로운 혁신을 만들어 낼 수 있는 강력한 렌딧 마피아가 형성되기를 기대해본다.지난 5월27일, 렌딧의 SeriesB 투자가 확정되던 날 모든 렌딧맨과 함께

기업문화 엿볼 때, 더팀스

로그인

/