스토리 홈

인터뷰

피드

뉴스

조회수 1600

스타일쉐어 커머스 시스템 리빌딩 회고 1

스타일쉐어 스토어 소개스타일쉐어 스토어(이하 커머스)는 2016년 4월 출시되어 지금까지 나날이 성장하고 있습니다. 작년 초, 커머스 시스템을 리빌딩하기로 했고 현재까지 진행 중입니다. 어떤 이유로 리빌딩을 하는지, 어떤 고민을 했는지, 어떻게 진행하고 있는지 몇 자 적어보려 합니다. 이 글은 문제 인식, 목표, 계획에 대한 내용입니다.리빌딩을 결정한 이유커머스 프로젝트를 시작할 당시 커머스 시스템을 경험해본 개발자가 없었습니다. 이 상황에서 새로이 구현하기엔 위험 부담이 크다는 판단을 했습니다. 때문에 커머스 솔루션을 도입했고, 적은 비용으로 커머스 기능을 출시할 수 있었습니다. 거래량이 점점 늘어나면서 솔루션이 감당할 수 있는 한계치를 벗어나자, 예상치 못했던 기술적인 이슈가 발생했습니다. 사내 MD팀, CS팀은 물론, 입점사들과 유저들에게까지 불편한 경험을 주고 있었습니다. 개발팀은 솔루션 유지 보수와 운영 이슈에 집중했지만, 끝이 없는 문제들에 점점 지쳐갔습니다. 개발팀의 퍼포먼스는 저하되고 있었고, 새로운 기능 개발에 집중하지 못하는 상황까지 발생했습니다. 이 시점에서도 거래량과 매출은 꾸준히 늘어났으며, 더 늦기 전에 리빌딩을 진행해야겠다고 판단했습니다.리빌딩의 목표당장 눈앞에 생겨나는 문제들로, 서비스가 해결하고자 하는 본질적인 문제들에 집중하지 못하는 상황입니다. 궁극적으로 이 상황을 개선하고 싶었습니다. 그리고 선택의 기로에 섰을 때 좋은 기준을 제시하기 위해, 언제 끝날지 모르는 리빌딩이 산으로 가는 걸 막기 위해 목표를 몇 가지 세웠습니다.유지보수 및 운영 이슈에 소모되는 개발 리소스 최소화커머스 시스템과 연계되는 기능들을 공격적으로 개발할 수 있도록 함개발 리소스 대비 높은 퍼포먼스를 낼 수 있어야 함튼튼한 커머스 시스템목표 1. 유지보수 및 운영 이슈에 들이는 개발 리소스 최소화기존 솔루션의 큰 레거시는 소모될 개발 리소스의 양과 일정을 예측하기 어렵게 만들었고, 개발자에게도 큰 스트레스를 안겨줬습니다. 서비스의 성장을 방해하는 큰 걸림돌 중 하나이며, 개발팀의 움직임을 느리게 만드는 주된 원인이었습니다. 리빌딩을 완료하더라도 유지보수와 운영 이슈는 끝이 없을 테지만, 더 이상 같은 문제를 반복하고 싶지 않았습니다. 효율적인 개발 리소스 운용을 위해선 가장 신경 써야 하는 부분이라고 생각됩니다.목표 2. 커머스 시스템과 연계되는 기능들을 공격적으로 개발할 수 있도록 함기존 솔루션 레거시가 너무 복잡하여 기능을 추가하거나 개선하기 어려워 반려한 요구사항이 많았습니다. 매력적인 요구사항에도 조심스럽게 대응했습니다. 서비스 성장을 위해 다양한 시도를 해야 하는 상황인데, 기술적인 이유로 진행이 까다롭다고 말하는 게 항상 아쉬웠습니다. 개발팀에서도 좋은 기능을 공격적으로 구현하고 싶으나, 실제로도 작업하기 까다로워 항상 답답했습니다. 어떤 방법이던 괜찮으니 지금보다 훨씬 더 공격적인 기능 구현으로 서비스 성장에 좋은 영향을 주고 싶었습니다.목표 3. 개발 리소스 소모 대비 높은 퍼포먼스를 낼 수 있어야 함스타일쉐어 팀은 기존 서비스 운영과 동시에 항상 새로운 무언가를 찾으려 합니다. 개발팀은 이 움직임에 맞춰 개발 리소스를 효율적으로 운용해야 합니다. 하지만 개발 리소스는 한정적이며, 다양항 상황에 따라 유동적으로 변해 예측하기 어렵습니다. 이런 상황에서 커머스 관련 작업 시, 언제나 평균 이상의 높은 퍼포먼스를 내고 싶었습니다.목표 4. 튼튼한 커머스 시스템커머스 시스템의 장애는 매출에 직접적인 악영향을 줍니다. 어떤 작업을 하더라도 커머스 시스템은 잘 운영되어야 합니다. 높은 가용성은 개발팀의 숙명이며, 공격적인 기능 개발에도 높은 가용성을 유지하려면 더욱 신경 써야 합니다.모두 꿈에 가까운 목표들입니다. 이 목표들에 조금이라도 더 가까이 다가갈 수 있도록 노력한다면 보다 좋은 결과를 얻을 수 있을 거라 생각했습니다.현실 반영과 계획당연하게도 현실적인 부분을 생각해야 했습니다. 이미 예정된 작업들이 많아 리빌딩에 필요한 개발 리소스를 확보하기 어려웠고, 개발 성공 여부 또한 불확실해 팀원들을 설득하기 어려웠습니다. 유지보수와 운영 이슈는 끝이 없었고, 회사 방향에 따라 추가 기능 개발과 개선 작업을 진행해야 했습니다. 이 상황을 고려해 리빌딩을 성공적으로 진행할 수 있도록 계획을 세워나갔습니다.개발 리소스에 여유가 생길 때까지 서브 프로젝트로 진행기존 커머스 시스템과 리빌딩된 시스템을 동시에 운영할 수 있어야 함적절한 단위로 서비스를 나눠 안전하고 효율적으로 개발 진행계획 1. 개발 리소스에 여유가 생길 때까지 서브 프로젝트로 진행다들 리빌딩이 필요하다고 느꼈지만, 선뜻 진행하기엔 큰 부담이었습니다. 시간이 흘러 여유가 생길 때 리빌딩을 진행해도 되지만, 그땐 너무 늦을 것 같았습니다. 최대한 빨리 작업을 시작하고 싶었고, 그러기 위해선 서브 프로젝트 수준으로 진행하는 게 제일 빠른 방법이라 생각했습니다.계획 2. 기존 커머스 시스템과 연동되어 동시에 운영할 수 있도록 함리빌딩의 완료 시점을 예측하기 어려웠습니다. 때문에 기존 커머스 시스템을 운영하며 리빌딩을 진행해야만 했습니다. 그리고 리빌딩된 시스템은 점진적으로 기존 커머스 시스템을 교체해 나가야 하므로, 두 시스템이 서로 연동되어야 했습니다. 또한 리빌딩된 시스템이 잘 동작할지에 대한 확신이 없어, 언제나 후퇴 계획을 세워야 했습니다. 이런 이유로 기존 커머스 시스템의 DB와 스키마를 그대로 사용하고, 두 시스템의 로직이 서로에게 문제가 되지 않도록 조심스럽게 개발하기로 했습니다.계획 3. 적절한 단위로 서비스를 나눠 안전하고 효율적으로 개발 진행커져가는 개발팀과 복잡해져 가는 커머스 시스템을 생각하면 요즘 자주 들리는 마이크로 서비스 구조(이하 MSA)를 도입해도 되지 않을까 싶었습니다. 솔직히 이런저런 이유보다, 재미 때문에 도입해보고 싶었습니다. 처음 도입하는 구조라 조심스러웠지만, 적절한 단위로 서비스를 나눈다면 충분히 좋은 효율을 낼 수 있을 것이라 생각되었습니다. 재미와 만족은 덤이고요. 서비스를 나누는 기준은 2가지로 잡았습니다.개발 안정성/개발 속도 둘 중 어느 것에 집중해야 하는가?서비스를 사용하는 주체는 누구인가?—개발 안정성/개발 속도 둘 중 어느 것에 집중해야 하는가?개발 안정성과 개발 속도에 대해 생각한 이유는 시스템 안정성과 작업 퍼포먼스 모두 잡고 싶은 마음 때문이었습니다. MSA는 서비스 별로 다른 언어를 사용해도 괜찮다는 장점이 있습니다. 덕분에 상황 별로 각기 다른 언어를 사용할 수 있고, 이를 통해 개발 안정성 혹은 개발 속도에 잘 집중할 수 있을 것이라 기대했습니다. 나중에 기술 스택을 설명하면서 얘기를 하겠지만, 개발 안정성을 추구해야 하는 부분은 java8로, 개발 속도를 추구해야 하는 부분은 node나 python으로 구현됩니다.서비스를 사용하는 주체는 누구인가?서비스를 어떤 기준으로 나눌지 고민이 많았습니다. 처음엔 상품 관리, 주문 관리, 출고 관리 등 DB 테이블에 가까운 기준으로 나누려고 했으나, 서버 운영이 큰 부담으로 다가올 것 같다는 의견 때문에 다른 기준을 세워야 했습니다. 서비스를 사용하는 주체 별로 나누면 어떨까라는 말이 나왔고, 이 기준이라면 큰 부담이 없을 것 같았습니다. 서비스를 사용하는 주체는 유저, 관리자, 입점사, 다른 서비스 이 4가지라고 정의했고, 이에 따라 서비스를 구성했습니다.—앞서 말한 두 기준으로 나눴을 때에 대한 예시입니다.유저 커머스 서비스 (node 혹은 python)관리자 커머스 서비스 (node 혹은 python)입점사 커머스 서비스 (node 혹은 python)커머스 핵심 기능 서비스 (java8)위 두 기준 말고도 서비스 운영에 큰 부담이 없다면 상황에 맞춰 다른 기준을 세워 서비스를 나누기도 했습니다.이 고민이 끝난 후, 현실적으로 실행 가능한 계획이 나온 것 같아 만족스러웠습니다. 이 계획을 토대로 아키텍처를 구성하고 개발을 진행했습니다.마무리어떤 문제 때문에 리빌딩을 결정했고, 어떤 목표와 계획을 세웠는지 주저리주저리 적어봤습니다. 앞에서 말했듯이 리빌딩은 아직 진행 중입니다. 현재 정식 일감으로 진행되고 있고, 상황에 맞게 계획을 다시 세워 조금씩 목표에 다가가고 있습니다. 처음엔 3부로 계획했지만, 아직 리빌딩 중이란 걸 까먹고 있었나 봅니다. 이 프로젝트가 완료되기 전까진 회고록으로써 글을 계속 쓸 것 같습니다. 앞으로 풀어야 할 문제들이 많으니 하소연할 것들도 많을 거고요. 아무쪼록 다음 편에선 시스템 구성도와 기술 스택에 대해서 한번 이야기해보려 합니다.스타일쉐어 개발팀의 고민과 생각들이 부디 도움이 되었길 빕니다. :)#스타일쉐어 #개발팀 #리빌딩 #인사이트 #조언
조회수 976

[인공지능 in IT] '머신 비전', 내 눈에 걸리기만 해봐

50~60년대 국내 상황은 말로 표현하기 힘들다. 당시 강대국들은 전쟁 직후 한국이 다시 정상적으로 복귀하는 것은 불가능하다고 여길 정도였으니, 여러 모로 살아남기 힘든 환경이었던 것만은 분명하다. 하지만, 뭐든지 열심히 노력하는 특유의 국민성을 바탕으로 한걸음씩 내딛기 시작했고, 1988년 서울 올림픽까지 개최할 정도로 경제 성장을 이뤘다. 당시 필자가 태어난 것은 아니었지만, 여러 자료나 부모님 세대의 말씀을 조합하면, 이 같은 성장의 중심에는 제조업의 부흥이 있었기 때문이다.제조업은 국가 실물 경제의 근간이라고 할 정도로 중요한 역할을 담당한다. 단단한 제조업 생태계가 창출해 내는 부가가치를 바탕으로 서비스업이 발전한다면, 산업의 경쟁력을 잃지 않으면서 지속적인 성장을 이뤄낼 수 있는데 큰 보탬이 된다. 최근에는 인공지능과 같은 고도의 기술이 널리 퍼져 제조업의 중요성을 더욱 부각하고 있다. 전통적인 기계 산업 기술은 과학기술을 지탱하는 뿌리의 역할을 하고, 인공지능이나 데이터의 확장 등 탄탄한 제조업 중심의 주력 산업과 융합해 폭발적으로 성과를 낼 수 있다. 결국, 아무리 새로운 기술이 등장한다 해도, 제조업과는 떼려야 뗄 수 없는 관계인 셈이다.인공지능은 제조업에서 매우 유용하게 쓰이고 있다. 그 중에서 공장 자동화에 큰 역할을 하고 있는 '머신 비전(Machine Vision)'에 대해서 이야기를 해보자. 머신 비전은 사물인식, 얼굴인식, 이미지 캡션, 문자 인식 등 여러 형태로 적용되며, 최근 들어 딥 러닝을 통해 더욱 강력해지고 있다. 특히, 비전을 활용해 불량품을 검출하는 'Defect Detection'은 제조업에서 큰 역할을 할 수 있다. 대다수의 공장에서 제품 생산 마지막 공정은 '품질보증(Quality Assurance, QA)'이다. QA를 통해서 생산한 제품 혹은 부품에 문제가 없는지 확인한 후, 구매자에게 좋은 품질의 제품만을 제공해야 하기 때문에 매우 중요하다.실제로 대량생산라인을 보유하고 있는 제조업 기반 기업은 QA에 막대한 비용을 소모하고 있다. 때문에 유심히 확인하지 않거나, 몇몇 샘플들만 체크하고, 심지어 QA를 생략하는 경우도 있다. 결국 피해는 고스란히 최종 구매자에게 이어진다. 예를 들어, 새로 장만한 스마트폰이나 자동차 부품에 흠집이 있는 경우, 최종 구매자가 겪어야 할 불편함은 작지 않다. 또한, 고객 충성도 하락까지 이어질 수 있어 기업은 사전에 방지해야 한다.불량품 검출이 이루어지는 프로세스를 간단하게 알아보자. 스켈터랩스의 정수익 책임 PM의 도움을 받아 이미지로 구성했다.< 불량품 검출 프로세스, 출처: 스켈터랩스 >먼저 부품 생산 과정 중 불량을 탐지하기 위해서는 광학 기기를 사용해 사진을 찍어야 한다. 그리고 촬영된 사진을 이용해 머신 비전으로 탐지하는 것이다. 하지만, 머신 비전이 적용되었다고 해서 바로 족집게처럼 불량품을 검출해낼 수 있는 것도 아니다. 이미 많은 이들이 알고 있지만, 딥 러닝은 수많은 데이터셋을 바탕으로 선행한 학습 전제가 필요하다. 결함으로 판명된 부품들에 대한 데이터를 수집하고, 학습해 '이 부품은 이런 형태의 손상이 있으니 불량이다'라고 판단하는 방식이다. 인식하고, 학습하고, 검출하는 단계를 계속해서 반복하며 기계가 점점 '똑똑해진다'라고 할 수 있다.이어서 스켈터랩스의 사례를 참고해보자. 내부에서 개발하고 있는 불량품 검출 서비스는 크게 세가지 부분으로 구성된다. 파란색 네모 안에 있는 이름은 가제다.< 스켈터랩스의 머신 비전 불량품 검출 서비스 >하나씩 살펴보면, 'Dulok'은 실제로 현장에서 촬영되는 이미지를 모니터링하거나, 이를 클라우드에 업로드하는 '모니터링 모듈'이며, 'Ewok'은 웹상으로 부품 정보에 대해 'curation', 'labeling', 추론 결과를 확인할 수 있도록 하는 '애플리케이션'이다. 마지막으로 'Gorax'는 '학습을 통해 부품의 결함을 검출하는 모델'이다. 이 부분은 실제 서비스에서 단순히 딥 러닝을 통한 추론 외에도 다른 피쳐들이 제공되어야 한다.기존에는 사람이 이미지 상에서 결함에 대한 정의를 하나하나 내리고, 결함의 특징을 수동으로 설정해야 했다. 때문에 반도체나 LCD처럼 표면 형태가 정형화되어 있는 분야에서만 머신 비전 기술을 활용할 수 있었다. 반대로 섬유나 천연가죽 등 표면 형태가 비정형화된 분야에서는 결함 특징 값을 수동으로 설정하기 어려워 육안검사에 의존해야만 했다.그러나 점차 '머신 비전' 기술이 발전하면서 적용되는 영역은 계속 늘어나고 있다. 이는 품질을 높이는 결과로 이어져, 결과적으로는 최종 소비자들이 혜택을 받는다. 이처럼 인공지능 기술은 향후 지속적으로 발전을 거듭해 제조업의 일자리를 뺏는 것이 아닌, 함께 공생하는 생태계를 구축하는데 도움될 것이라 생각한다.이호진, 스켈터랩스 마케팅 매니저조원규 전 구글코리아 R&D총괄 사장을 주축으로 구글, 삼성, 카이스트 AI 랩 출신들로 구성된 인공지능 기술 기업 스켈터랩스에서 마케팅을 담당하고 있다#스켈터랩스 #기업문화 #인사이트 #경험공유 #조직문화 #인공지능기업 #기술기업
조회수 1102

안드로이드 색상 투명도

제 깃헙블로그 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참고한 블로그: 커피한잔의 여유와 코딩#트레바리 #개발자 #안드로이드 #앱개발 #인사이트 #경험공유 #꿀팁
조회수 4350

크몽 검색 기능 개선기

안녕하세요? 크몽의 백엔드 개발자로 활동하고 있는 에이든입니다. :)오늘은 크몽에 입사하고 한 달 동안 UX팀에서 진행한 검색 기능 개선에 대한 이야기를 해보려고 합니다.배경크몽에는 재능을 판매하는 프리랜서의 서비스 정보가 많이 저장되어있습니다. 판매하는 서비스 정보가 많을수록 검색 기능이 잘 되어있다면 사용자는 원하는 서비스를 빨리 찾을 수 있고, 프리랜서는 다양한 서비스를 의뢰인에게 판매할 수 있습니다.크몽에서는 사용자에게 정확한 검색으로 다양한 서비스를 제공하기 위해 노력하고 있습니다. 이번 글에서는 크몽 UX팀에서 보다 나은 검색 기능을 위해 어떠한 노력을 했는지 공유하고자 합니다.기존의 검색 기능기존의 검색 기능은 기본적인 키워드 검색 외에 별다른 기능을 제공하지 않았습니다. 그리고 스핑크스 검색엔진으로 구성되었습니다. 스핑크스는 전문 텍스트 검색 기능을 제공하며 데이터베이스와 잘 통합될 뿐만 아니라 스크립트 언어에 쉽게 접근할 수 있도록 설계되었습니다. 스핑크스의 동작 구조는 다음과 같습니다.스핑크스의 동작 구조Searchd는 클라이언트로부터 요청을 받고 스핑크스 인덱스에 대해 검색을 실행하는 역할을 합니다. 그리고 스핑크스 인덱서는 스핑크스 인덱스로 데이터를 가져오는 역할을 합니다.크몽은 이를 통해 사용자에게 검색 기능을 제공했습니다. 하지만 기존의 검색 기능은 불편한 점이 있었습니다.기존의 검색 기능의 불편한 점기존의 검색 기능은 의뢰인이 어떤 서비스를 필요로 하는지 본인이 정확하게 정의할 수 있어야 했습니다. 그게 아니라면 여러 키워드를 검색해보거나 원하는 서비스를 찾기 위해 해당 카테고리에서 서비스 전체를 둘러봐야 했습니다. 또한 많은 유료광고로 인해 사용자는 일반 서비스를 찾기가 힘든 문제가 있었습니다.기능상의 불편한 점뿐만 아니라 구현상에도 불편한 점이 있었습니다. 스핑크스에서 한글 검색을 구현하기 위해서는 복잡한 설정을 거쳐야 했으며 ngram analyzer를 통해서만 한글 형태소 분석이 가능했습니다. ngram analyzer는 음절 단위의 한국어 형태소 분석을 하므로 인덱스의 양이 많아질 뿐만 아니라 불필요한 정보까지 검색에 노출이 됩니다. 불필요한 정보가 노출되면서 종료율은 높아지고 서비스 상세페이지의 전환율이 낮아졌습니다. 또한 스핑크스는 데이터의 저장이 되지 않기 때문에 분석을 위해서는 별도의 과정이 필요했습니다.이에 크몽 개발팀은 사용자를 위한 검색 기능 보강뿐만 아니라 검색 엔진 변경이라는 결론을 내립니다.새로운 검색 기능새로운 검색 기능을 개발하기에 앞서 요구사항을 파악하고 새로운 검색 엔진에 대한 기술 탐색을 선행했습니다.프로젝트 진행 목적 및 요구사항정확한 검색 결과 제공광고 상품 제거를 통한 서비스 상세페이지로의 전환율 증대서비스 검색에 최적화된 검색 플로우무엇을 검색해야 할지 모르는 사용자를 위한 검색 가이드검색 엔진 및 한글 형태소 분석기 변경을 통해 사용자에게 정확한 검색 결과를 제공하는 게 우선순위였습니다. 그리고 광고 상품을 제거하고 사용자가 다양한 서비스를 찾을 수 있게 도와주는 기능을(자동완성검색, 연관검색어, 인기검색어) 추가했습니다. 그뿐만 아니라 서비스 검색에 최적화된 검색 플로우를 위해 UI 개선도 진행했습니다.새로운 검색 엔진새로운 검색엔진을 찾던 중 은전한닢 한글 형태소 분석기를 공식으로 지원하는 엘라스틱서치를 찾았습니다.17개 검색 엔진 순위 (출처: DB-ENGINES)17개 검색 엔진의 순위를 살펴보면 아파치 루씬 기반의 엘라스틱서치가 다른 검색 엔진보다 100점 넘게 차이 나는 압도적인 점수를 기록하고 있습니다. 위의 점수는 구글이나 빙에서 언급 횟수, 구글 트렌드, 기술적 논의 횟수, 채용 공고, 소셜 네트워크에서 언급 횟수 등으로 측정한 점수입니다. 점수 산정 방법이 객관적이지 못하지만 엘라스틱서치가 핫하다는 것에는 이견이 없었습니다. 이에 본격적으로 엘라스틱서치에 대해서 기술 탐색을 시작했으며 스핑크스와 비교도 해봤습니다.엘라스틱서치엘라스틱서치는 확장성이 뛰어난 RESTful 검색 및 분석 엔진입니다. 대용량 데이터를 빠르고 실시간으로 저장, 검색 및 분석할 수 있습니다. 기술 탐색 결과 엘라스틱서치에 저장한 데이터를 키바나를 통해서 분석하고 시각화할 수 있다는 점이 매력적이었고, 공식으로 한글 형태소 분석기를 지원하기 때문에 검색 정확도를 높일 수 있다고 생각했습니다. 한글 형태소 분석기를 이용한 엘라스틱서치의 분석 과정은 다음과 같습니다.한글 형태소 분석기를 이용한 엘라스틱서치의 분석 과정필드의 title에 블로그 검색에 엘라스틱서치를 적용해보려고 합니다. 라는 문장이 있다면 지정한 analyzer를 통해서 분석을 진행합니다. 먼저 문자 필터를 거치고 은전한닢으로 한글 형태소 분석을 수행합니다. 형태소 분석이 완료되면 [블로그, 검색, 엘라스틱, 서치, 적용, 보, 하]로 나누어집니다. 그리고 토큰 필터를 통해 [블로그, 검색, 엘라스틱, 일래스틱, elasticsearch, es, 서치, 적용, 보, 하]로 term이 만들어집니다. 이 term은 elasticsearch index에 문서 id와 함께 저장됩니다.다음은 엘라스틱서치와 스핑크스를 비교해봤습니다.엘라스틱서치 vs 스핑크스엘라스틱서치 vs 스핑크스엘라스틱서치와 스핑크스를 비교해보면 스핑크스도 충분히 좋은 검색엔진이지만 한글형태소 분석기와 키바나의 시각화, 데이터 분석 같은 장점을 활용하기 위해 엘라스틱서치를 도입하기로 했습니다.도입을 결정하고 엘라스틱서치를 구축하는 방법을 알아봤습니다.  1. 엘라스틱 클라우드를 사용하는 방법  2. AWS Elasticsearch Service를 이용해서 구축하는 방법3. EC2 인스턴스에 오픈소스 엘라스틱서치를 직접 설치해서 구축하는 방법   엘라스틱서치를 구축하는 방법에는 보통 3가지 방법이 있고 아래의 특징을 가지고 있습니다.1번은 엘라스틱에서 관리 및 교육, 컨설팅을 지원해줍니다. 그리고 한글 형태소 분석기 은전한닢을 지원합니다. 최신 버전의 엘라스틱 스택을 바로 사용할 수 있으며 모니터링 기능도 지원합니다. 라이선스 별 지원은 링크를 통해서 확인할 수 있습니다.2번은 AWS에서 제공하는 Elasticsearch Service이며, 관리형 서비스입니다. 같은 VPC에 묶여있는 인스턴스를 통해서만 접근할 수 있게 되어있으며 외부에서는 접근할 수 없습니다.(퍼블릭 액세스도 있으나 AWS에서 권장하지 않습니다.) 키바나를 사용하기 위해서는 같은 VPC의 인스턴스 웹 서버 프록시나 AWS 코그니토로 접근해야 합니다. 한글 형태소 분석기 은전한닢을 지원하지만 다른 플러그인은 지원하지 않는 경우가 많이 있습니다. AWS Elasticsearch Service에서 지원하는 플러그인 리스트는 여기에서 확인할 수 있습니다.3번은 EC2 인스턴스에 오픈소스 엘라스틱서치를 설치해서 사용하는 방법입니다. 직접 서버를 구축하는 방법이기 때문에 사용자가 어떻게 사용하느냐에 따라 달라집니다.크몽 개발팀은 가격, 관리적 측면을 고려한 결과 2번 AWS Elasticsearch Service로 구축을 진행했습니다.구현구현은 엘라스틱에서 라라벨 프레임워크에서 사용할 수 있는 엘라스틱서치 관련 라이브러리를 정리해둔 링크를 참고했습니다. 3개의 라이브러리 중 스타가 제일 많은 Plastic 라이브러리를 사용해서 구현을 시도한 적이 있었는데 몇 가지 장점이 있었지만 엘라스틱서치 5까지만 지원을 하므로 field type에 text, keyword가 존재하지 않아 매핑하는데 문제가 있었습니다. 그리고 아직 지원하지 않는 쿼리도 존재하기 때문에 결국에는 PHP 공식 엘라스틱서치 클라이언트 라이브러리인 Elasticsearch-PHP를 사용해야 되는 상황도 발생했습니다. 위에서 말한 점 때문에 Plastic 라이브러리를 걷어내고 Elasticsearch-PHP만 이용해서 개발을 진행했습니다. 엘라스틱에서 제공하는 Elasticsearch-PHP 가이드도 잘 정리되어있습니다. 더욱 자세한 구축, 구현 방법을 알고 싶으신 분들은 아래의 글에서 확인하실 수 있습니다.라라벨 프레임워크 - 엘라스틱서치 사용 경험기 : 초기 작업 수행라라벨 프레임워크 - 엘라스틱서치 사용 경험기 : 문서 관리 작업 수행결과검색 기능 개선 결과는 아래와 같습니다,1.자동완성검색자동완성검색 기능2. 연관검색어 + 검색 결과 광고 제거연관검색어 및 검색결과 광고 제거3. 키워드와 관련된 카테고리 추천키워드와 관련된 카테고리 추천4. 검색 결과가 없는 키워드에는 인기검색어 추천검색 결과가 없는 키워드에는 인기검색어 추천무엇을 검색해야 할지 모르는 사용자를 위한 검색 가이드를 만들기 위해 노력했으며, 기능 추가로 사용자의 검색 만족도와 정확도를 높이려고 노력했습니다.또한 엘라스틱서치와 한글 형태소 분석기 은전한닢을 이용해 검색 기능 개선을 통한 결과 평균 체류 시간은 20초 정도 증가했으며 종료율은 최대 22.4%, 평균 1% 정도 떨어졌습니다. 또한 서비스 상세페이지 전환율은 최대 78.3%, 평균 3% 이상 증가했습니다. 서비스 상세페이지 전환율의 상승은 사용자의 검색 만족과 검색 정확도가 상승했다고 볼 수 있습니다.정리이번 글에서는 엘라스틱서치와 한글 형태소 분석기 은전한닢을 이용해 검색 기능을 개선한 이야기를 정리해봤습니다. 검색 기능 개선 이후 서비스 상세페이지 전환율이 조금씩 상승 중입니다. 릴리즈한지 두 달 정도밖에 되지 않아 조금 더 지켜봐야 하겠지만 전환율이 조금씩 상승하고 있다는 건 좋은 신호인 거 같습니다. 다만 짧은 글을 통해서 경험을 전달하려고 하니 많은 내용을 담지 못한 것 같아 아쉽습니다. 다음에는 더욱더 깊이 있는 글을 전달할 수 있는 에이든이 되겠습니다. 감사합니다.#크몽 #개발팀 #개발자 #개발문화 #경험공유 #인사이트
조회수 2651

Next.js 튜토리얼 8편: 컴포넌트 스타일링

* 이 글은 Next.js의 공식 튜토리얼을 번역한 글입니다.** 오역 및 오탈자가 있을 수 있습니다. 발견하시면 제보해주세요!목차1편: 시작하기 2편: 페이지 이동 3편: 공유 컴포넌트4편: 동적 페이지 5편: 라우트 마스킹6편: 서버 사이드 7편: 데이터 가져오기 8편: 컴포넌트 스타일링 - 현재 글9편: 배포하기개요지금까지 컴포넌트를 스타일링 하는 것을 미뤄왔습니다. 그러나 이제는 몇 가지 스타일을 적용해볼만 합니다.React 애플리케이션에는 컴포넌트를 스타일링 할 수 있는 여러가지 기술들이 있습니다. 크게 두 가지 방법으로 분류할 수 있습니다:1. 전통적인 CSS 파일 기반의 스타일링 (SASS, PostCSS 등)2. CSS in Js 스타일링 결과적으로 전통적인 CSS 파일 기반의 스타일링(특히 SSR)은 실용적인 문제가 많아 Next.js에서 스타일을 지정할 때는 이 방법을 사용하지 않는 것이 좋습니다. 대신 CSS in JS 방법을 추천합니다. 이 방법은 CSS 파일들을 불러오는 것보다 개별적인 컴포넌트 스타일링 할 때 사용 할 수 있습니다.Next.js는 styled-jsx라는 CSS in JS 프레임워크를 미리 설치해두었습니다. 컴포넌트에 이미 익숙한 CSS를 작성할 수 있습니다. 이 CSS는 해당 컴포넌트에만 적용되며 심지어 하위 컴포넌트에도 적용되지 않습니다.이는 CSS가 범위가 있음을 뜻합니다.styled-jsx를 어떻게 사용할 수 있는지 살펴봅시다.설치이번 장에서는 간단한 Next.js 애플리케이션이 필요합니다. 다음의 샘플 애플리케이션을 다운받아주세요:아래의 명령어로 실행시킬 수 있습니다:이제 http://localhost:3000로 이동하여 애플리케이션에 접근할 수 있습니다.home 페이지 스타일링하기home 페이지(pages/index.js)에 스타일을 추가해봅시다.간단히 pages/index.js를 다음과 같이 변경해주세요:   <style jsx> 엘리먼트를 살펴봅시다. 이것은 CSS를 작성하는 곳입니다.코드를 바꾼 후 블로그 home 페이지는 다음과 같이 보일 것입니다:위의 코드에서 스타일 태그 안에 직접 스타일을 작성하지 않고 템플릿 문자열 안에 작성하였습니다.템플릿 문자열({``}) 없이 직접 CSS를 작성해봅시다:어떤 일이 일어날까요?- 아무 일도 일어나지 않는다.- 새로운 스타일이 적용된다.- "문법 에러: 기대되지 않는 토큰"이라는 에러가 발생한다.- "허용되지 않는 스타일 제공자"라는 에러가 발생한다.스타일은 템플릿 문자열 안에 위치해야 합니다styled-jsx는 babel 플러그인을 통해 동작합니다. babel 플러그인은 빌드 과정에서 모든 CSS를 분해하고 적용합니다. (스타일이 추가 시간 없이 적용됩니다)styled-jsx 내에 제약 조건을 제공합니다. 나중에 styled-jsx 안에 동적 변수를 사용할 수 있습니다. 이것이 스타일을 템플릿 문자열 ({``}) 안에 작성해야하는 이유입니다.스타일과 중첩된 컴포넌트home 페이지에 작은 변화를 만들어봅시다. 다음과 같이 링크 컴포넌트를 분리시켰습니다:    import Layout from '../components/MyLayout.js'   pages/index.js 안의 내용을 위와 같이 수정해봅시다.무슨 일이 일어나나요?- 아무런 일도 일어나지 않는다.- 링크가 아닌 h1만 스타일이 적용된다.- 페이지에 에러가 발생한다.- 콘솔에 에러가 발생한다.중첩된 컴포넌트에는 적용되지 않습니다위의 코드를 실행하면 다음과 같이 보입니다:보다시피 CSS는 하위 컴포넌트 내부의 엘리멘트에는 적용되지 않습니다.styled-jsx의 특징은 더 큰 애플리케이션에서 스타일들을 관리할 때 도움이 됩니다.이 경우에는 하위 컴포넌트에 직접 스타일을 적용해야 합니다. 지금 상황에서는 링크 컴포넌트에 직접 스타일을 적용해야 합니다:다른 방법로는 global selectors을 사용할 수 있습니다.전역 스타일때때로 하위 컴포넌트 안의 스타일을 바꿔야 합니다. 일례로 React에서 마크다운을 사용하는 경우가 있습니다. post 페이지(pages/post.js)에서 볼 수 있습니다.post 페이지는 전역 스타일이 유용하게 쓰일 수 있는 곳입니다. styled-jsx를 사용하여 몇 가지 전역 스타일을 추가해봅시다. pages/post.js에 다음과 같은 내용을 적용해주세요.다음 내용을 적용하기 전에 npm install --save react-markdown 명령어를 통해 react-markdown 컴포넌트를 설치해주세요. 무슨 일이 일어나나요?- 아무런 일도 일어나지 않는다.- 마크다운 컨텐츠에 스타일이 적용된다.- 페이지에 에러가 발생한다.- 콘솔에 에러가 발생한다.전역 스타일이 동작합니다전역적으로 스타일이 적용되므로 잘 동작합니다.이 기능은 매우 유용할 수 있지만 항상 전역 prop 없이 스타일을 작성하길 추천합니다.여전히 일반적인 스타일 태그보다 좋은 방법입니다. styled-jsx를 사용하면 필요한 모든 접두사와 CSS 유효성 검사가 babel 플러그인 내부에서 수행되어 추가적인 런타임 오버헤드가 없습니다.다음엔 무엇을 해야할까요이 편에서는 styled-jsx의 표면만 다루었습니다. 더 많은 것들을 할 수 있습니다. styled-jsx Github 저장소에서 더 많은 내용을 참고하세요.Next.js에서 꽤나 괜찮은 다른 스타일링 방법들이 있습니다. 이 부분도 같이 참고해주세요.#트레바리 #개발자 #안드로이드 #앱개발 #Next.js #백엔드 #인사이트 #경험공유
조회수 1875

Swift 4.1에서 딥링크로 앱을 여는 경우 크래시되는 문제 해결하기

최근 Xcode 9.3 버전이 배포되었습니다. 이 버전에는 가장 최신의 Swift 4.1 버전이 포함되어 있습니다. Swift 4.1에는 여러 흥미로운 개선사항들이 많지만, 치명적인 버그도 존재합니다. 바로 딥링크를 통해 앱을 여는 경우 크래시가 발생하는 문제입니다. StyleShare에서는 QA 과정을 통해 문제를 발견할 수 있었습니다.만약 여러분의 애플리케이션이 아래 조건을 모두 충족할 경우 문제가 발생합니다:Swift 4.1 버전을 이용해서 빌드한 경우Deployment Target이 iOS 11.0 미만인 경우AppDelegate에서 application(_:open:sourceApplication:annotation:) 메서드를 구현한 경우문제를 재현하기에 가장 좋은 방법은 Safari 앱을 이용하는 것입니다.1. iOS 기기 또는 사뮬레이터에서 Safari 앱을 구동합니다.2. 주소 입력란에 앱이 지원하는 딥링크 URL을 입력한 뒤 이동합니다. (e.g. myapp://)3. 앱이 구동됨과 동시에 강제 종료됩니다.이 버그는 Swift 이슈 트래커에 SR-7240 티켓으로 이미 등록되어 있습니다. Resolved 상태로 표시되지만 이번 Xcode 9.3 버전에는 포함되지 않은 것으로 보입니다. 다행히 댓글에 한 개발자가 문제를 해결할 수 있는 workaround를 공유해두었는데요. 이 방법을 이용하면 당장의 문제는 해결할 수 있습니다. AppDelegate 메서드의 annotation 파라미터의 타입을 Any에서 Any?로 변경하는 것입니다.- func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool + func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any?) -> Bool<iframe width="700" height="250" data-src="/media/0ce1fe8c63fca7a6c953233b94406d02?postId=ed495077c36" data-media-id="0ce1fe8c63fca7a6c953233b94406d02" data-thumbnail="https://i.embed.ly/1/image?url=https://avatars2.githubusercontent.com/u/931655?s=400&v=4&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://medium.com/media/0ce1fe8c63fca7a6c953233b94406d02?postId=ed495077c36" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 100px;">UIApplicationDelegate에 정의된 메서드 시그니쳐와 다르기 때문에 컴파일러가 경고를 표시하지만 무시하셔도 됩니다.만약 새로운 버전의 앱을 릴리즈 할 계획을 가지고 계시다면 이 이슈를 꼭 확인하시길 바랍니다. 이 버그는 페이스북 로그인 등 다른 앱을 이용한 로그인이나, 카드 결제 후 주문서로 돌아오는 흐름에서 큰 문제를 일으킵니다. 이 글이 여러분들께 도움이 되길 바랍니다.Swift Korea 그룹에서 Xcode Release Notes에도 같은 내용이 있다는 것을 제보해주셨습니다. Swift Compiler 섹션의 Known Issues 4번째 항목입니다.#스타일쉐어 #개발팀 #개발자 #개발후기 #경험공유 #인사이트
조회수 1544

8퍼센트 CTO 1년 차 회고

2015년 11월 4일에 8퍼센트에 입사했으니 이제 1년이 되었다. CTO라는 직함을 달고 보낸 지난 1년을 뒤돌아 본다.1년전 첫번째 스프린트나는 무엇을 원했던가?회고를 할 때는 목표를 기준으로 지금을 살펴봐야 한다. 일 년 전에 썼던 8퍼센트에 입사하기까지 라는 글을 다시 꺼내어 보니 당시의 나는 이런 것들을 원했다. 성공하는 회사에 다닌다.개발 조직을 책임 지고 꿈꿔왔던 이상을 실험한다.회사 경영을 경험한다.사회에 도움이 되는 일을 한다.1) 성공하는 회사에 다닌다. 입사 전이라 "성공하는 회사에 다닌다”라고 적었지만 입사를 한 이상 “회사를 성공시킨다”라는 목표로 바꿔서 생각해도 좋겠다.2015년 10월 말을 기준으로 78.4억의 누적 대출액이 현재 기준으로 480억 가량 되니 지난 1년 동안 약 400억의 돈을 투자자로부터 대출자에게로 연결했다. 나는 이 돈의 크기가 정확히 8퍼센트라는 회사의 사회적인 영향력 그리고 고객들이 회사에 갖는 신뢰의 크기라고 생각한다. 또한 회사의 성공의 척도이다.그럼 이 400억이 성공을 이야기할 때 충분한가에 답을 해야 할터인데, 아직은 많이 부족하다. 하지만 어디인지 모르는 성공이라는 것에 다가갈 확률이 일 년 전에 비해 높아졌느냐라고 묻는다면 "그렇다"라고 자신 있게 말하겠다. 그리고 나 또한 그 확률을 높이는 것에 공헌하고 있다.입사할 당시에 대표님이 내세웠던 조건 중 하나가 올해 말 기준으로 500억이었는데, 그 기준은 넘기게 되었으니 80점을 주자.2) 개발 조직을 책임 지고 꿈꿔왔던 이상을 실험한다.입사 전에는 개발 조직만 맡을 것이라고 생각했으나, 현재는 더 넓은 프로덕트를 만드는 조직을 책임지고 있다. 1년 전에 꿈꿨던 이상이라는 것은 멋지게 일하는 조직이다. 입사 초기에는 이를 위해 꽤나 많은 노력을 했다. 회사 자체가 백지상태이기도 했고 의욕도 충만했다. 하지만 시간이 지나면서 나도 모르게 안주하게 되고 더 잘하기 위한 노력에 게을러졌다. 반성하자. 그래도 일 년 동안 데모를 한 번도 빠지지 않고 34차례 진행했다. (종종 프로젝트 진척이 잘 되지 않으면 데모에서 도망가고 싶다) 그리고 주기가 끝날 때마다 프로세스 개선을 위한 회고 회의를 해왔다. 비록 그 과정에 보완할 점은 많으나 포기하지 않고 프로세스를 일 년 동안 유지한 것에 점수를 주고 싶다. 이상에는 아직 멀었으나 이 조직이 내가 많은 것들을 실험할 수 있고, 그런 설득만 할 수 있다면 그 실험에 기꺼이 동참해 줄 수 있는 조직이라는 것을 깨달았다. 80점으로 시작해서 50점까지 내려갔다가 최근에 10점 정도를 얻었다. 60점을 준다.3) 회사 경영을 경험한다. 초기에 대표님의 신뢰를 얻는데 까지 시간이 꽤 걸렸다. 지금 생각해보면 서로 간의 신뢰를 쌓는데 시간이 걸리는 것은 자연스러운 것인데, 초기에는 의욕이 앞섰다. 왜 내게 더 많은 것을 맡기지 않는지가 불만스러웠다. 대표님이 내리는 결정의 많은 부분에 의심이 들었으며 딴지를 걸었다. 하지만 지금은 대표님의 선택과 결정이 대부분 이해되고 신뢰가 간다. 그리고 대표님이 내게 많은 것을 위임하고 믿어주는 것을 느낀다. 합이 맞아간다.생각보다 회사는 시장의 시간에 쫓겨  부족한 정보를 가지고 결정을 내려야만 했다. 회사의 결정이 모든 것을 좌우한다고 생각했었지만 이제는 결정에 따른 실행이 더 중요하다는 것을 알게 되었다. 4) 사회에 도움이 되는 일을 한다. 사회에 도움이 되는 일을 하는 것은 이 회사에 입사했을 때 결정이 되었다. 회사의 성장이 사회에 미치는 긍정적인 영향과 비례한다는 생각에는 변함이 없다. 이 회사의 존재가 이미 사회에 많은 영향을 미쳤다. 그리고 대부분은 긍정적인 영향이라고 생각한다. 90점을 주겠다.일하는 것의 변화 1) 일하는 양의 변화초기 반년은 후회가 없을 정도로 최선을 다해서 살았다. (내가 인생에서 이런 말을 할 수 있는 시기가 몇 번 없다.) 내 역량의 100%를 다하며 살았다. 그 6개월을 지난 이후에는 살짝 기어를 낮췄다. 좋게 말하면 마라톤을 위한 모드로 바꿨다고도 할 수 있고 어쩌면 6개월의 달리기로 조금 지쳤는지도 모르겠다. 2) 시간 분배의 변화처음 입사했을 때에는 시간의 50%를 개발에 사용했지만 지금은 10% 밖에 사용하지 못하고 나머지 40% 를 프로젝트 관리에 사용하고 있다. 30% 정도를 팀에 쓰고 있는데 처음에는 팀의 구조를 갖추는 데 사용했다면 지금은 팀을 운영하는 데 사용한다. 대체로 자리에 앉아 있는 시간이 많이 줄었고 내외부 사람들과 커뮤니케이션하는 시간이 늘어났다. (슬랙 통계를 보니 내가 압도적인 수다쟁이더라)나는 무엇을 배웠을까? 1) B2C 사업에서의 배움 기존에 일했던 회사는 B2B 회사였다. 손에 꼽을 수 있는 고객을 만족시키면 되었고 상대적으로 그들이 원하는 것은 명확했다. 혹은 커뮤니케이션을 통해 요구사항을 명확하게 만들 수 있었다. 상대적으로 긴 호흡으로 일을 했고, 성능이 중요했다.B2C 서비스는 달랐다. 고객은 어떤 면에서는 전혀 이성적이지 않았다. 놀라운 일이었다. 하지만 대부분 우리의 서비스는 냉정하게 평가되었다. 고객의 반응은 즉각적이지만 그 반응을 옳게 해석해서 제품에 반영하는 것은 어렵구나라는 것을 느꼈다. 지금 이 순간 고객을 최대로 만족시키는 선택이 회사에 있어 항상 옳은 선택은 아니라는 것도 알았다. 내가 개발하고 있는 서비스를 사용하는 많은 사람들이 있다는 것 그리고 사회에 직접적인 영향을 미친다는 것이 제품 개발을 지속할 수 있는 큰 동기가 된다는 것을 느꼈다.2) 프로덕트 책임자로서의 배움제품을 책임지고 있는 사람으로 B2C 서비스에 필요한 많은 역량이 부족하다는 것을 알게 되었다. 그리고 나의 부족한 역량이 완성도가 떨어지는 서비스에 많은 영향을 주고 있다는 것 또한 알게 되었다. 기획자와 일하는 경험, 디자이너와 일하는 경험 모두 처음이었다. 이를 통해 같은 회사에서 하나의 제품을 만들지만 그것을 바라보는 다양한 시각이 존재한다는 것을 알게 되었다.지난 회사의 CTO를 보며 제품의 문제를 어떻게 이렇게 잘 찾아낼까 생각했었는데 나 또한 그렇게 되더라. 통찰력이 아니라 관심을 얼마나 가지는가, 얼마나 책임감을 가지고 제품을 바라보는가에 대한 차이라는 것을 알게 되었다. 많은 기술적, 비즈니스에 기반한 결정을 했고, 그 결정의 결과를 지켜보고 있다. 그것에서 배웠다.3) 프로젝트 관리자로서의 배움 프로덕트팀이 일하는 방식으로 스크럼을 도입했다. 스크럼을 할 때 ScrumBut(우리는 스크럼을 해요. 하지만 이것저것은 하지 않아요.)을 유의하라는 말을 하는데 스크럼에서 요구하는 것들 중에서 하지 못한 것들이 꽤 있다. 예를 들면 업무의 양을 측정해서 번다운 차트를 제대로 그려가며 팀의 속도를 측정하거나,  업무를 항상 우선순위 기반으로 하는 것 등이다. 처음에는 시도했었으나 몇 번의 스프린트 후에는 적당히 스크럼을 적용하고 말았다. 프로젝트를 잘 관리하기 위해서는 많은 노력이 필요하다는 것을 알면서도 필요한 만큼의 노력을 기울이지 않은 것을 반성한다. 코딩을 포함한 회사에 많은 재미있을 것들에 우선순위를 두고 재미없음을 이유로 중요한 프로젝트의 관리를 뒤로 미루었다.4) 도구의 도입에서의 배움여러 가지 도구들을 도입했다. 모든 커뮤니케이션을 슬랙을 통하도록 여러 가지를 도입했다. 아마 우리 회사만큼 슬랙을 열심히 그리고 잘 쓰는 회사가 흔치 않을 것이라 생각한다.  컨플루언스를 도입해서 문서를 쓰는 문화를 만들어 갔다. 여전히 내가 제일 많은 문서를 쓰고, 대부분 내가 위키 가드닝(문서의 내용과 구조를 재조직하는 일)을 하고 있지만 사람들이 위키를 통해서 커뮤니케이션하는 것을 자연스럽게 생각하는 것을 보면 뿌듯하다. 트렐로도 도입해서 사용하고 있다. 최근까지는 엉성하게 쓰고 있었는 데 사용 가이드라인을 잡아서 한번 공유했으니, 앞으로 팀에 녹아들 것으로 기대한다.이렇게 도구를 도입하는 과정에서 변화를 이끌어 내는 방법을 연습했다. 사람들은 스스로 필요성을 느껴야 변화를 받아들인다. 탑다운식의 강압적인 도입은 결국 실패한다. 구성원들이 도구가 업무에 도움이 되는구나 라는 것을 느낄 때까지 선구자가 많은 노력을 기울여야 한다는 것을 알게 되었다. 사람들은 자신들이 필요한 정보를 컨플루언스에서 찾을 수 있을 때 자신도 정보를 컨플루언스에 남기기 시작했다. 자신들의 요청이 트렐로를 통해서 잘 처리된다는 것을 느꼈을 때 새로운 업무를 트렐로를 통해 전달해 주었다. 5) 개발에서의 배움초반에는 영역을 가리지 않고 개발을 했었다. 인프라 쪽도 정리하고 대출 프로세스도 개발하고 다른 금융업체와 연동도 하고 그리고 개발 환경도 갖추었다. 하지만 1년이 지난 지금 이미 내가 작성했던 코드는 절반 이상 다른 분들의 더 나은 코드로 대체되었다.타 금융권과 연계해서 개발을 하면서 이쪽 동네가 얼마나 기술 변화에 뒤쳐져 있는지를 알게 되었다. 취미로만 해봤던 웹 개발을 제품 레벨로 처음 해봤다. 프런트앤드 개발의 중요성과 어려움을 알게 되었다.개발팀의 효율을 올릴 수 있는 테스팅, 코드 리뷰, CI의 사용 등을 실제로 적용해 볼 수 있었다.마지막으로 회사에 좋은 분들을 모셔오면서 내가 얼마나 부족한 개발자인지를 알게 되었다.6) 금융업에서의 배움회사의 절반인 프로덕트를 만드는 사람들은 대부분 스타트업 출신이고, 나머지 절반은 금융권 출신으로 구성되어 있다. 금알못(금융을 알지 못하는 바보)으로 출발한 내가 이제 그들의 대화에 낄 수 있는 정도는 되었다. 하지만 여전히 하루가 멀다 하고 새로운 용어와 개념을 만나고, 대화가 끝나면 용어를 검색해보기 일쑤다.금융 동네는 어떤 경우에는 모든 것에 이유가 있어 딱딱 맞아떨어지는 것처럼 보이다가도 어떤 경우에는 도대체 이해가 안 되는 경우를 만나기도 한다. 여하튼 지난 일 년 동안 새로운 분야에서 일하면서 모르던 것(정확히는 모르는지도 몰랐던 것)들을  알아가는 즐거움을 느꼈다. 다음 회사를 가게 된다면 금융이 아닌 또 다른 분야에서 일하는 게 좋겠다는 생각이 들었다. 7) 채용에서의 배움입사했을 때 개발자 2명, 기획자 1명, 디자이너 1명이던 팀은 이제 개발자 9명에 기획자 2명, 디자이너 1명인 12명 팀이 되었다. 이 중 개발자 6명과 기획자 1명을 직접 채용했다. 이 과정에서 스타트업 채용의 어려움을 알게 되었고 조그만 노하우를 얻게 되었다. 그리고 채용에 따르는 책임이라는 것도 알게 되었다.채용 글을 쓰고 페이스북에 광고를 하고 구인 사이트에 올려보고 했지만 결국 대부분의 채용이 소개로 이루어졌다. 좋은 사람은 쉽게 다른 회사에 지원하지 않는다. 채용한 사람의 30배가 넘는 이력서를 받았고 5배가 넘는 면접을 보았다. 하지만 결국 소개를 받아 채용하는 것이 거의 유일한 방법인 것 같다. 회사에 대해 꾸준히 글을 써오고 있는데 이것이 채용에 많은 도움이 되었다.프로덕트팀 구성원은 내가 직접 채용을 결정하다 보니 이효진 대표에 의해서 내 인생이 바뀐 것처럼, 내가 채용한 사람들의 인생을 바꿨다. 그들이 자신들의 능력을 발휘해서 8퍼센트에 공헌할 수 있도록 하고 회사를 성공시켜서 그들의 노력에 답해 줄 수 있어야 한다는 생각을 한다. 8) 관리자로서의 배움 지난 회사에서 5명의 팀 리더를 할 때에는 내가 개발자인가 관리자인가라고 물으면 답하기가 쉽지 않았다. 하지만 지금 내게 묻는다면 나는 관리자라고 답하겠다. 나는 내 노력 50%를 들여서 전 구성원의 효율을 10% 더 올릴 수 있는 사람이 되어야 한다. 좋은 관리자였냐라고 하면 그렇지는 못했던 것 같다. 특히 구성원들에게 제때 필요한 피드백을 하지 못한 것은 아쉽다. 쓴소리를 해야 하는 위치에 있음에도 좋은 사람으로 남고 싶어서 적절한 때 적절한 피드백을 하지 못했다. 특히 같은 팀에 있는 디자이너와 기획자에게는 미안한 마음이다. 그들의 결과물에 대한 피드백도 쉽지 않았고, 커리어에 대해 해줄 수 있는 조언도 없었다. 그저 그들이 맡고 있는 좋은 프로덕트를 통해 성장해 나가길 바랄 뿐이다. 회사에서 1년 동안 "함께"라는 것을 기업 문화에 심기 위해 노력했다. 내가 시도했던 것들 중에 어떤 것들은 문화가 되어 정착이 되었고, 어떤 것들이 도태되어 사라졌다. 그 기준은 재미였다. 사람들에게 재미를 줄 수 있었던 슬랙의 #study 채널을 통해서 함께 공부하기, 브런치 매거진을 통해 함께 글쓰기, 2주에 한 번씩 오는 특별한 점심, 함께 하는 워크샵은 문화로 살아남았고 나머지는 사라졌다.  잃은 것은 무엇인가?1) 개발자로서의 경쟁력 개발자로서 경쟁력이 떨어지고 있다. 일반적으로 개발자가 망하는 과정을 다음과 같이 이야기한다.개발을 열심히 잘 하고 있음나이가 들면서 회사에서 관리자를 하라고 함관리자를 했더니 개발할 시간이 없어서 개발 실력이 떨어짐그 회사를 나오고 났더니 찾아 주는 곳이 없음치킨집내가 이런 과정으로 가고 있는 것은 아닐까? 에 대한 불안감이 있다. 전 회사에서는 새롭게 쏟아지는 기술들을 따라가며 공부를 해왔는데, 이제는 그런 공부 대신 당장 회사에 필요한 공부를 하게 된다. 이렇게 기술적인 경쟁력을 잃어 가게 되면 앞으로 먹고사는데 문제는 없을까?라는 생각도 들고, 당장 CTO라는 자리에서 옳은 결정들을 할 수 있을까 하는 생각 또한 든다.  2) 나와 가족체중을 얻었다. 운동할 시간이 없었기보다는 운동할 마음의 여유가 없었다. (둘 다 핑계이기는 매한가지다.) 체중이 늘어나다 보니 나 자신에 대한 자신감이 좀 떨어졌다. 가족들과는 입사 전에 비해 많은 시간을 보내지 못한다. 시간을 함께 보낼 때에도 핸드폰으로 슬랙을 확인하기 일쑤였다. 그리고 육체적/정신적으로 지친 상태라 100% 마음껏 놀아주지 못했다. 총평8퍼센트에 입사하기 전 일 년보다 훨씬 더 치열하게 살았다는 것만으로도 만족할 수 있는 1년이다. 내가 원하던 자리에서 원하던 경험을 할 수 있는 기회를 갖게 된 것만으로도 8퍼센트와 이효진 대표에게 감사한다. 자신 있게 추진하던 일 중 용두사미가 되어 버린 것들은 아쉽다. 하지만 용기 있게 많은 것들을 시도한 것은 잘했다. 내가 잘하는 것과 못하는 것이 여실히 드러난 1년이었다.   다음 1년은 무엇을 목표로 해야 할까?1) 회사를 성공시키자회사의 성장과 성공에 기대고 있는 것들이 너무나 많다. 지난 1년이 잽으로 탐색으로 해보는 1라운드였다면, 앞으로의 1년은 제대로 주먹을 뻗어보고 맞아보는 2라운드가 될 것으로 기대한다.  2) 그릇의 크기를 늘이자내 그릇의 크기에 따라 좋은 프로덕트, 구성원들의 성장, 채용이 좌우된다는 것을 알게 되었다. 그리고 입사 전보다 내가 갖춰야 할 역량들이 훨씬 명확해졌다. 꾸준히 갈고닦자.3) 더 멋지게 일하는 팀을 만들자 점점 손발이 맞아 간다. 더 많은 기회를 제공하고, 더 많은 것을 위임하자. 그리고 피드백을 잘하자. 이를 위해 끊임없이 실험하자.4) 손은 항상 더럽게지난 회사 CTO 님의 가장 큰 장점이 항상 손을 더럽게 유지하는 것이었다. 다시 말해 작더라도 일부 모듈을 직접 개발하고 다른 사람들의 코드들을 충분히 이해하셨다. 나 또한 다른 많은 일들이 있더라도 하루에 한 줄의 코딩은 할 수 있도록 하고, 다른 사람의 코드를 리뷰하는 데에도 시간을 쏟아야 하겠다.다시 맞이하는 1년회고를 통해 순식간에 지나간 지난 1년이 가볍지 않았다는 것을 알게 되었다. 다행이다. 이 글을 작성하면서 1년 전에 쓴  8퍼센트 입사 날을 읽어 보았다. 그날만큼은 아니지만 가슴이 두근거린다. 여전히 8퍼센트는 내게 모험이고 도전이다. 이제 새로운 마음으로 1년 1일 째를 맞이해야겠다. 지금 기분이라면 1년 뒤 더 멋진 회고글을 쓸 수 있을 것 같다.30번째쯤 스프린트의 데일리 미팅저와 함께 하고 싶은 개발자 분은 지원해 주세요! 기다리고 있습니다.#8퍼센트 #에잇퍼센트 #CTO #기업문화 #조직문화 #팀문화 #후기 #돌아보기 #개발자
조회수 1032

VCNC 개발팀 워크숍을 소개합니다. - VCNC Engineering Blog

VCNC 에서는 최근에 모빌리티 서비스 이동의 기본 타다를 출시했습니다. 신규 서비스를 준비하면서 팀도 새롭게 구성되고 새로운 멤버들이 팀에 합류했습니다. 이러한 변화 속에서도 좋은 개발 문화를 유지하기 위해서 VCNC 개발팀은 큰 노력을 하고 있습니다. 그중에서도 모두가 자랑하고 싶어 하는 VCNC 개발팀 워크숍을 소개합니다.VCNC 개발팀 워크숍최근 VCNC 개발팀 워크숍은 2018년 12월 19일 수요일에 진행되었습니다. 2016년 12월 처음 시작해서 최근까지 총 6번의 워크숍이 열렸습니다. VCNC 가 SOCAR에 인수되어 타다 서비스를 바쁘게 준비했던 2018년 8월을 제외하고 1년에 3번씩(4, 8, 12월) 꾸준히 개최되고 있습니다.VCNC 개발팀 워크숍은 개발팀 멤버들이 업무 외적으로 가지고 있던 각자의 관심사들을 공유하고 개발자들이 할 수 있는 고민을 같이 나눠보기 위한 욕구에 의해 처음 제안되었습니다. 포맷을 어떻게 할지 논의한 끝에 아래와 같은 포맷으로 워크숍을 진행하기로 했고 최근까지 이 포맷으로 워크숍을 진행하고 있습니다.오전 시간에는 모든 멤버가 각자의 관심사에 대해 5~10분 정도로 가벼운 라이트닝 톡을 하자.오후 시간에는 토의 주제를 정해서 몇 가지 깊은 토의를 나눠보자.회사의 업무에서 완전히 벗어나서 집중하기 위해 프로젝터 사용이 가능한 외부 카페를 대관하자.고기 회식을 하자!2018년 12월 제 6회 VCNC 개발팀 워크숍 단체 사진라이트닝 톡라이트닝 톡은 위에 언급했던 대로 모든 멤버가 5~10분 정도의 시간 동안 각자의 관심사에 대해서 다른 멤버들에게 소개하는 시간입니다. 발표 주제는 처음에는 개발로 한정 지었다가 더 폭넓게 관심사를 공유하기 위해 자유 주제로 변경했습니다. 다들 워크숍 전날까지는 어떤 발표를 해야 할지 걱정하며 투덜대지만, 막상 워크숍 당일이 되면 굉장히 흥미로운 주제들을 가지고 참여를 합니다. 라이트닝 톡이라는 의미에 맞게 1회 워크숍에서는 타이머를 켜고 시간 체크를 하면서 간단하게 발표를 했습니다. 그런데 기대했던 것보다 훨씬 좋은 발표들이 나오면서 발표 시간을 유동적으로 해서 발표의 퀄리티를 더 높이기로 했는데, 바로 다음 워크숍에 1시간 10분짜리 장대한 강의가 등장하는 바람에 절제의 중요성을 다시금 느끼면서 다시 타이머를 켜기로 했습니다…2017년 12월 워크숍에서는 PB팀이 상품 협찬을 해줘서 (PB팀 감사합니다!) 최고의 발표를 선정해 밀크 미니 인형을 지급했습니다. 영예의 수상자는 욕망의 흐름 이라는 발표를 정말 욕망의 흐름대로 발표한 Max로 선정되었습니다.<iframe src="https://docs.google.com/presentation/d/e/2PACX-1vQChBaARqlj8XfZx75MtkcejwupwBPt9tgD47sL99L1mHceYnPR2yDJnVAKFq8nFHXG9Pc9QbWBA5Eb/embed?start=false&loop=false&delayms=10000" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"> 지금까지 워크숍을 6회나 진행했기 때문에 상당한 양의 라이트닝 톡 발표자료들이 모였습니다. 그중에서 몇 가지 발표의 슬라이드를 공유합니다.Glitches of Mario by PrinceOrigami - 종이접기와 수학 by PrinceLattice-based Cryptography by BradTADA-Android 회고 by David기반 작업들을 무엇을 했는가? + RIB 간단 설명Contract by DoogieAd Fraud by HughBB84 - 양자 역학을 이용한 절대적으로 안전한 키 분배 프로토콜 by James불완전성 정리 by James삼단논법 by JamesGAN by MaxReinforcement Learning based on AlphaGo by NelsonSteganography by Nelson재귀의 폭풍 by TedUBER: COSTS & REVENUES by TerryProbabilistic Filter by Youngboom다음 워크숍부터는 발표를 녹화해서 슬라이드와 함께 공유해보도록 하겠습니다.최고의 발표로 선정된 Max종이접기로 각의 3등분선 구하기 실습필자의 발표를 경청하는 멤버들디스크의 위험성을 온몸으로 표현 중 심층 토의VCNC 개발팀 워크숍에서는 회사의 주요 결정사항 혹은 공통으로 관심이 있는 이슈들을 선정해서 모두의 의견을 듣고 공감대를 형성하거나 액션 플랜을 세우는 토의를 진행합니다. 토의의 주제는 발전적이고 열린 커뮤니케이션을 지향하는 멤버들의 특성상 회사 생활 과정에서 자연스럽게 형성됩니다. VCNC 에서는 평소에도 서로의 의견을 공유하는 자리를 자주 가집니다. 그 예로는 매 달 진행하는 매니저와의 1:1 개인 리뷰 제도, 각 팀별 주간 회고 회의, 제품 피쳐 개발 단위로 진행하는 회고 회의 등이 있습니다. 이러한 의견 공유 과정에서 멤버 각자가 생각하는 불만, 문제점, 희망 사항들이 자연스럽게 워크숍의 토의 주제로 발전됩니다. 토의는 특별한 절차 없이 모든 구성원이 자연스럽게 끼어들면서 자신의 의견을 펼치며 진행됩니다. 모두의 의견을 듣는 것이 중요하기 때문에 특별한 주제가 아니라면 적은 인원으로 조를 구성해서 토의한 뒤 의견을 취합합니다. 정리한 내용은 제품팀 및 HR 담당자에게 전달되며 그 후 우리가 해볼 수 있는 시도들을 하거나 새로운 회사의 정책들이 생겨나기도 합니다.둘러앉아서 토의에 집중하는 멤버들 (편안한 자세 가능)아래의 항목들은 실제로 진행했던 토의의 주제들입니다.순수 개발 관련점차 높아지는 개발 복잡성을 어떻게 해결할까?서버-클라 간 프로토콜 문서화 문제제품 개발 프로세스 관련제품 개발 프로세스를 스프린트에서 칸반으로 변경하고 지금까지 겪었던 느낀 점, 문제점 및 해결 방안은?이슈 관리가 잘 안 되는데 원인 및 해결책은?QA가 필요한가? 제품 품질을 높이기 위해선 무엇을 해야 하는가?회사의 문화, 복지 등 전반회사에서 팀 간 커뮤니케이션을 원활하게 하기 위해 Manager 제도가 도입되는데 Manager 는 어떠한 역할을 맡아야 하는가?Manager 제도의 후기 공유 및 개선 방향.어떠한 모습의 회사를 원하는가?필요한 사내 문화 및 복지는 무엇이 있을까?개인의 발전 관련언제 동기부여가 되는가? 저하되게 만드는 요인은?어떠한 사람과 같이 일을 하고 싶은가?어떠한 모니터링 및 피드백을 받고 싶은가?VCNC 개발팀 워크숍의 토의 결과로 회사의 많은 부분이 발전하고 있습니다. QA 팀이 생겼고 해외 및 국내 콘퍼런스 지원 관련 복지 정책이 새로 생겼습니다. 제품 개발 프로세스는 새로운 시도를 거치면서 지속해서 발전해 나가고 있습니다.그 외우걱우걱워크숍에는 풍족한 먹을거리가 함께합니다. 카페를 대관하는 경우에는 무제한으로 음료가 제공되며 점심시간에는 배달을 시켜서 먹으면서 함께 이야기를 나눕니다. 마무리로 저녁에는 고기를 먹고 싶은 만큼 맘껏 먹으면서 역시 이야기꽃을 피웁니다.미니게임워크숍의 포맷이 라이트닝 톡 + 심층 토의 조합으로만 진행되어 느껴지는 지루함을 탈피하기 위해 2018년 4월 워크숍에서는 2인 1조로 팀을 구성해서 미니게임을 진행했습니다. 개발자 감성에 걸맞게 스크래치 게임인 Lightbot 2로 1시간 정도 플레이를 했습니다. 승패가 있는 대결은 아니었지만 다들 피로감을 호소할 정도로 엄청나게 집중하면서 시간을 보냈습니다.워크숍의 핵심은 고기를 굽는 것점심에는 피자를 시켜 먹으며 자유로운 대화를 나눕니다.집중해서 Lightbot 을 플레이하는 플레이어휴식 중에도 즐거운 대화는 계속됩니다. 마치며VCNC 개발팀 워크숍은 앞으로도 계속됩니다. 앞으로도 좋은 회사의 문화를 소개하는 기회를 자주 만들도록 노력하겠습니다. 저희와 함께 VCNC 를 발전시킬 좋은 분들을 기다리고 있으니 많은 지원 바랍니다!
조회수 4688

자바스크립트 기초 문법 정리 Part 2 - 객체

지난 Part 1 포스팅에 이어 자바스크립트 기초 문법에 대해 정리해보았습니다. 이번 포스팅에서는 여러 객체와 그 객체에서 제공하는 각 메서드에 대해 정리하였습니다. 다루는 객체의 여러 메서드에 대해 정리하였기 때문에 전 포스팅처럼 간략하지는 않지만 이번 포스팅을 저장해 두고 자바스크립트로 개발하면서 필요할 때마다 참고하여 보기에는 좋을 것 같습니다. 다만, 메서드 사용 예의 코드는 넣지 않았으니 예제 부분이 필요하다면 필히 공식 문서를 참고해주세요. 익히는 것 자체도 공식 문서를 통하여 보는 것이 가장 좋지만 혹여 영어에 취약하신 분이라면 이 포스팅을 참고하는 것도 괜찮을 것 같습니다. :)내장 객체브라우저의 자바스크립트 엔진에 내장된 객체. String/Date/Array/Nath/RegExp Object 등이 있음.날짜 객체 DateDate 객체 생성new Date()new Date(milliseconds)new Date(dateString)new Date(year, month, day, hours, minutes, seconds, milliseconds)Date Get 메서드getDate() - 일 정보를 가져옴.getDay() - 요일 정보를 가져옴. 0(일요일)-6(토요일)getFullYear - 연도 정보를 가져옴. (yyyy)getHours() - 시간 정보를 가져옴.getMilliseconds() - 밀리초 정보를 가져옴. 0-999 (1/1000 초의 단위)getMinutes() - 분 정보를 가져옴.getMonth() - 월 정보를 가져옴. 현재 월에서 -1한 값으로 옴.getSeconds() - 초 정보를 가져옴.getTime() - 1970년 1월 1일부터 경과된 시간을 밀리초로 가져옴.Date Set 메서드setDate() - 일 정보를 설정.setFullYear() - 연도 정보를 설정. 원한다면 월과 일 정보도 설정할 수 있다.setHours() - 시간 정보를 설정.setMillseconds() - 밀리초 정보를 설정.setMinutes() - 분 정보를 설정.setSeconds() - 초 정보를 설정.setTime() - 1970년 1월 1일부터 경과된 시간을 밀리초로 설정.기타 Date 메서드now() - 1970년 1월 1일부터 지금까지의 밀리초를 반환.parse() - 날짜 형태의 문자열을 변환하여 1970년 1월 1일부터 입력한 날짜까지의 밀리초를 반환.toString() - Date 객체를 문자열로 변환.toJSON() - Date 객체를 JSON 데이터로 변환.valueOf() - Date 객체를 밀리초로 반환.숫자 객체 NumberNumber 생성var num = 1;      var num2 = new Number(1);Number 객체의 속성MAX_VALUE - 표현 가능한 가장 큰 수.MIN_VALUE - 표현 가능한 가장 작은 수.POSITIVE_INFINITY - 무한대 수 표기.NEGATIVE_INFINITY - 음의 무한대 수 표기.NaN - 숫자가 아닌 경우 표기.Number 객체 메서드toExponential(n) - 자수 표기법으로 소수점 n자리만큼 문자형 데이터로 반환.toFixed(n) - 소수점 n자리만큼 반올림하여 문자형 데이터로 반환.toPrecision(n) - 유효 숫자 n의 개수만큼 반올림하여 문자형 데이터로 반환.toString() - 숫자형 데이터를 문자형 데이터로 반환.valueOf() - 객체의 원래 값을 반환.parseInt(값) - 데이터를 정수로 변환하여 반환.parseFloat(값) - 데이터를 실수로 변환하여 반환.수학 객체 MathMath 메서드 및 상수Math.abs(숫자) - 숫자의 절댓값을 반환.Math.max(숫자1, 숫자2, 숫자3) - 숫자 중 최댓값을 반환.Math.min(숫자1, 숫자2, 숫자3) - 숫자 중 최솟값을 반환.Math.pow(숫자, 제곱값) - 숫자의 거듭제곱한 값을 반환.Math.random() - 0~1 사이의 난수를 반환.Math.round(숫자) - 소수점 첫째 자리에서 반올림하여 정수를 반환.Math.ceil(숫자) - 소수점 첫째 자리에서 무조건 올림에서 정수를 반환.Math.floor(숫자) - 소수점 첫째 자리에서 무조건 내림해서 정수를 반환.Math.sqrt(숫자) - 숫자의 제곱근 값을 반환.Math.PI - 원주율 상수를 반환.배열 객체 ArrayArray 생성var array = new Array();array[0] = 1;array[1] = 2;var array2 = new Array(1, "temp", true);var array3 = [1, true, "문자열도 가능"];Array 객체의 메서드 및 속성join(연결문자) - 배열 객체에 데이터를 연결 문자 기준으로 1개의 문자형 데이터로 반환.reverse() - 배열 객체에 데이터의 순서를 거꾸로 바꾼 후 반환.sort() - 배열 객체에 데이터를 오름차순으로 정렬.slice(index1, index2) - 배열 객체에 데이터 중 원하는 인덱스 구간만큼 잘라서 배열 객체로 가져옴.splice() - 배열 객체에 지정 데이터를 삭제하고 그 구간에 새 데이터를 삽입할 수 있음.concat() - 2개의 배열 객체를 하나로 결합.pop() - 배열에 저장된 데이터 중 마지막 인덱스에 저장된 데이터 삭제.push(new data) - 배열 객체에 마지막 인덱스에 새 데이터를 삽입.shift() - 배열 객체에 저장된 데이터 중 첫 번째 인덱스에 저장된 데이터를 삭제.unshift(new data) - 배열 객체의 가장 앞의 인덱스에 새 데이터를 삽입.length - 배열에 저장된 총 데이터의 개수를 반환.문자 객체 StringString 생성var str = "hello";      var str2 = new String("hi");String 객체 메서드 및 속성charAt(index) - 문자열에서 인덱스 번호에 해당하는 문자 반환.indexOf("찾을 문자") - 문자열에서 왼쪽부터 찾을 문자와 일치하는 문자를 찾아 최초로 일치하는 문자의 인덱스 번호를 반환. 찾는 문자가 없으면 -1 반환.lastIndexOf("찾을 문자") - indexOf와 동일하나 문자열의 오른쪽부터 찾음.match("찾을 문자") - indexOf와 동일하나 찾는 문자가 없으면 null을 반환.replace("바꿀 문자", "새 문자") - 문자열에서 왼쪽부터 바꿀 문자와 일치하는 문자를 찾아 최초로 찾은 문자를 새 문자로 치환.search("찾을 문자") - 문자열 왼쪽부터 찾을 문자와 일치하는 문자를 찾아 최초로 일치하는 인덱스 번호를 반환.slice(a, b) - a개의 문자를 자르고 b번째 이후에 문자를 자른 후 남은 문자를 반환.substring(a, b) - a 인덱스부터 b 인덱스 이전 구간의 문자를 반환.substr(a, 문자 개수) - 문자열에 a 인덱스부터 지정한 문자 개수만큼 문자열을 반환.split("문자") - 지정한 문자를 기준으로 문자 데이터를 나누어 배열에 저장하여 반환.toLowerCase() - 문자열에서 영문 대문자를 모두 소문자로 바꿈.toUpperCase() - 문자열에서 영문 소문자를 모두 대문자로 바꿈.length - 문자열에서 문자의 개수를 반환.concat("새로운 문자") - 문자열에 새로운 문자열을 결합.charCodeAt("찾을 문자") - 찾을 문자의 아스키 코드 값을 반환.fromCharCode(아스키 코드 값) - 아스키 코드 값에 해당하는 문자를 반환.trim() - 문자의 앞 또는 뒤에 공백 문자열을 삭제.브라우저 객체 모델(BOM)브라우저에 내장된 객체. window 객체브라우저 객체의 최상위 객체.window 객체 메서드open("url 경로", "창 이름", "옵션 설정") - 새 창을 열 때 사용.- open() 메서드 옵션 설정: width/height/left/top/location/status/scrollbars/tollbarsalert("메세지") - 경고 창을 띄움.prompt("질의 내용", "기본 답변") - 질의응답 창을 띄움.confirm("질의 내용") - 확인/취소 창을 띄움.- 확인 클릭시 true 반환, 취소 클릭시 false 반환.moveTo(x 위치값, y 위치값) - 창의 위치를 이동시킬 때 사용.resizeTo(너빗값, 높잇값) - 창의 크기를 변경시킬 때 사용.setInterval("스크립트 실행문", 시간 간격) - 일정 간격으로 반복하여 실행문을 실행시킬 때 사용.clearIntervar(참조 변수) - 참조 변수에 참조되어 있는 setInterval() 삭제.setTimeout("스크립트 실행문", 시간 간격) - 일정 간격으로 한 번만 실행문을 실행시킬 때 사용.clearTimeout(참조 변수) - 참조 변수에 참조되어 있던 setTimeout() 삭제.screen 객체사용자의 모니터 정보를 제공하는 객체.screen 객체 속성width/height/availWidth/availHeight/colorDepth(사용자 모니터가 표현 가능한 컬러 bit)location 객체사용자 브라우저의 주소 창에 url에 대한 정보와 새로 고침 기능을 제공하는 객체.location 객체 속성 및 메서드href - 주소 영역에 참조 주소를 설정하거나 URL 반환.hash - URL의 해시값을 반환.hostname - URL의 호스트 이름을 설정하거나 반환.host - URL의 호스트 이름과 포트 번호를 반환.port - URL의 포트 번호를 반환.protocol - URL의 프로토콜을 반환.search - URL의 쿼리를 반환.reload() - 새로 고침.history 객체사용자가 방문한 사이트 중 이전에 방문한 사이트와 다음 방문한 사이트로 다시 돌아갈 수 있는 속성과 메서드를 제공하는 객체.history 메서드 및 속성back() - 이전 방문한 페이지로 이동.forward() - 다음 방문한 페이지로 이동.go(이동 숫자) - 이동 숫자만큼의 페이지로 이동. 음의 값이면 이전 페이지로 이동.length - 방문 기록에 저장된 목록의 개수 반환.navigator 객체현재 방문자가 사용하는 브라우저 정보와 운영체제의 정보를 제공하는 객체.navigator 속성appCodeName - 방문자의 브라우저 코드명을 반환.appName - 방문자의 브라우저 이름 반환.appVersion - 방문자의 브라우저 버전 정보를 반환.language - 방문자의 브라우저 사용 언어를 반환.product - 방문자의 브라우저 사용 엔진 이름을 반환.platform - 방문자의 브라우저를 실행하는 운영체제를 반환.userAgent - 방문자의 브라우저와 운영체제의 종합 정보를 제공.문자 객체 모델(DOM)HTML 문서의 구조.선택자직접 선택자직접 문서에서 요소를 선택함. (id/class/폼 명/요소 명 등)document.getElementById("아이디 명") - 아이디를 이용해 요소를 선택.document.getElmentsByTagName("요소 명") - 요소의 이름을 이용해 요소를 선택.document.formName.inputName - 폼 요소에 name 속성을 이용해 요소를 선택.인접 관계 선택자직접 선택자를 사용해 선택해 온 문서 객체를 기준으로 가까이에 있는 요소를 선택함. (parentNode/childeNodes 등)parentNode - 선택한 요소의 부모 요소를 선택.childNodes - 선택한 요소의 모든 자식 요소를 선택. 선택한 모든 요소가 저장됨.firstChild - 선택한 요소의 첫 번째 자식 요소만 선택.previousSibling - 선택한 요소의 이전에 오는 형제 요소만 선택.nextSibling - 선택한 요소의 다음에 오는 형제 요소만 선택.문서 객체 이벤트 핸들러 적용하기onclick - 선택한 요소를 클릭했을 때 이벤트 발생.onmousevoer - 선택한 요소에 마우스를 올렸을 때 이벤트 발생.onmouseout - 선택한 요소에 마우스가 벗어났을 때 이벤트 발생.submit - 선택한 폼에 전송이 일어났을 떄 이벤트 발생.버튼document.getElementById("btn").onclick = function() {    alert("welcome");}일단은 참고하는 책을 기준으로하여 정리해보았는데 후에 시간이 될 때마다 공식 문서를 참고하여 번역한다는 생각으로 보다 세부적인 사항을 정리해도 좋을 것 같다는 생각이 드네요. 우선적으로는 빠르게 함수와 이벤트에 대해 배우고 객체에 대한 더 자세한 사항을 정리하도록 하겠습니다. 다음 포스팅은 자바스크립트의 함수와 이벤트에 대해 다룰 예정입니다!참고문헌:Do it! 자바스크립트+제이쿼리 입문 - 정인용JavaScript 튜토리얼 문서 (http://www.w3schools.com/js/default.asp)티스토리 블로그와 동시에 포스팅을 진행하고 있습니다.http://madeitwantit.tistory.com#트레바리 #개발자 #안드로이드 #앱개발 #Node.js #백엔드 #인사이트 #경험공유
조회수 2273

스포카 서버의 구조

안녕하세요. 스포카 개발팀에서 서버 관련 개발 업무를 담당하고 있는 문성원입니다. 오늘은 스포카 서버의 구조와 사용된 기술들에 대해서 함께 살펴보겠습니다.스택이란?먼저 스택(Stack)이란 용어에 대해서 함께 생각해보죠. 컴퓨터 과학을 공부하신 분들이라면 선입후출(FILO)이나 스택 오버플로우(Stack Overflow)등의 개념으로 익숙하실만한 용어기도 합니다. 그런데 서버 구조를 설명한다면서 왠 스택이냐구요? 다행히(?)도 지금부터 살펴 볼 스택은 솔루션 스택(Solution Stack)입니다. 스포카 서버라는 큰 솔루션이 원활히 동작하기 위해서 쓰이고 있는 각종 서브 시스템과 컴포넌트들의 묶음을 이야기하는 것으로 바꿔말하자면 이 글에서 다룰 기술 이야기는 모두 이 스택에 관한 이야기입니다.2011년 12월 현재 스포카 서버를 구성하고 있는 스택은 다음과 같습니다.DotcloudLinux 2.6.38.2nginx 0.8.53uwsgi 0.9.8.5Python 2.6.5Redis 2.2.2Celery 2.2.7Amazon Relational Database ServiceMySQL 5.5.12Amazon Simple Storage ServiceDotcloudDotcloud는 지금부터 설명드릴 스택을 묶어서 제공해주는 PaaS(Platform as a Service)의 일종입니다. Amazon Elastic Cloud Computing(Amazon EC2) 기반으로 동작하며 거기에 더해 손쉬운 확장과 배포가 장점입니다. 스포카 서버는 데이터베이스(Amazon RDS)와 업로드되는 데이터(Amazon S3) 이외의 모든 서비스를 Dotcloud를 통하여 제공하고 있습니다.nginx, uwsgi. 그리고 WSGI기본적으로 스포카 서버는 HTTP 형식의 요청을 받아 응답을 돌려주는 웹 어플리케이션입니다. 이러한 처리는 1차적으로 nginx를 통해 이뤄지는데, 이 중 서버사이드에서 처리가 필요한 경우에는 uwsgi라는 데몬이 이 처리를 담당합니다. (구버젼의 Apache Tomcat을 사용하시던 Java개발자분들은 Apache Tomcat과 Apache httpd와의 관계를 떠올리시면 편합니다.)이 경우 uwsgi는 일종의 어플리케이션 컨테이너(Application Container)로 동작하게 됩니다. 적재한 어플리케이션을 실행만 시켜주는 역할이죠. 이러한 uwsgi에 적재할 어플리케이션(스포카 서버)에는 일종의 규격이 존재하는데, 이걸 WSGI라고 합니다.(정확히는 WSGI에 의해 정의된 어플리케이션을 돌릴 수 있게 설계된 컨테이너가 uwsgi라고 봐야겠지만요.) WSGI는 Python표준(PEP-033)으로 HTTP를 통해 요청을 받아 응답하는 어플리케이션에 대한 명세로 이러한 명세를 만족시키는 클래스나 함수, (__call__을 통해 부를 수 있는)객체를 WSGI 어플리케이션이라고 합니다.정리하자면 스포카 서버는 WSGI에 맞게 작성된 프로그램을 nginx와 uwsgi를 통해 운용하여 요청을 처리하는 웹 어플리케이션이라고 할 수 있습니다.RedisRedis란 키-값(Key-Value) 저장 서버로 확장이 용이하며 속도가 우수합니다. 스포카 서버에선 이를 내부적인 임시 데이터 관리와 Celery의 작업(Task) 분배에 사용하고 있습니다.CeleryCelery는 Python으로 작성된 비동기 작업 큐(Asynchronous task queue/job queue)입니다. 앞서 소개한 작업(Task)를 브로커(Broker, 스포카 서버는 Redis를 사용)를 통해 전달하면 하나 이상의 워커(Worker)가 이를 처리하는 구조입니다. 포인트 적립-공유에 따른 분배처리, 포스팅 기능, 페이스북/트위터 공유등의 비동기 처리가 필요한 작업을 Celery에 위임하여 처리하고 있습니다.Amazon Relational Database Service대부분의 웹 어플리케이션과 마찬가지로 스포카 서버는 영속적으로 저장되어야하는 정보(회원 목록, 구매 내역)들을 디스크 기반의 데이터베이스(Database)에 저장합니다. Amazon Relational Database Service(Amazon RDS)는 Amazon EC2를 기반으로 그러한 데이터베이스를 간편하게 관리(모니터링, 백업, 접근제어)할 수 있게 도와주는 웹서비스입니다. Oracle과 MySQL을 지원하는데 스포카 서버는 그 중 MySQL을 사용하고 있습니다.Amazon Simple Storage ServiceAmazon Simple Storage Service(Amazon S3)는 Amazon RDS와 마찬가지로 Amazon EC2를 기반으로 한 데이터 저장 관리 서비스입니다. 스포카 서버에 업로드 되는 사진이나 문서등의 파일들을 통합하여 관리하여 서버의 인스턴스를 늘려 확장하는 경우에도 문제없이 대처할 수 있도록 하는 것이 주 목적입니다.#스포카 #스택 #개발 #개발자 #개발팀 #인사이트 #조언 #스킬스택 #스택설명
조회수 898

[Tech Blog] Keep Principles in Mind

원칙(Principle)은 중요합니다. “난 원칙대로 살지 않겠어!” 라고 외치고 싶더라도, 원칙이 있고 원칙을 충분히 이해하고 있지 않다면 그저 사춘기 소년/소녀의 이유 없는 반항 정도로 밖에 들리지 않을테니까요. 사실 대부분의 이런 경우 원칙 보다는 “규칙(Rule)대로 살지 않겠다”에 가깝지만, 여기에서는 그냥 넘어가도록 하죠. 소프트웨어 개발에도 다양한 원칙들이 존재합니다. 학부 수업에서 잠깐 들었거나 이런 저런 글들을 읽다가 접해 봤을 이런 원칙들은 실제 서비스를 만들면서 바쁘게 기능을 추가하고 버그를 수정 하느라 어느새 기억 속에서 잊혀지곤 하죠. 정신없이 기능을 구현하다가 문득 코드를 돌아봤을 때 ‘이게 왜 여기에 있지’ 라는 의문이 든다면 한 번쯤 원칙을 되새겨 보라는 신호가 아닐까요? 이 글에서는 Clean Architecture 와 Clean Code 등의 저자로 유명한 Uncle Bob(Robert C. Martin)이 얘기하는 S.O.L.I.D Principles 에 대해 얘기해 보려고 합니다. SOLID 원칙은 밥 아저씨가 2000년도 자신의 논문 Design Principle and Design Patterns 에서 OOD(Object-Oriented Design)를 위해서 제안한 5가지 원칙의 앞 글자만 떼서 붙여졌습니다. Object-Oriented Design 을 대상으로 제안된 원칙이지만 Agile 개발 등의 개발 방법론 핵심 철학에도 적용될 수 있는 개념들 입니다. S.O.L.I.D Principles Single Responsibility Principle Class 는 오직 한 가지의 책임이 주어져야 하고, 오직 한 가지 이유에서만 변경되어야 합니다. 보고서를 편집하고 출력하는 모듈에 대해서 생각해 볼까요. 해당 모듈은 두 가지의 이유로 변경될 가능성이 있습니다. 보고서의 내용이 바뀌었을 때도 변경되어야 하고, 보고서의 형식이 바뀌었을 때도 변경되어야 합니다. 편집 과정 때문에 모듈을 변경하다 보면 해당 변경 사항이 출력 부분에도 영향을 미칠 가능성이 상당히 높습니다. 이 경우 내용을 편집하는 모듈(i.e 내용을 담당하는 모듈)과 출력하는 모듈(i.e 형식을 담당하는 모듈) 두 가지로 나뉘어야 합니다. “할 수 있다고 해서 해야 한다는 뜻은 아닙니다.” Open / Closed Principle Class, Module, Function 등의 소프트웨어 구성 요소는 확장(extension)에 대해 열려 있어야 하며, 변경(modification)에 대해 닫혀 있어야 합니다. 어떤 모듈이 Data Structure 에 필드를 추가하거나 함수를 추가하는 등 확장이 가능하다면 그 모듈은 확장에 대해 열려 있다고 표현합니다. 반면에 어떤 모듈이 수정 없이 다른 모듈에 의해 사용될 수 있다면 그 모듈은 닫혀 있다고 표현합니다.  public class CreditCard {     private int cardType;       public int getCardType() { return cardType; }       public void setCardType(int cardType) { this.cardType = cardType; }          public double getDiscount(double monthlyCost){          if (cardType == 1) {              return monthlyCost * 0.02;          } else {              return monthlyCost * 0.01;          }     } }  위 CreditCard class 에 새로운 카드 타입을 추가하려고 하면 getDiscount 함수를 변경할 수 밖에 없습니다. 이 경우 Open/Closed Principle 을 위반된다고 볼 수 있습니다. “코트를 입기 위해서 개복 수술을 할 필요는 없으니까요.” Liskov Substitution Principle 프로그램 상의 Object 들은 프로그램의 정확성을 해치지 않으면서 하위 타입의 Instance 로 변경 가능해야 합니다. 하위 타입 함수 인자의 반공변성(Contravariance), 하위 타입 함수 반환 타입의 공변성(Covariance), 상위 타입의 예외를 상속하지 않는 추가적인 예외 발생 금지 등의 요구 사항이 있습니다. OOP 에서 상속 개념을 배울 때 이해를 돕기 위해 주어진 몇 가지 예시들이 있었을텐데, 우습게도 우리가 생각하기에 타당한 상속에 관한 예시들 중 의외로 원칙을 위배하는 경우가 많습니다. Liskov Substitution Principle 을 위반하는 대표적인 예시는 정사각형과 직사각형입니다. 정사각형은 직사각형의 일종이니 Square가 Rectangle을 상속받는 것이 충분이 타당한 것으로 보입니다. 정말 그럴까요? Rectangle 의 넓이를 구하는 함수의 테스트를 구성해 봅시다.  Rectangle rect = new Rectangle(); rect.setWidth(10); rect.setHeight(20); assertEquals(200, rect.getArea());  여기에 new Rectangle() 대신에 new Square()가 rect 에 할당되면 어떻게 될까요? 넓이는 400 을 반환하기 때문에 테스트는 실패하겠죠. 정사각형이 직사각형을 상속 받으면 Liskov Subsitution Principle 을 위반한다고 볼 수 있습니다. 상속은 문제를 해결하는데 있어서 상당히 유혹적인 방법입니다. 하지만 상당히 많은 경우에 상속을 오용할 가능성이 높습니다. “오리처럼 생기고 오리처럼 꽥꽥 거리더라도, 배터리가 필요하다면 오리가 아닙니다.” Interface Segregation Principle 많은 것을 아우르고 일반적으로 사용 가능한 하나의 interface 보다 특정 클라이언트를 위한 여러 개의 interface 가 낫습니다. Xerox는 Stapling(프린터기가!?), Fax 등의 다양한 기능이 포함된 신규 프린터 소프트웨어를 개발 도중, 더이상 개발이 불가능할 정도로 프로그램이 번잡 해졌다는 것을 인정하고 밥 아저씨에게 도움을 요청합니다. 문제는 Job Class 하나가 모든 기능을 다 구현하고 있다는데 있었습니다. 이 비대한 Class 는 Client 입장에서 사용되지도 않을 모든 함수를 알 수 있게 구성 되어 있었죠. 이 문제에 대해 밥 아저씨는 Interface Segregation Principle 을 적용하여 각 Client 입장에서 사용해야 하는 함수 만을 가지고 있는 각 interface 들을 따로 만들었습니다. 그리고는 다음에 나올 Principle 인 Dependency Inversion Principle 을 통해서 해당 기능을 구현하게 함으로써 문제를 해결했습니다. Dependency Inversion Principle “추상화에 의존해야지, 구체화에 의존하면 안됩니다.” 상위 계층의 모듈은 하위 계층의 구현이 아니라 추상화에 의존해야 합니다. 상위 계층이 하위 계층의 구현에 의존하던 전통적인 의존 관계를 역전 시킴으로써 상위 계층이 하위 계층의 구현으로부터 독립되게 할 수 있습니다. 예를 들어 Dependency Injection 은 이 원칙을 따르는 방법 중 하나 입니다. Conclusion 세상에 나쁜 프로그램은 있습니다. 당장 눈에 보이는 기능이 똑같다고 같은 프로그램인 것은 아닙니다. 생각보다 많은 코드들이 ‘그 곳에 넣을 수 있기 때문에’, ‘그 곳에 넣어도 돌아가기 때문에’ 깊은 고민 없이 그 곳에 정착합니다. 당장 좀 더 빠르게 기능을 추가해서 주변 사람들의 박수를 받을 수도 있습니다. 허나 이것들이 쌓이면 더이상 손댈 수 없는 코드가 되고, 문제를 느끼고는 Refactoring을 하자고 다짐하고, 모두 엎은 다음 또 다시 같은 코드를 만들게 되겠죠. 쉬운 코드가 가장 만들기 어려운 코드이고, 그런 좋은 코드는 좋은 원칙으로 부터 나옵니다. 변화에 적응할 수 있는 프로그램, 의도가 쉽게 읽히는 프로그램, 문제 발생 가능성이 적은 프로그램, 쉽게 확장할 수 있는 프로그램 등 좋은 프로그램을 만드는 것은 우리가 실제로 목표하는 것을 달성하기 위해서 정말 중요합니다. 이는 그저 경험이나, Tweak 만으로 이루어지지 않습니다. 다양한 신규 기술들과 Framework 들을 두루 섭렵하면서 활동 반경을 넓히고 경험을 쌓았다면, 가끔은 잠시 서서 원칙에 대해 되돌아 보는 것은 어떨까요?   *버즈빌에서 활기찬 개발자를 채용 중입니다. (전문연구요원 포함)작가소개 Whale, Chief Architect “Keep calm and dream on.”

기업문화 엿볼 때, 더팀스

로그인

/