스토리 홈

인터뷰

피드

뉴스

조회수 1522

우리는 비정상인걸까?

필자는 스팀헌트라는 스팀 블록체인 기반 댑 프로젝트를 진행하고 있다. 스타트업을 하면서 저마다의 관점과 철학이 다른 문제이겠으나, 내가 지금까지 약 1년간 경험해본 이놈의 "블록체인"이라는 업계는 뭔가 정상적이지 않다. 그간 나름 "스타트업"이라는 업계 전반의 경험에 비추어 봤을때 이바닥 관행들이 뭐가 내게는 비정상적으로 보이는지 간략히 살펴보면 다음과 같다.1.대부분의 "블록체인" 태그를 달고 나오는 프로젝트들은 가장 처음 하는 일이 펀딩이다. 아직 제품은 커녕 그냥 프로젝트 소개하는 랜딩페이지에 수십명의 팀원, 어드바이저 리스트, 현실성이 있을까 싶은 각종 기업 로고들이 파트너사로 나열되어 있다.2.그들에게 "제품"이란 마치 수십 수백페이지의 엄청난 공을 들인 "화이트페이퍼"인듯 하다. 왜냐하면 위에서 얘기한 랜딩페이지 맨 위에 항상 가장 대문짝 만한 자리를 차지하고, 이미 3개국어는 기본, 5개국어 버전까지 준비해 놨기 때문이다.3.이런 제품도 없고 요상한 랜딩페이지만 있는 프로젝트들이 수십, 수백억의 ICO, IEO, 프라이빗 세일 등등의 단어로 치장된 "토큰 세일"을 진행한다. 이들이 초기에 들이는 자원중 99% 이상은 카톡방 관리, 텔레그램방 관리, 코인판 (사이트 이름이다) 마케팅, 각종 밋업, 컨퍼런스 참여, 유투버들 마케팅 등등이다. 물론 이런 행동들은 성공적인 펀딩을 위해 필요한 일들이긴 하다. 다만, 일반적인 스타트업이라면 초기에 99%의 자원이 제품과 유저들에게 쏟아야 마땅한 단계에 그게 아니라는게 내겐 비정상적인걸로 보일 뿐.4.아직 제품도 없는 팀이 팀원 리스트를 꾸린걸 보면 거의 중견급 스타트업 레벨이다. 아직 유저도 없고 비즈니스도 없는 팀이 CEO, CTO, CMO, CSO, C.... 레벨이 5명은 기본, 개발자 5-6명을 리스트에 박아놓는다. 일반적인 스타트업에서는 MVP가 어느정도 검증되고 나서 스케일을 낼때 하는 일들이다. 마치 삽도 뜨기 전에 삽질할 사람들 수십명을 모아놓은 그림이다. 이 중 십중팔구는 삽을 뜨려고 보니 땅바닥이 콘크리트 바닥이라 팔 수가 없거나, 애초에 팔 의지도 없었던게 대부분이지만...5.어드바이저 리스트... 내가 가장 요상하게 여기던 관행인데, 어느 프로젝트를 들어가도 이력이 화려해 보이는 어드바이저들 5명 이상은 기본으로 갖고 들어가더라. 내가 맨 처음 이바닥 들어갈때는 나름 "뭐, 아무도 가본 길이 아니니 조언해줄 사람들이 많이 필요할수도 있겠지.."라고 착각했었다. 알고보니, 그들은 그저 위에 자리를 채워주는 역할과 아주 약간의 투자자+거래소 인맥을 소개시켜주는 역할을 하는 사람들이더라. 이렇게 이름만 팔아주고 대부분 총 발행량의 0.5 ~ 2, 3%까지 토큰을 받아가는데, 대부분 상장과 함께 가장 먼저 덤핑될 토큰들이라는게 업계의 공통된 시각이다. 사실, 이 바닥이 그리 넓지 않아서 거래소 인맥 소개시켜주는건 인맥이 넓으신 1-2명으로도 충분히 커버 가능하다. 아예 제대로된 엑셀러레이터 들어가면 그들이 백배는 더 전문적으로 잘 해주는 영역이기도 하다. 아무리 생각해도 삽도 안떠본 스타트업이 저 많은 어드바이저 리스트를 꾸려야 할 이유를 지금도 못찾았고, 앞으로도 모를것 같다.6.지금이야 STO니 해서 증권형 토큰들이 하나둘씩 나오지만, ICO하는 대부분의 코인들은 본인들이 "유틸리티" 코인이라고 주장한다. 뭐, 토큰 모델 디자인상 유틸리티 토큰일 수 있다. 그런데 문제는, 이를 배포할 때 초기 토큰 홀더들은 100% "투자자"라는데에 있다. 그들이 주장하는 토큰의 유틸리티, 유저 페르소나와 1도 관계 없는 사람들이 대부분 토큰을 갖게 되고, 시장 상장 후 차익 실현을 위해 보유하는 경우가 거의 백프로다. 마치 사탕 사먹으라고 발행한 백원짜리 동전을 손에 쥔 백명의 사람들이 사실 사탕 사먹으려는게 아니고 모두 이백원, 삼백원에 팔기위해 손에 쥐고 있는것과 같은 논리다. 이러니, "유틸리티" 토큰이라는게 작동할리가 없다.7.백서... 어드바이저와 함께 내가 가장 요상하게 여기는거다. 대부분의 프로젝트가 삽도 뜨기 전에 수십, 수백장짜리의 백서부터 쓴다. 읽어보면 완전 세상을 바꿀 의지가 넘쳐 흐르는 철학적 도입부 + 본인들의 기술이 세상에 없던, 혹은 현존하는 기술은 거의 쓰레기 수준이라는 설명 + 삽도 떠본적 없는데 3-5개년 중장기 계획이 세워져 있고, 3년후에는 이미 이 시장을 평정해 있는 이야기들로 점철되어 있다. 제품도 없고 유저도 없는 상태에서 쓰여지는 수십페이지짜리 백서라는건, 그냥 대학교에서 팀플 리포트 A학점정도 맞을 만큼 잘 써진 그냥 소설 페이퍼정도인데, 이걸 무슨 신주단지마냥 만들어서 돌리는지 도무지 이해할수가 없다.8.투자자 생태계가 진짜 엄청나게 요상하게 꾸려져 있다. 일반적인 스타트업에서 보통 시드펀딩을 위해 VC들을 만나보면, 그들은 이 제품이 진짜 어떤 문제를 해결중인건지, 그 문제 해결에 열광하는 유저들이 얼마나 존재하는지, 이게 스케일이 가능한 형태인지, 스케일 했을때 시장규모가 얼마나 될건지, 이놈들이 그중 얼마나 먹을 수 있는 팀원들인지... 보통 이런걸 본다. 이런걸 봐야 나중에 스케일에 성공해서 엑싯이 되든 상장이 되든 해서 투자 수익을 얻을 수 있기 때문이다. 한편, 이바닥 투자자들이 가장 중요시 여기는 것들을 나열해 보면 다음과 같다.1) 백서가 얼마나 있어빌리티하게 작성되어 있는지 (본인들이 잘 모르는 개념들이 잔뜩 들어가 있을수록 높은 점수를 받는다)2) 흥행성 - 이 프로젝트가 얼마나 "호재"를 잘 타서 토큰 가격 펌핑이 가능한 구조인건지. 파트너사들, 각종 MOU, 화려한 이력이 있는 팀, 어드바이저 등등이 보통 활용된다.3) 토큰 분배 - 프라이빗 세일에서 디스카운트 먹은 투자자들 규모가 얼마나 되는지, 팀/어드바이저들은 얼마를 던질 준비가 되어 있는지4) 토큰 상장 - 소위 "대형" 거래소에 처음부터 상장될건지, 얼마나 많은 거래소에서 유통될건지...이 어디에도 "제품"이나 "유저"와 관련된 내용은 하나도 없다. 즉, 투자자들이 진짜 그들 제품의 성공 가능성에 대해 점쳐보며 투자할 분위기도, 그럴 생태계도 아닌게 이 판이다.9.원래 비트코인도, 이더리움도, 이런 탈중앙화 퍼블릭 블록체인 프로젝트의 강점은 오픈소스 프로젝트라는데에 있다. 모든 소스코드가 깃헙에 투명하게 공개되어 있고, 누구나 개발에 기여할 수 있다. 그런데, 이 후에 쏟아진 수 많은 블록체인 프로젝트들이 개발이 이루어지지 않거나, 본인들 소스코드는 비공개라고 하는 경우가 허다하다. 심지어 깃헙 링크가 아예 없는 프로젝트도 수두룩 하다.10.글로벌 프로젝트라는데 물론 아직 "글로벌" 유저도 없고, 레딧이나 트위터 등의 활동도 전무하고, 공식 커뮤니케이션 채널은 카카오톡 오픈챗이나 텔레그램 채널이란다. 가끔 싱가포르나 어디 글로벌 컨퍼런스에서 머리 노란 사람들과 사진 몇방 찍고 이걸 블로그나 신문기사로 찍어내면 글로벌 프로젝트가 되는 분위기다.이렇게 요상한 관행들이 어떤 결과를 가져왔는지 한번 살펴보자. 뭐, 가격 폭락하고 거품 빠지고... 이딴걸 얘기하려는게 아니다. 일반적인 스타트업 업계에 비해 이바닥의 현 성적표가 얼마나 초라한지를 보는거다.1. 전체 ICO의 78% 이상은 스캠으로 판명, 7%는 실패하거나 프로젝트가 사멸하였다 (블룸버그).2. 가장 큰 네트워크 규모를 자랑하는 이더리움 블록체인에서 돌아가는 1,375개의 댑 (DApp - 블록체인에서 돌아가는 앱을 뜻하는 단어)들 중 86%는 유저가 단 한명도 없으며, 93%는 아예 온 체인 트랜잭션이 단 한 건도 발생하지 않은 댑이다 (크립토글로브).3. 이더리움 지갑 보유자 전체의 고작 2%만이 이더리움 댑을 사용하는 유저이다 (dapp.com)4. CoinGecko에 리스팅 되어 있는 전체 4,139개의 프로젝트 중 과거 30일 동안 단 한번이라도 개발 커밋이 이루어진 프로젝트는 단 64개 밖에 없다 (2019년 2월 28일 기준).이걸 스타트업 상황에 비교해서 설명해보면 이렇다.전체 스타트업 중 78%는 사기를 쳤고, 7%는 삽도 못떠보고 망했다. 86%는 유저를 1명도 못만들었고, 93%는 유저는 있는데 유저들의 사용 이력이 1도 없다. 특정 운영체제를 쓰는 스마트폰 보유자들의 고작 2%만이 실제 앱 스토어에서 앱을 다운받아 사용하는 유저이다. 전체 스타트업 중 고작 1.5%만이 과거 30일동안 단 한번이라도 개발 커밋이 이루어졌다. 정말 요상하지 않는가? 그런데 더 충격적인건... 이걸 요상하게 여기는 우리 팀이 더 비정상이라고 보는 이 업계 시각이다. 내가 하는 스팀헌트라는 프로젝트에 대해서는 다음 글에서 상세히 소개할 예정이지만, 우리는 처음에 제품부터 만들어서 유저를 모으고, 가설을 검증하고, 사업모델을 모색하고... 그 다음 펀딩을 추진하는, 지금까지 스타트업에서 있었던 아주 일반적인 트리를 타고 있었다.백서? 물론 없었다. 제품 운영도 안해보고 저런 소설을 내 스스로 쓰는거에 대한 오글거림도 있었고, 솔직히 수만명의 커뮤니티 유저들을 상대하다 보면 그런짓에 시간을 쓸 여유도 없었다.웹사이트에는 그냥 이렇게 끄적여 놨었다...ㅎㅎ그런데, 우리는 아주 일반적인 단계라고 여기며 요즘 펀딩을 준비하고 있는데, 거의 모든 관계자들이 그놈의 "백서"를 요구한다. 제품부터 열어봅시다, 유저부터 한번 봅시다 하고 말꺼내는 사람들이 거짓말 안보태고 10에 1명 찾아볼까 말까였다. 우리도 얼마전까지는 "우린 그런 소설책 쓸 시간이 없어요~~" 이랬었는데... 결국 우리도 백기를 들고 일주일만에 백서를 써버렸다. 근데 사실 써보고 나니, 우린 제품도 1년이나 운영하면서 나름 가설 검증을 많이 해 놓은 단계라 그런지 백서가 쉽게 써지긴 하더라. 로드맵도 3-5년 후 이야기는 있지도 않다. 1년 앞에 어떻게 될지 모르는게 일반적인데 굳이 3-5년후를 쓸 가치를 못느낀다.사실, 위에서 소개한 뭔가 이 바닥에서는 "비정상"처럼 여겨지는 일반적인 스타트업들이 타는 트리를 타고 있는 블록체인 프로젝트들이, 스팀헌트가 만들어진 스팀 블록체인에는 수두룩하게 많다. 아니, 스팀에서는 오히려 위에서처럼 백서만 들고와서 펀딩하는 프로젝트들을 더 까는 경향이 있다.스팀이 코인의 시총만 따지면 40-50위권 수준이라 유명새를 타지 못한 상태이지만, 그 블록체인을 기반으로 움직이는 60여개의 댑들은 이미 실제 유저들을 어마어마하게 거느리고, 이더리움이나 EOS마냥 메타마스크나 스캐터를 깔지 않으면 로그인조차 할 수 없는 상태가 아닌, 일반적인 앱을 쓰는것과 동일한 UX에 모바일에서도 100%로 돌아간다. 코인판의 수 많은 사람들이 거래소에서 pump and dump에만 열을 올리고 있는 사이 스팀에서는 실제 소셜 앱들을 만들기 위한 스타트업 다운 스타트업 생태계가 만들어지고 있던 거다.출처 - https://stateofthedapps.com (2019년 1월 7일 기준)https://stateofthedapps.com라고, 이더리움, EOS등 2,500개 이상의 댑들의 유저수, 트랜젝션을 기반으로 순위를 매기는 공신력 있는 사이트가 있다 (무슨 돈만내면 별점 매겨주는 ICO레이팅 그딴 사이트가 아니다). 거기 차트에 들어가보면 이미 스팀기반 댑들이 상위권을 차지하고 있다. 스팀헌트도 항상 상위 10-20위사이에서 왔다갔다 하면서 최상위권을 유지중이다. 또한, 대부분이 도박, 게임등인 이더리움/EOS와는 달리 스팀기반 댑들은 소셜 서비스라는게 엣지이다. 스팀헌트 역시 테크 얼리어답터들의 "커뮤니티" 플랫폼이다.오늘을 기점으로 다시 브런치 활동을 시작하려고 한다. 내가 직전에 연재하던 시리즈가 "기획돌이의 스타트업 고군분투기"였는데, 이건 일반적인 스타트업에서 좌충우돌하던 깨달음에 대한 글들이였다면, 오늘부터 연재할 글들은 이 "비정상"이 "정상"처럼 여겨지는 블록체인판에서 내가 스팀헌트 프로젝트를 운영하면서 겪게되는 좌충우돌에 대한 이야기들을 소개할 예정이니, 많은 관심과 구독 부탁드린다.글쓴이는 스팀헌트 (Steemhunt) 라는 스팀 블록체인 기반 제품 큐레이션 플랫폼의 Co-founder 및 디자이너 입니다. 비즈니스를 전공하고 대기업에서 기획자로 일하다가 스타트업을 창업하고 본업을 디자이너로 전향하게 되는 과정에서 경험한 다양한 고군분투기를 연재하고 있습니다.현재 운영중인 스팀헌트 (Steemhunt)는 전 세계 2,500개가 넘는 블록체인 기반 앱들 중에서 Top 10에 들어갈 정도로 전 세계 150개국 이상의 많은 유저들을 보유한 글로벌 디앱 (DApp - Decentralised Application) 입니다 (출처 - https://www.stateofthedapps.com/rankings).스팀헌트 웹사이트 바로가기
조회수 2056

AWS 서비스를 활용한 Kubernetes 클러스터 구축 - VCNC Engineering Blog

Kubernetes 클러스터를 상용 환경에서 운영하기 위해서는 몇 가지 추가 구성요소를 설치해야 합니다. 예를 들어 Ingress를 만들더라도 실제로 트래픽을 받아줄 Ingress Controller를 설치해두지 않았으면 소용이 없습니다. 그리고 모니터링을 위해 컨테이너의 로그나 CPU/메모리 사용량 등을 수집, 조회할 수 있는 서비스도 필요합니다.다행히 이러한 추가 구성요소 또한 Kubernetes 클러스터 위에서 일반 애플리케이션과 거의 같은 방식으로 작동하므로 설치하는 것이 어렵지는 않습니다. 다만 클러스터를 원하는 대로 구성할 수 있는 만큼 선택의 폭이 넓어서 여러 가지 해법을 놓고 고민하게 될 수 있습니다. 이 글에서는 타다 서비스를 위해 Kubernetes 클러스터를 구성할 때 어떤 선택을 했는지, 특히 AWS 환경에서는 어떤 서비스들을 활용할 수 있는지 공유합니다.서비스를 외부에 노출: NGINX Ingress Controller + NLBIngress Controller 고르기Kubernetes에서 클러스터 내부 서비스를 외부에 HTTP(S)로 노출할 때는 Ingress를 사용할 수 있습니다. TLS 암호화, 로드밸런싱, 호스트명/경로 기반 라우팅 등을 제공해서 상당히 편리한데, Ingress가 실제로 작동하기 위해서는 Ingress Controller가 필요합니다.시중에는 다양한 종류의 Ingress Controller 솔루션이 나와 있습니다. 그중 Kubernetes 프로젝트에서 공식 지원하는 NGINX Ingress Controller와 AWS ALB 로드밸런서를 이용하는 AWS ALB Ingress Controller를 두고 고민을 했습니다.타다에서는 클라이언트(모바일 앱)에 실시간 이벤트를 전달하기 위해 gRPC를 사용하고 있어서 gRPC를 지원하지 않는 ALB는 선택할 수 없었습니다. 그리고 AWS ALB Ingress Controller는 현재 Ingress 하나마다 ALB를 1개 생성하는 구조여서 앞으로 노출할 서비스 수가 늘어난다면 비용 효율이 떨어진다고 판단했습니다. 따라서 NGINX Ingress Controller를 선택하게 되었습니다.NGINX Ingress Controller는 NGINX 웹서버를 기반으로 하므로 gRPC 모듈을 비롯하여 다양한 NGINX 모듈을 통해 굉장히 세세한 부분까지 설정할 수 있습니다. NGINX Ingress Controller는 Ingress나 Ingress가 가리키는 서비스의 엔드포인트에 변화가 생길 때마다 동적으로 NGINX 설정을 업데이트하는 방식으로 동작합니다.NGINX Ingress Controller 로드밸런싱NGINX Ingress Controller를 사용해도 외부에서 오는 트래픽을 적절히 분배해 줄 외부 로드밸런서는 필요합니다. AWS의 로드밸런서는 Classic ELB, ALB, NLB가 있습니다. 앞서 설명했듯이 ALB는 gRPC를 지원하지 않아서 Classic ELB를 TCP 모드로 사용하거나 NLB를 사용해야 합니다. Classic ELB는 동시에 많은 연결을 처리하려면 웜 업이 필요한 단점이 있어 NLB를 사용하기로 하였습니다.최근 NLB가 TLS termination을 지원하기 시작했지만, HTTP/2와 gRPC를 사용하기 위해 필요한 ALPN 정보를 설정할 수 없어서 NGINX 수준에서 TLS 암호화를 처리하고 있습니다. NLB 수준에서 TLS 처리를 하면 무료로 자동 갱신되는 ACM 인증서를 사용할 수 있는 등 여러 가지 이점이 있어서 아쉽습니다.Kubernetes에서 LoadBalancer 타입의 서비스를 생성하면 알아서 AWS 로드밸런서를 만들어줍니다. 하지만 이렇게 해서 NLB를 생성하는 방식은 아직 알파 기능입니다. 따라서 먼저 NodePort 타입의 서비스를 생성하여 모든 노드의 특정 포트에 NGINX를 노출한 다음, 별도로 생성한 NLB에 노드들이 속한 오토스케일링 그룹을 연결해주는 방식으로 직접 설정하게 되었습니다.정리해보면 외부에서 오는 트래픽을 처리할 때는 다음과 같은 과정을 거칩니다.모든 서브도메인(*.tadatada.com)은 NLB를 가리킵니다.NLB의 443 포트로 암호화된 HTTP 또는 gRPC 요청이 들어옵니다. NLB는 적절한 Kubernetes 노드 중 하나의 특정 포트(예: 30000번)로 요청을 전달합니다.Kubernetes 노드에서는 포트 번호를 보고 NGINX 서비스로 향하는 요청임을 알 수 있고 NGINX 컨테이너 중 하나로 요청을 전달합니다.NGINX는 복호화를 한 다음 HTTP Host 헤더를 확인하여 요청을 전달할 Ingress를 알아냅니다. 그리고 해당 Ingress의 엔드포인트 중 하나로 복호화한 요청을 프록시합니다.애플리케이션 컨테이너가 요청을 처리합니다.트래픽 흐름: NLB → NodePort → NGINX Ingress Controller → 내부 서비스Pod에 IAM 역할 부여: kube2iamS3, SQS 등 IAM으로 인증하는 AWS 서비스에 접근하려면 인증 정보가 필요합니다. EC2에서는 액세스 키를 직접 넣는 대신 EC2 인스턴스 프로파일로 인스턴스에 IAM 역할을 부여할 수 있습니다. 하지만 하나의 Kubernetes 노드 (=EC2 인스턴스)에는 여러 Pod이 실행될 수 있기 때문에 Pod마다 다른 IAM 역할을 부여하기를 원한다면 인스턴스 프로파일을 활용할 수 없게 됩니다. (인스턴스 프로파일에는 하나의 IAM 역할만 부여 가능)kube2iam을 사용하면 다음과 같이 Pod 어노테이션으로 IAM 역할을 지정할 수 있습니다.apiVersion: v1 kind: Pod metadata: name: aws-cli labels: name: aws-cli annotations: iam.amazonaws.com/role: role-arn spec: ... 설치나 사용법은 문서를 참고하면 어렵지 않은데, 원리를 간단히 설명해 보겠습니다. EC2 인스턴스 안에서는 특정 IP 주소(169.254.169.254)로 접속하면 EC2 메타데이터 API에 접근할 수 있습니다. AWS SDK는 EC2 메타데이터 API를 통해서 인스턴스 프로파일에 붙은 IAM 역할과 IAM 역할에 해당되는 액세스 키 쌍을 받아오게 됩니다.kube2iam은 모든 노드에 실행되면서 Pod 내부에서 EC2 메타데이터 서버 주소로 나가는 모든 요청을 가로챕니다. 그리고 인스턴스 프로파일 정보와 액세스 키 발급 요청을 kube2iam 서버가 대신 처리합니다. 따라서 Pod 안에서는 인스턴스 프로파일이 부여된 EC2 인스턴스 내부에 있는 것처럼 느껴지게 됩니다.추후 AWS SDK에 EKS 지원이 추가되면 별도로 데몬을 설치하지 않고도 Pod에 IAM 역할을 줄 수 있게 될 것으로 보입니다.로그 수집: fluentd + CloudWatch LogsKubernetes의 컨테이너가 stdout/stderr로 출력하는 로그는 노드에만 쌓이고 컨테이너를 재시작하거나 삭제하면 함께 삭제됩니다. 또한 노드의 디스크가 꽉 차는 것을 방지하기 위해 일정 크기를 넘으면 오래된 로그는 없어집니다. 그러므로 로그가 사라지지 않도록 계속 어딘가에 모아두어야 합니다.AWS에서 활용할 수 있는 로그 저장 서비스에는 CloudWatch Logs가 있습니다. fluentd를 DaemonSet으로 노드마다 하나씩 실행해서 컨테이너 로그를 CloudWatch Logs로 전송할 수 있습니다.CloudWatch Logs에 저장한 로그는 최근 나온 CloudWatch Logs Insights로 검색, 분석할 수 있습니다. 아직 나온 지 얼마 되지 않아서 기능이 많지는 않지만, 간단히 조회하는 용도로는 충분합니다.CloudWatch Logs Insights 사용 예모니터링: PrometheusEC2 인스턴스 하나에 서비스 하나를 띄워서 사용할 때는 CloudWatch로 CPU 사용률 등의 지표를 측정할 수 있었습니다. 하지만 Kubernetes를 사용하면 여러 서비스가 하나의 인스턴스에서 동시에 실행될 것이므로 인스턴스 수준의 지표는 무의미합니다. 특히 최소 실행 단위인 컨테이너 수준의 CPU 사용률 같은 값을 측정해야 하는데, CloudWatch를 사용하기에는 과금 체계가 적합하지 않습니다.기본 제공되는 5분 간격의 EC2 지표는 무료지만 CloudWatch에 커스텀 지표를 올리게 되면 지표 당 비용을 지불해야 합니다. 이 때 '지표'는 지표 이름 + 고유한 차원(dimension)의 조합입니다. 예를 들어 CPUUtilization이라는 이름의 지표가 PodName=server-aaaaaaaa과 PodName=server-bbbbbbbb라는 다른 차원으로 올라온다면 각각을 다른 지표로 취급합니다. 따라서 지표 수가 너무 많아지지 않게 조정해야 하는데 그러면 상세하게 모니터링하기가 어렵습니다.비용 문제도 있고, Kubernetes의 여러 가지 정보를 CloudWatch로 내보내는 기존 도구가 없었기 때문에 다른 방법을 찾아보게 되었습니다. 그래서 Kubernetes 모니터링을 위해 많이 사용하는 Prometheus를 선택했습니다. Prometheus를 온전히 사용하기 위해서는 다양한 컴포넌트들이 필요한데, Prometheus Operator Helm 차트를 사용하면 비교적 쉽게 구축할 수 있습니다.Prometheus는 Kubernetes 클러스터 모니터링 외에 애플리케이션 모니터링에도 사용할 수 있습니다. 타다의 애플리케이션들은 Spring Boot로 작성되어 있는데 Spring Boot Actuator와 Micrometer의 Prometheus 지원을 사용해서 애플리케이션 수준의 지표도 Prometheus로 모니터링하고 있습니다. 특히 Prometheus Operator를 사용하면 모니터링 대상을 추가할 때 Prometheus 설정 파일을 수정하지 않아도 Kubernetes에 ServiceMonitor 리소스를 등록하기만 하면 되어서 편리합니다.Prometheus로 수집된 지표는 Grafana 대시보드로 시각화하고, 정해진 조건에서 Alertmanager를 통해 PagerDuty와 Slack에 알림을 보냅니다.Grafana 대시보드의 모습자동 처리량 확장: Cluster AutoscalerKubernetes에서 자동 처리량 확장은 크게 두 종류로 나눌 수 있습니다. 먼저 Horizontal Pod Autoscaler로 CPU, 메모리 사용량에 따라 Pod의 수를 자동으로 조정할 수 있습니다. HPA가 실제로 동작하기 위해서는 오토스케일링을 위한 지표를 제공하는 Metrics Server를 설치해야 합니다. 그런데 부하가 증가해서 HPA가 Pod 수를 늘리려고 할 때 워커 노드에 여유가 충분하지 않으면 새로운 Pod을 실행할 수 없어서 소용이 없습니다. 이 때 워커 노드의 수를 자동으로 조정해주는 것이 Cluster Autoscaler입니다. Cluster Autoscaler는 노드 수를 증가시키기만 하는 것이 아니라 여유가 생겼을 때 노드 수를 자동으로 줄여서 불필요한 비용이 발생하지 않도록 해줍니다.AWS 환경에서 Cluster Autoscaler는 EC2 API를 통해 EC2 오토스케일링 그룹의 Desired Capacity 값을 필요한 노드 수로 조정하는 방식으로 작동합니다. 따라서 Cluster Autoscaler에는 EC2 API를 호출할 수 있는 IAM 권한을 주어야 합니다. 이를 위해 위에서 소개한 kube2iam을 사용할 수 있습니다. 그리고 Cluster Autoscaler가 오토스케일링 그룹을 자동으로 발견할 수 있도록 미리 정해진 태그를 붙여야 합니다.한 가지 주의할 점은 노드의 오토스케일링 그룹이 여러 가용 영역(AZ)에 걸쳐있으면 안 된다는 것입니다. 오토스케일링 그룹이 여러 AZ에 속한 경우 AZ 간 인스턴스 수의 균형을 맞추려고 하는데 이 과정에서 인스턴스가 예기치 않게 종료될 수 있습니다. 이 때 해당 노드에 실행되어 있던 Pod이 안전하게 종료되지 않을 수 있기 때문에 AZ마다 오토스케일링 그룹을 따로 만들고 AZ 간 균형은 Cluster Autoscaler가 맞추도록 설정해야 합니다.도움이 되는 링크들위에서 소개한 컴포넌트들은 다음과 같은 Helm 차트를 통해 설치해서 사용하고 있습니다.stable/nginx-ingressstable/kube2iamincubator/fluentd-cloudwatchstable/prometheus-operatorstable/metrics-serverstable/cluster-autoscalerEKS Workshop: AWS 환경에서 Kubernetes 운영할 때 참고할 만한 정보가 많이 있습니다.Kubernetes Slack 채널: #eks 채널에는 AWS 직원들도 접속해 있어서 높은 확률로 답변을 받을 수 있습니다.
조회수 1496

코인원코어 엔진, PM과 개발자가 직접 답해드립니다!

‘코인원코어 엔진을 탑재하고 새로운 심장을 품게 된 코인원.’오늘은 차세대 엔진 프로젝트 ‘랩터TF’ 구성원들과 함께 엔진을 탑재하기까지의 비하인드 스토리와 코인원에서 일하는 이유에 대해 들어보려고 합니다.차세대 엔진 프로젝트는 코인원 크루의 치열했던 고민과 협업의 결과물입니다. 짧게 주어진 시간 동안 출산을 경험한 크루, 공휴일을 반납하고 개근상을 탄 크루 등 여러 에피소드를 남기고 무사히 서비스를 오픈할 수 있었습니다. 이 모든 것은 크루들의 헌신과 열정이 모여 이룰 수 있었던 성과였어요.'랩터TF'를 성공적으로 이끈 랩터 5총사. 지금 바로 이들이 만들어낸 성공 스토리를 공개합니다.Q. 안녕하세요, 자기소개와 함께 현재 하고 계신 일을 소개해주세요!요한 : 이번 랩터 프로젝트 PM과 더불어 블록체인셀에서 Cell Owner (이하 ‘CO’)로 이중생활(?) 하고 있는 조요한입니다. 블록체인셀에서는 주로 암호화폐 자산 입출금을 위한 지갑을 개발하고, 코인원에 블록체인 기술을 연구하고 적용하고 있습니다!자현 : QA셀의 CO 겸 Release Manager를 맡은 구자현입니다. (저도 이중생활을 하네요!) QA셀은 SW테스팅을 통해 코인원 서비스의 품질 경쟁력을 확보하는 것을 목표로 하고 있어요. 그리고 서비스 일정에 차질이 없도록, 전사 배포 프로세스와 일정을 관리합니다.지훈 : 모바일셀의 백엔드 개발자로 일하고 있는 김지훈입니다. 백엔드 개발자에 대해 간략하게 말씀드리면, ‘눈에 보이지 않는 부분을 개발한다.’라고 말씀드릴 수 있겠네요. 저는 코인원 모바일 애플리케이션의 백엔드 API 서버를 담당하고 있습니다. 은호 : 트레이딩셀의 백엔드 개발자 이은호입니다. 지훈님이 모바일 쪽이라면, 저는 웹 영역에서 ‘보이지 않는 손’의 역할을 맡고 있습니다. 서버 뒷단의 작업을 통해 코인원 유저가 안정적이며 신속하게 거래를 할 수 있는 환경을 제공하고 있고요. 랩터 프로젝트에서는 주로 매칭엔진 API 개발을 담당했습니다.허민 : 플랫폼셀의 시스템 엔지니어 허민입니다. 코인원을 지탱하는 인프라 플랫폼의 아키텍처 설계부터 구축과 운영까지 통합적으로 담당하고 있습니다. 특히 이번 랩터 프로젝트가 안정적으로 운영될 수 있도록 서비스 구성부터 많은 정성을 기울였습니다.Q. 차세대 엔진 프로젝트에 왜 랩터라는 별칭이 붙게 되었나요?요한 : 새로운 엔진으로 교체한 이후에 유저들이 서비스적으로 크게 체감할 수 있는 부분은 아무래도 속도일 겁니다. 요새 제 첫째아들이 동물도감에 푹 빠져있어요. 동물도감에서는 지구상에서 가장 빠른 동물로 ‘랩터'라는 공룡을 지칭하고 있습니다. 엔진교체로 거래 속도가 빨라지는 것을 가장 잘 표현할 수 있는 단어라 생각되어 이렇게 별명을 붙여보았어요. 자현 : 저도 랩터 별칭 때문에 찾아본 것이 또 하나 있어요. 전투기 중에서도 가장 빠른 기종을 ‘랩터'라고 하더라고요. 랩터 전투기는 신기술의 집합체이며 아주 정밀하게 만들어졌다고 하네요. 새롭게 교체된 엔진을 가장 잘 표현하는 것 같아 TF원으로서 맴이 아주 뿌-듯합니다!Q. 코인원의 새로운 차세대 엔진 ‘코인원코어'에 대한 자세한 설명 부탁드릴게요.요한 : 코인원코어는 초당 300만 건 이상의 거래 체결 처리가 가능한 고성능 엔진입니다. 수백 대의 서버로 수평 확장이 가능한 분산시스템을 갖추고 있어요. 서비스 중단 없이 거래 엔진을 확장할 수 있고, 신규 암호화폐 상장도 가능합니다. 또한 예상치 못한 장애 상황에서도 별도의 점검 없이 실시간으로 대응할 수 있습니다.코인원은 2014년에 출발해 4년이라는 적지 않은 시간 동안 거래소를 운영하면서 발생한 한계점들을 해결할 솔루션이 필요했어요. 이에 코인원의 다년간 거래소 운영 경험과 서버 엔진 전문기업 아이펀팩토리의 대규모 분산처리 기술이 융합된 거래엔진을 탄생시켰습니다.※ 코인원코어에 관한 자세한 설명은 (https://coinonecore.com/)에서 확인할 수 있습니다!▲화기애애하게 회의중(?)인 랩터TF 크루들!Q. 코인원이 새로운 엔진을 장착하기 이전과 이후, 무엇이 달라졌나요?은호 : 먼저, 시스템 확장성 부분에 대해 말씀드릴게요. 이전에는 상장되어 있는 암호화폐의 개수가 늘어날수록 시스템에 많은 부하가 발생했어요. 시스템을 수평 확장할 수 없는 구조적 한계를 지니고 있었죠. 기존 자원을 더 높은 사양의 자원으로 업그레이드하여 시스템의 부하를 해결했었는데, 이는 매우 높은 유지 비용을 요구하고 확장성 측면에서 한계점이 명확했어요.이제는 코인원코어 엔진을 새롭게 탑재하면서 이러한 부분들을 해결했습니다. 무한히 확장할 수 있는 병렬구조의 아키텍처를 구성했고, 더 많은 암호화폐를 상장해도 끄떡없는 코인원이 되었어요.고가용성과 장애 극복 측면에서 보자면, 모든 서버가 이중화 요건을 만족하여 단일 장애점(Single Point of Failure : SPOF)없는 안정적인 아키텍처로 구성되었습니다. 예상치 못한 장애 상황에서도 별도의 점검 없이 실시간 대응이 가능해 더 안정적인 거래소 운영을 할 수 있습니다.요한 : 이어서 성능에 관한 부분입니다. 거래체결량이 이전보다 100배 이상 향상되었습니다. 암호화폐 거래소 운영에 있어 안정적인 서버 운영은 가장 중요한 요소로 꼽히고 있어요. 특히 거래 서버의 경우 단시간에 수많은 요청을 처리해야 하는데, 코인원 코어는 초당 300만 건 이상 체결 처리를 합니다. 이는 증권사 수준 이상의 체결 엔진 성능이라 말씀드릴 수 있습니다.Q. 이번 코인원코어에 새롭게 적용된 기술적 특징이 있다면?허민 : 한국의 ‘Amazon EKS (Kubernetes Management Service)’가 오픈하고 나서, 가장 빠르게 도입한 회사가 코인원일겁니다. 대부분의 작업을 코드화 한 후, GUI 화면에서 반복적으로 작업하느라 속도가 나지 않던 부분들을 개선하게 되었고요. Kubernetes를 구축하면서 대부분의 서비스를 도커 컨테이너로 전환시키고 서비스들을 마이크로화 했습니다. 이제는 각각의 서비스 배포를 분리해서 업데이트 할 때, 다른 서비스에는 영향을 주지 않도록 시스템을 설계했어요. 개발한 서비스를 안정적이면서도 손쉽게 배포할 수 있고, 문제가 발생했을 때는 빠르게 복구가 가능하게 되었답니다.지훈 : 모바일쪽에서는 이번에 랩터 프로젝트를 하게 되면서 기존 베이스 코드를 리팩토링 한 부분이 절반정도 됩니다. 좀 더 효율적으로 프레임워크를 쓸 수 있도록 리팩토링 작업이 많이 들어갔고요. 많은 성능 향상을 기대하고 있어요!은호 : 앞서 요한님께도 말씀해주셨지만, 코인원코어의 가장 큰 특징은 세계적인 증권 거래엔진을 상회하는 체결성능과 이를 뒷받침하는 안정성이라고 생각해요. 백엔드 개발자 입장에서 성능과 안정성이라는 두가지 품질 요건은 대부분의 상황에서 Trade-off 관계에 놓이게 되는 아키텍처 요건이거든요. 한가지 요건을 달성하게 되면 다른 한가지 요건은 어느정도 희생을 감수할 수 밖에 없습니다. 그러나 코인원코어는 두 마리 토끼를 모두 포기하지 않았어요.초당 300만건이상의 주문을 체결할 수 있는 성능을 제공함과 동시에 장애 발생 상황에서도 단 한 건의 주문 누락 없이 서버가 복구되고 대체됩니다. 이 모든 과정이 전략적으로 자동화 되어 고객의 자산을 보다 더 안전하게 지킬 수 있게 되었어요. 코인원과 코인원코어의 뛰어난 기술력으로 이뤄낸 성과라 자부합니다.▲늦은 시간까지 열정적으로 진행되었던 '랩터TF'▲랩터 TF의 파워업을 위한 영양제와 야식 또한 빠질 수 없겠죠? ;)Q. 코인원 크루로 일하시면서 가장 큰 장점은 무엇인가요?요한 : 직무에 상관없이 자유롭게 소통하는 코인원 크루의 모습이 좋습니다. 코인원에서는 PM, 개발자, 디자이너가 모여 데일리 스탠드업 미팅, 회고 등 원활하게 소통하는 문화가 잘 구축되어 있습니다. 일하면서 좋을 때도 있지만 때론 힘든 부분들도 있을 거에요. 이에 대해 코인원 크루는 서로 투명하게 소통하고 피드백을 건네며 함께 성장합니다.지훈 : 코인원 입사 후에 개발 시간을 그래프로 나타내보았어요. 제 고향인 모바일셀보다 랩터 프로젝트에서 보낸 시간이 더 많더라고요. 랩터 프로젝트를 하면서 느낀 것 중, 코인원 크루는 자부심과 일에 임하는 태도가 남다르다는 것입니다. 저 또한 다른 크루분들의 열정적인 모습을 보고 다시 불태우게 되더라고요. 앞으로 코인원에서 새롭고 재미난 개발작업들을 많이 할 것 같아요.은호 : 코인원이라는 공간은 혼자가 아닌 모두가 함께 만들어나가는 공간이라는 것을 느끼고 있어요. 코인원에서 일하면서 함께 도전하고 성취하려는 크루들의 마인드가 무척 좋습니다. 더불어 모두가 거리낌 없이 새로운 기술을 받아들이려고 하는 스타트업 정신을 잘 가지고 있다는 것이 큰 장점이라고 생각해요. 새로운 기술을 이곳저곳 적용해보면서 시행착오를 겪어야 하는 개발자에게 있어서 가장 중요한 부분입니다. 허민 : 코인원은 이전에 몸담았던 다른 산업군의 회사들보다 훨씬 스펙타클한 곳이에요. 저는 그동안 새로움에 대한 갈증이 매우 컸어요. 시스템 엔지니어의 특성상 기존 서비스를 안정적으로 운영하면서 새로운 기술을 도입하는 부분에는 어려움이 많았거든요. 현재는 다양한 인프라 환경과 블록체인 기술에 관해 공부하고 도전해 볼 수 있는 제 모습이 좋습니다. 그리고 코인원의 크루분들도 새로운 기술에 대해 적극적으로 수용하려 하고, 회사 차원에서도 투자도 많이 이뤄져 뿌듯하네요!자현 : 코인원은 책임감으로 똘똘 뭉친 좋은 사람들이 모여있는 곳이에요. 빠듯한 일정 속에 고생하신 분들이 정말 많습니다. 힘들다고 하기 전에 먼저 알고 서로 응원해주는 모습들이 보기 좋아요. 그렇기 때문에 더욱 힘을내서 랩터 프로젝트를 할 수 있었고요. 또한 새로운 기술에 대해 회사 차원에서 끓임 없이 지원 해줍니다. 저 또한 QA 엔지니어로서 새로운 툴들을 찾아보고 활용할 수 있도록 노력하고 있죠! ▲크루 여러분, 정말 고생 많으셨습니다 :-)Q. 앞으로 코인원에서 이루고 싶은 목표가 있다면?요한 : 블록체인셀의 CO로서 좀 더 안정적인 무중단 입출금 플랫폼을 구축하고 운영하고 싶어요. 아직 블록체인과 암호화폐 생태계가 기술적 관점을 요구할 때가 많아, 일반 유저들이 이해하는데 상당히 어려움을 겪고 있습니다. 저는 유저가 쉽고 편리하게 이용할 수 있는 서비스를 만들고 싶습니다. 마지막으로, 유망한 블록체인 프로젝트들을 더 많이 코인원에 상장하고 싶네요!자현 : QA는 SW제품의 품질을 높이기 위해 개발 전 단계에 걸쳐 코인원의 품질을 체계적으로 잡아가는 조직입니다. 테스팅을 통해 결함을 조기 발견하고 제품 품질을 높여 유저가 서비스를 이용하는 데 문제가 없도록 하고 있어요. 현재 코인원 서비스가 놀이터 수준이라면 고도화된 서비스로 유저들이 즐길 수 있는 놀이동산이 되었으면 좋겠습니다. 코인원 놀이동산에 모여 많은 분이 다양한 서비스를 즐길 수 있으면 좋겠네요!지훈 : 제가 코인원에 입사한 지 얼마 되지 않아, 전체적인 개발을 이해하는데 조금은 감이 오지 않았던 때가 있었습니다. 그래서 특히 랩터TF에 감사해요. 하드코어 심화 속성(?) 수업으로 코인원에 대한 모든 것을 숙지할 수 있게 해주었거든요. 이제는 모바일셀의 백엔드 개발자로서 새로운 서비스나 기능을 많이 개발하고 싶어요. (P.S. 모바일 개발에 대한 A to Z까지 크루분들에게 알려드릴 수 있도록 하겠습니다.)은호 : 개발자의 자아실현 실천법 중에 ‘기여’라는 방법이 있습니다. 개발자는 누구나 오픈 소스 커뮤니티의 도움을 받아 개발을 해왔고, 앞으로도 하고 있을 거에요. 저는 제 멘토와도 같은 오픈소스 커뮤니티에 기여하는 것을 소소하게 목표로 삼고 있어요. 오픈소스 프로젝트를 기획하고, 관심있는 프로젝트에 더 큰 기여를 해 제가 받았던 도움들을 보답하고 싶네요. 이러한 기여의 방법은 저의 개발 커리어로서도 명예이고, 제가 속한 조직에 더 큰 선순환을 불러일으킬거에요.허민 : IT업계 중에서 좋은 개발문화가 회자되는 곳으로 넷플릭스와 페이스북을 꼽습니다. 이들의 경우,  좋은 아이디어나 유저의 요구사항을 빠르게 적용해서 서비스에 반영하고 있어요. 이러한 실행속도는 안정적인 플랫폼이 뒷받침되기에 가능하다고 생각합니다. 코인원 또한 지속적으로 플랫폼을 개선해 나갈 생각이고, 이러한 개발문화를 스며들게 하는것이 제 목표라고 할 수 있겠네요.Q. 코인원에 합류할 예비 PM 그리고 개발자분들에게 한 말씀 부탁드려요!요한 : 코인원은 크루들에게 많은 오너십을 부여하고 있어요. 자신이 맡은 Product에 많은 역할과 권한을 갖는 것을 좋아하고 블록체인을 좋아한다면 코인원으로 오세요! 자현 : 책임감이 강한 분이 오셨으면 좋겠어요. 최소한 자신이 구현한 것에 대해서 끝까지 책임질 수 있는, 마지막 실행단계까지 끝까지 확인할 수 있는 분이었으면 좋겠네요. 모두가 편해지는 개발 월드를 위해!지훈 : 아무래도 금융 쪽에 서비스를 하다 보니까 머리가 좋으신 분들이 정말 많이 지원하실 것 같아요! 아, 추가로 테스트코드를 같이 작성하시는 분이 오시면 정말 좋을 것 같네요!은호 : 자신의 결과물에 자부심과 책임감이 있는 크루가 함께했으면 좋겠습니다! (진지,궁서체입니다.) 허민 : 수평적인 협업을 하고 싶으신 분! 같이의 가치를 소중히 여기시는 분! 어려운 문제가 앞에 있어도 즐기면서 넘어갈 수 있는 분들! 창의적이면서도 효율적으로 일하고 싶으시다면 저희와 함께해요!▲수줍게 웃음짓고 계신 랩터TF 인터뷰이들!지금까지 랩터TF 크루들의 이야기를 들어봤습니다.인터뷰 내내 엔진 서비스를 개발했을 때의 열정이 고스란히 전해졌어요. 함께 서비스를 만들고 성장하면서 서로의 신뢰가 더 두터워졌다는 코인원 크루들. 이러한 믿음 안에서 불가능한 일도 가능하게 만든 힘을 엿볼 수 있었습니다.앞으로 코인원은 더 빠르고, 더 안전하고, 더 단단해진 서비스로 여러분들을 찾아뵐 예정입니다. 엔진 프로젝트를 시작점으로 최고의 서비스를 만들어나가는 이들의 모습이 기대됩니다!끝으로, 특별한 개발문화를 경험할 기회! 코인원 채용에 함께하는 것도 잊지 마세요 :-)
조회수 2385

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 #백엔드 #인사이트 #경험공유
조회수 1319

채널 데스크 프론트엔드 기술 스택

오프라인 고객 분석 솔루션 워크인사이트를 개발해 온 조이는 최근 온라인 접객 서비스 채널을 런칭했습니다. 이 글은 채널과 관련된 기술 블로그의 첫번째 글로 채널 데스크 프론트엔드(웹, 윈도우, OSX)의 기술 스택 및 개발 환경을 소개하도록 하겠습니다.React채널 개발을 처음 시작할 당시 (지금으로부터 1년 전) 에 워크인사이트 대시보드 및 기타 사내 툴에서는 AngularJS 1을 사용하고 있었습니다. 비교적 적은 코드로 복잡한 애플리케이션을 빠르게 만들 수 있는 점에는 만족했지만 퍼포먼스면에서는 아쉬운 부분이 많았습니다. 따라서 새로운 프레임워크 및 라이브러리를 리서치 했고 매우 가볍고 렌더링 퍼포먼스 면에서 AngularJS 1 대비 우위에 있던 React 를 사용하기로 결정했습니다.컴포넌트의 설계 패턴은 Redux를 만든 Dan이 제안한 Container 와 Presentational 컴포넌트를 구분하는 방식으로 설계하고 있습니다. 따라서 Container 가 data fetch 및 update 등의 액션을 실행하고 Presentational 컴포넌트들을 조합하여 렌더링을 하게 됩니다.React를 실제 1년째 사용해 본 결과 저를 비롯한 팀원들은 매우 만족하고 있습니다. 구조, 스타일, 동작을 한 컴포넌트로 묶어 재사용성이 매우 높아졌으며 React의 휴리스틱한 Dom diff algorithm 덕분에 렌더링 퍼포먼스에서도 많은 이득을 얻을 수 있었습니다.Facebook Flux Utils아키텍쳐는 페이스북이 제안한 flux 철학에 따라 설계되었습니다. flux를 구현하기 위한 기본적인 유틸리티 기능을 제공하는 Flux Utils을 사용합니다. Flux의 많은 구현체 중에 요즘 가장 인기인 Redux도 고려했었습니다. 저희가 프로젝트를 시작할 당시에 Redux는 5~6개월밖에 되지 않은 프로젝트였고 거의 Dan의 1인 프로젝트였기 때문에 향후 메인터넌스를 장담할 수 없다고 판단했습니다. 그보다는 페이스북이 만든 Flux Utils가 그런 면에서는 더 안전할 거라고 생각했던 것이죠.약 1년 정도 Flux Utils로 개발해오며 몇 가지 문제를 겪게 되었습니다. 애플리케이션이 커지면서 관리해야할 State가 많아지고 그들 사이의 의존성 관리 때문에 Store의 복잡도가 빠르게 증가했습니다. 그에 따라 테스트가 어려워지고 올바른 유닛테스트를 위해서는 테스트 코드 역시 매우 복잡해지는 문제가 있었습니다.그래서 Redux를 다시 리서치하게 되었고, 결론적으로 “단일 Store, 다수Reducer” 라는 Redux의 철학을 통해 State 관리 로직(Reducer)을 단순하고 테스트도 쉽게 유지할 수 있겠다는 생각을 하게 되었습니다. 뿐만 아니라 그 동안 설계와 관련되어 고민하고 필요한 경우 저희 스스로 개발해서 사용하던 많은 부분이 Redux의 서브 프로젝트 형태로 (redux-actions, redux-thunk, reselect 등) 개발되어 사용되고 있는 것을 발견해서 Redux로의 마이그레이션을 결정했고 현재 진행 중에 있습니다.Electron이 글의 도입부에서 이야기한 것처럼 채널 데스크는 윈도우용, OSX용 애플리케이션으로도 제공됩니다. 채널 개발 초기 당시 윈도우, OSX 각각 네이티브로 만들 리소스가 부족했기 때문에 웹 기술 기반으로 네이티브 앱을 만들 수 있는 다양한 솔루션들을 리서치했고 그 중 Electron을 선택하게 되었습니다.Electron은 제가 정말 좋아하는 제품인 Slack, Simplenote에서 사용하고 알려져 있고 국내에서는 Remember 등에서 사용하고 있습니다. 초기 개발 당시에는 안정성에 의문을 제기하는 개발자들도 많았고 저희도 여러 문제와 삽질(인증, 패키징, 이슈 레포팅의 어려움, 메모리릭 등등)을 많이 겪긴 했습니다만 개인적으로는 충분히 프로덕션에 쓸 수 있을 정도 수준이라고 생각합니다. 무엇보다 프론트엔드 개발자가 매우 적은 노력으로도 네이티브 데스크탑 앱을 만들 수 있는 장점이 다른 모든 문제점을 상쇄하고도 남습니다.언어개발 언어로는 자바스크립트 ES6를 사용합니다. 언어를 선택할 당시에도 여러 옵션이 있었는데 가능하면 실험적이지 않고 표준을 사용하는 것이 미래 유지보수에 안전하다고 판단했습니다. 또한 다른 자바스크립트 대안 언어를 사용하지 않더라도 ES6 (일부 ES7 포함) 스펙도 충분히 효율적인 개발이 가능하다고 생각했습니다.코딩 스타일은 기본적으로 Airbnb의 코딩 스타일 가이드라인을 따르며 조이의 상황과 맞지 않는 부분은 엔지니어들과 상의 후 수정해서 사용하고 있습니다. 스타일 체크는 ESLint로 자동화한 뒤 Circle CI와 붙여서 모든 풀리퀘스트에 대해 점검하고 있습니다.테스트초기 개발할 때는 테스트 코드를 별도로 붙이지 않았습니다. 고객의 요구와 기타 상황에 따라 기획과 설계가 크게 변경되기도 했고 그 때마다 기민하게 반응하기 위해서, 어느 정도 확립된 제품이 되기 이전에는 테스트 코드는 작성하지 않는 것이 좋다고 판단했습니다. 이제는 많은 부분이 확정되었고 안정성이 중요해지기 시작했으며 애플리케이션이 커지면서 자동화된 테스트는 필수가 되기 시작했기에 최근에 도입을 하고 있습니다.테스트를 위한 도구는 Jest, Enzyme 등을 사용합니다. Presentational 컴포넌트에 대한 테스트는 props에 따라 원하는 형태로 렌더링이 이루어지는지, 이벤트에 따라 콜백이 잘 실행되는지 등의 Spec 을 작성합니다. Container 컴포넌트에 대한 테스트는 각종 이벤트 및 동작을 시뮬레이션하고 그에 따라 Action이 잘 발생하는지 또는 내부 state가 잘 변경되는지를 테스트합니다. 또한 Store (또는 Reducer), Action Creator, Model, Util 등 모든 구성 요소에 대한 테스트를 붙이려고 노력하고 있습니다. 유닛 테스트가 아닌 e2e 테스트 혹은 css 스타일 테스트 등은 하지 않고 있습니다.빌드 및 배포현재 채널 데스크는 Client-side rendering을 합니다. 초기 로딩 속도가 느리다는 단점이 있어서 Server-side rendering으로의 전환도 고려하고 있습니다. 이미 Node.js 를 사용하고 있어서 Isomorphic Javascript의 형태로 어렵지 않게 전환이 가능합니다.작성된 자바스크립트는 Babel로 컴파일되고 Webpack으로 번들화됩니다. css를 포함한 각종 리소스들 역시 Webpack을 통해 처리됩니다. 웬만한 작업은 npm과 Webpack으로만 자동화하려고 했으며, Electron과 관련된 작업(패키징, 인증 등)들만 gulp를 이용해 자동화됩니다. 모든 리소스들은 Node.js + express 서버로 Serving 되고, Node.js 앱은 Docker로 빌드되어 AWS EC2로 배포됩니다.마무리이상으로 채널 데스크 프론트엔드의 기술 스택을 소개해드렸습니다. 앞으로 각 부분 별로 저희 팀이 고민해 온 문제들과 해결 방법을 공유하고자 합니다. 뛰어난 개발자 분들의 많은 관심과 피드백 부탁드립니다!
조회수 2722

iOS 아키텍처 패턴(MVC, MVVM, VIPER)

Overview“글 한 번 써보실래요?” 입사하고 일주일이 지나 기술 블로그에 글을 써 보라는 제안을 받았습니다. 여러 고민 끝에, 아이폰 앱(이하 ‘iOS’) 주니어 개발자로서 프로젝트 경험과, 공부한 내용을 바탕으로 글을 쓰기로 했습니다. 적절한 짤이라고 생각하는 중iOS 개발자 사전 준비iOS 개발자의 길에 들어섰다면 이미 앱 개발과 개발 언어에 대해서는 알고 있을 겁니다. 개발 프로그램 Xcode와 프로그램을 지원하는 macOS 환경, 개발 언어 Swift 또는 Objective-C, iOS 앱 프로그래밍 등 iOS 앱을 개발하기 위해 필요한 내용까지도요. 우선 ‘iOS 주니어 개발자라면 꼭 알고 있어야 할 것’들을 아래 목록과 같이 정리했습니다. 글을 읽기 전, 목록 중에서 공부가 더 필요한 것이 있다면 꼭! 검색해보세요. Xcode, macOSApple Developer ProgramSwift or Objective-CCocoa TouchUIKitAuto Layout…iOS Architecture Patterns(아키텍처 패턴)“Viper 패턴 들어보셨어요?” Viper는 단순히 ‘독사’를 의미하는 줄 알았는데, MVC 패턴와 같이 디자인 패턴의 한 종류라는 건 입사하고 나서 알게 됐습니다. MVC와 SingleTon(싱글톤) 패턴은 익숙했지만 Viper 패턴은 생소했습니다. Viper 패턴을 3일 안에 분석하겠다는 저의 부끄러운 과거를 반성합니다... ㅜㅜ검색해보니 다양한 디자인 패턴을 찾을 수 있었습니다. iOS 개발자는 앱 프로젝트를 시작하기 전 또는 이미 진행되고 있는 프로젝트에서 개발을 시작한다면 우선 어떤 패턴으로 설계되어 있는지 파악해야 합니다. 그러므로 오늘은 iOS 개발에 주로 사용되는 패턴인 MVC, MVVM, VIPER를 간단하게 살펴보겠습니다.MVCMVC 패턴Model(모델), View(뷰), Controller(컨트롤러). Model에서는 애플리케이션에서 사용할 데이터들을 관리하고, View는 유저 인터페이스를 표현 및 관리합니다. Controller는 View와 Model의 다리 역할을 해 View의 입력을 Model이 반영하고, Model의 변화를 View에 갱신하는 역할을 합니다. 하지만, 애플의 MVC 패턴은 기존 MVC 패턴과 다릅니다. View와 Controller가 강하게 연결되어 있어 View Controller가 거의 모든 일을 합니다.1) 애플 MVC 패턴MVVMMVVM 패턴Model(모델), View(뷰), ViewModel(뷰모델). Controller를 빼고 ViewModel을 추가한 패턴입니다. 여기서 View Controller가 View가 되고, ViewModel이 중간 역할을 합니다. View와 ViewModel 사이에 Binding(바인딩-연결고리)가 있습니다. ViewModel은 Model에 변화를 주고, ViewModel을 업데이트하는데 이 바인딩으로 인해 View도 업데이트됩니다. ViewModel은 View에 대해 아무것도 모르기 때문에 테스트가 쉽고 바인딩으로 인해 코드 양이 많이 줄어듭니다.import Foundation // ViewModel var gameScore: Int? var gameScoreLabel: UILabel func updateGameScoreLabel() {   var text = ""   if let gameScore = gameScore, gameScore == 100 {       text = "Excellent!!"   } else if let gameScore = gameScore, gameScore >= 90 && gameScore < 100>       text = "Great Job!"   } else if let gameScore = gameScore, gameScore < 90>       text = "Not Bad~"   }   gameScoreLabel.text = text } // View Controller gameScoreLabel.text = viewModel.updateGameScoreLabel간단한 예를 들면, 게임 점수에 따라서 textView에 보여줄 내용을 담당하는 함수 등, View에서 변화가 일어나는 함수들이 View Controller에 정의되어 사용하는 경우가 많을 겁니다. 이런 함수들이 점점 많아지면 View Controller가 Massive, 많은 코드를 담게 됩니다. 그래서 이런 함수들을 ViewModel에 옮기고, 값들을 미리 세팅한 다음에 view controller에서 viewModel을 선언하고 viewModel의 함수를 불러오는 식으로 사용하면 됩니다. 매우 간단한 예제이기 때문에 대략 viewModel과 view controller에서 어떻게 사용하는지만 보시면 될 것 같습니다. 이 패턴은 주로 Reactive programming(ReactiveCocoa, RxSwift 등)을 할 때 많이 사용하는 패턴이어서 다음에 설명하겠습니다.VIPERVIPER 패턴View(뷰), Interactor(인터렉터), Presenter(프리젠터), Entities(엔티티), Router(라우터). MV(X) 패턴과 다른 패턴으로 MVC 패턴을 대체하기 위해 만들어진 패턴입니다. 먼저 Entity는 그저 모델 객체입니다. 단순하게 어떤 모델의 속성들만 있는, Dumb Model이라고 부를 수 있습니다. 이 모델 객체를 조작하는 것이 바로 Interactor입니다. 어떤 행동(behavior or use case)에 따라서 모델 객체를 조작하는 로직이 담겨 있습니다. 작업이 완료되어도 View에 아무런 영향 없이 오로지 데이터 작업만 합니다.Presenter는 데이터를 Interactor에서 가져오고, 언제 View에 보여줄지 결정합니다. View에 보여주기 전 내용을 준비하는 로직을 담당한다고 생각하면 됩니다. View는 Presenter에서 어떻게 보여줘야 할지 요청대로 디스플레이하고, 사용자의 입력을 받으면 다시 Presenter로 넘깁니다. Presenter는 View/ViewController, Interactor, Router와 상호작용합니다. Interactor로부터 조작된 데이터를 가져오고, 디스플레이하기 위해 데이터들을 준비한 다음 View/ViewController에 보냅니다.Router 또는 Wireframe은 화면 전환(navigation information)을 담당합니다. Presenter가 “언제” 화면을 전환해야 하는지 안다면, Router는 화면 전환을 “어떻게” 하는지 알고 있습니다. Router는 화면 전환 애니메이션을 구현하고, View Controller를 생성하여 Presenter와 연결합니다.항목내용ViewPresenter의 요청대로 디스플레이하고, 사용자 입력을 Presenter로 보내는 작업을 합니다.InteractorUse case에 따라서 Entity 모델 객체를 조작하는 로직을 담고 있습니다.PresenterInteractor로부터 데이터를 가져오고, View로 보내기 위해 데이터를 준비하여 “언제” View에 보여줄지를 결정합니다.Entity모델 객체. Dumb Model.Router(Wireframe)화면 전환(navigation information)을 담당하며, Presenter가 “언제” 화면 전환해야하는지를 안다면, Wireframe은 화면 전환을 “어떻게” 하는지를 알고 있습니다.하...지금까지 설명한 내용들은 막상 프로젝트 만들어 소스를 작성하려고 하면 막막해집니다. 역할이 잘 분할되어 있기에 앱의 기능을 하나 정하여 interactor, entity, presenter, view, router 만들고, 또 앱의 기능에 따라서 다시 interactor, entity,…. 고민을 많이 해야 해서 다시 MVC 패턴으로 돌아가고 싶은 마음이 생깁니다.크게 보면 Add Module와 List Module, 그리고 공통적인 모델(데이터)을 잘 분리한 앱 구조Conclusion도대체 우리는 왜 다양한 앱 디자인 패턴을 알아야 할까요? 그 이유는 바로 앱의 특성에 따라 적합한 설계를 가지고 작업해야 하기 때문입니다. 간단한 앱 프로젝트는 쉽게 개발하고 적용할 수 있는 MVC 패턴이 더 적합합니다. 반대로 MVVM 패턴이나 VIPER 패턴을 적용하면 점점 커지는 앱 프로젝트에 잘 대응할 수 있습니다. 또는 어떤 디자인 패턴이 적용된 앱 프로젝트에 참여하면, 그 디자인 패턴에 대해 알아야 앱 구조를 이해하고 기능을 추가하거나 수정할 수 있고, 작업하는 시간을 줄일 수 있을 겁니다.가장 좋은 패턴은 사람마다 차이가 있습니다. 패턴마다 장단점도 있습니다. 다만 어떤 패턴이든지 간에 구조화되고 정리된 코드는 쉽고, 직관적입니다. 이 글 하나만으로 앱 패턴을 완벽하게 마스터할 수는 없어도 패턴의 종류와 특징을 알게 되었다면 본전입니다. 다음 편도 기대해주세요! :-) 도움말 1) View Controller에서는 Controller가 View의 life cycle(라이프 사이클)에 관여하기 때문에 View와 Controller를 분리하기 어렵습니다. 개발자들 사이에서는 Massive View Controllers라고도 불립니다. 앱을 테스트할 때, Model은 따로 분리되어 테스트를 할 수 있어도 View와 Controller는 강하게 연결되어 있기 때문에 각각 테스트하기 어렵습니다. 참고문헌 iOS Architecture Patterns: Demystifying MVC, MVP, MVVM and VIPER글김주희 사원 | R&D 개발1팀kimjh3@brandi.co.kr브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유 #iOS
조회수 995

ASIHTTPRequest를 대체하는 iOS 네트워킹 라이브러리 2가지

ASIHTTPRequest는 iOS 개발자들 사이에서 가장 많이 이용되는 네트워킹 라이브러리인데, 간결한 인터페이스와 개선된 성능으로 인기를 끌었습니다. Github의 Objective-C Most Watched Overall에서도 2위 자리를 현재도 유지하고 있는 것을 보면 이 라이브러리가 얼마나 오랜 시간 동안 iOS 개발자들에게 사랑받았는지는 쉽게 알 수 있습니다.[request release];하지만 애석하게도, 이 라이브러리는 작년 9월에 제작 종료가 선언되었습니다. 6개월 이상 된 소식이지만 하도 오랜 시간 동안 쓰여와서 소개된 곳이 많다보니 제작 종료 소식이 많이 안 퍼지고 있는 듯합니다.여러 가지 이유가 있겠지만, 제작자는 제작 종료 선언 글을 통해 “내부가 너무 복잡해졌고, 수 년에 걸쳐 누적된 몇 가지 아키텍처 선택이 프로젝트를 유지 보수하기 어렵게 만들었다.”라고 제작 종료 선언의 이유에 대해 고백하고 있습니다.부지런히 갈아탈 준비를 해두세요.제작 종료가 선언된 라이브러리인 만큼 가능하면 새로운 라이브러리로 갈아타시는 것이 좋습니다. iOS 개발환경은 1년 단위로 빠르게 성장하고 있는데, 당장 최근 iOS5 개발환경만 해도 block 문법 기반의 API 패러다임, ARC 지원들이 현행 라이브러리들의 필수 요소처럼 굳어져 가고 있습니다. 이에 맞추어 따라갈 수 있는 라이브러리들을 쓰는 것이 장기적인 개발 환경 개선에 도움이 될 것입니다.어떤 대안이 있나?ASIHTTPRequest 라이브러리 개발자는 여러 가지 대안을 소개했지만, 저는 2가지 정도로 간추려서 추천하고자 합니다. 하나는 AFNetworking이며, 하나는 MKNetworkKit입니다.AFNetworkingAFNetworking은 최근 Facebook에 인수된 Gowalla에서 NSURLConnection, NSOperation 등의 기본 Foundation framework 위에 구현된 네트워킹 라이브러리입니다.현재 ASIHTTPRequest의 대안으로 가장 빠르게 성장하고 있는 라이브러리인데, 그 이유는 유명 애플리케이션 개발사의 개발자들이 유지하고 있는 프로젝트이면서, 꽤 명쾌한 API를 제공하고 있습니다. 기본적인 block 기반의 API 구성 외로도, SDWebImage와 같은 라이브러리에서 볼 수 있는 이미지 다운로드 헬퍼도 제공하고 있어 매우 편리합니다.자세한 사용법은 AFNetworking Github 저장소에서 확인할 수 있습니다.MKNetworkKitASIHTTPRequest는 편리한 API를 제공해주는 것으로 많은 사용자에게 사랑받았지만, 기본 NSURLConnection, NSOperation 으로 낼 수 없는 높은 퍼포먼스 또한 그의 강점이었습니다. MKNetworkKit은, ASIHTTPRequest의 아키텍처와 AFNetworking의 인터페이스를 동시에 지향하고자 하는 라이브러리입니다. 그 외에도 아래와 같은 기능들을 추가로 겸비합니다.전체 앱에 대한 single queue 관리자동 queue 크기 조절캐싱과 복구 기능비슷한 request를 하나의 처리로 수행Full ARC support아주 멋진 목표를 가지고 진행되고 있는 프로젝트이며 개발 진척도 상당히 빠른 속도로 진행 중이지만, 아직 자잘한 버그가 많다는 것이 단점입니다. 네트워킹 라이브러리는 애플리케이션 단위에선 상당히 저 수준에 있는 만큼, 이 문제는 치명적일 수 있습니다. 그래서 상업용 프로젝트에 바로 이용하기보다는 실험적인 프로젝트에서 써보면서 지켜보는 것을 추천합니다.마무리하며iOS 애플리케이션 개발 환경에서 네트워킹 라이브러리의 선택은 개발 속도와 애플리케이션 퍼포먼스에서 아주 중요한 위치에 속합니다. ASIHTTPRequest는 그 중 가장 많이 쓰였지만, 개발 종료를 선언했기 때문에 대안 라이브러리를 준비하시는 것이 좋습니다.AFNetworking은 편리하게 쓸 수 있는 API를 NSURLConnection, NSOperation 위에 구현하였으며, 믿을 수 있을 만큼 성숙하여 현재 새 프로젝트에 바로 도입하기 좋습니다. MKNetworkKit은 아직 개발이 한창 더 진행되어야 하지만 API 디자인과 개선된 퍼포먼스, ARC 지원 등 보다 미래지향적인 목표를 하고 있으므로 장기적으로 지켜볼 가치가 있습니다.이 외에도 추천하는 라이브러리가 있다면 공유해봅시다.#스포카 #개발 #개발팀 #개발자 #개발팁 #꿀팁 #인사이트 #조언
조회수 793

AWS IoT Core 활용하기

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

Dropwizard와 Asynchronous HBase 적용기

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

스켈티인터뷰 / 스켈터랩스의 스테로이드 서종훈 님을 만나보세요:)

Editor. 스켈터랩스에서는 배경이 모두 다른 다양한 멤버들이 함께 모여 최고의 머신 인텔리전스 개발을 향해 힘껏 나아가고 있습니다. 스켈터랩스의 식구들, Skeltie를 소개하는 시간을 통해 우리의 일상과 혁신을 만들어가는 과정을 들어보세요! 스켈터랩스의 스테로이드 서종훈 님을 만나보세요:)사진1. 스켈터랩스 스테로이드 서종훈 님Q. 진부한 첫 번째 질문, 자기소개를 부탁한다.A. 스켈터랩스에서 소프트웨어 엔지니어로 일하고 있는 서종훈이다. 연세대학교 컴퓨터과학과에서 HCI(Human-computer interaction)와 컴퓨터 비전(Vision)쪽 연구로 박사 학위를 받았다. 그리고 L모 기업의 AI연구소에서 일을 하다가 최근 스켈터랩스에 입사했다.Q. 어떻게 스켈터랩스에 입사하게 되었는지 궁금하다.A. 지인을 통해서 스켈터랩스의 여러가지 프로젝트에 대해 듣게 되었다. 스켈터랩스의 Inno Lab에서 진행 중인 프로젝트가 HCI와 가장 연관성이 깊고, 재미있는 디바이스를 구현하고 있어서 눈여겨 보다가 입사를 지원했다. 물론 프로젝트의 방향성이 나의 관심 분야와 일치하는지 뿐만 아니라, 함께 일하는 사람이 어떤 사람인지 알아보는 과정도 필요했다. 다행히 스켈터랩스에 지인이 있었고, 그의 소개로 하드웨어 엔지니어팀을 이끌고 있는 재경 님을 비롯하여 다른 팀원들을 미리 만날 수 있었다. 긴 대화 끝에 회사의 조직문화나 방향성의 결이 나와 맞는다는 생각을 했다. 뛰어난 개발자가 많기 때문에 내가 계속 성장해나갈 수 있는 환경이라는 점도 입사 결심을 굳히게 된 큰 요소 중 하나다.Q. 스켈터랩스에서는 어떤 업무를 맡고 있는가. A. 스마트 거울 샘(Samm)의 제스처 인식을 담당하고 있다. 이미지 인식을 기반으로 하는 작업이기 때문에 카메라로 구현을 하는게 맞을 지, 혹은 센서를 사용하는 것이 좋을지를 테스트하며 최적의 답을 찾아내려 하고 있다. 또한 엔도어 솔루션(Endor Solution, 공정 과정에서 부품의 결함을 자동으로 검출하는 솔루션)이 더욱 뛰어난 성능을 발휘할 수 있도록 개발에 참여하고 있다. 기존의 팀원들 모두가 딥러닝 경험이 풍부하다. 반면 전통적인 비전(Vision) 쪽 경험은 상대적으로 내가 더 풍부하기 때문에, 데이터처리나 고전적인 방법을 적용한 개발을 통해 엔도어 솔루션을 탄탄하게 보완하려고 한다. 텐서플로우(Tensorflow) 기반으로 기존의 팀이 일해왔다면, 나는 OpenCV를 통해 선행 데이터를 처리한다.사진2. 영화 <마이너리티 리포트>에 등장하는 G-SpeakQ. 비전 기술에 관심을 갖게 된 특별한 계기가 있었는지 궁금하다.A. 글쎄, 계기라고 말하기는 힘들다. 그냥 자연스럽게 HCI쪽에 관심을 가지게 되었고, 그러다보니 다양한 인터페이스를 구현하는 일을 맡아왔다. 당시 HCI가 붐이었고, 아이폰이 이제 막 세상에 등장한 시기이기도 했다. 그런데 HCI 분야의 개발을 지속할수록, 사람들에게 편리한 방식으로 원하는 것을 제공할 수 있는 분야에서 비전 기술은 필수라는 생각이 들더라. 웨어러블 디바이스를 사용하지 않고서도, 개개인의 행동을 관찰하고 그에 맞게 적절한 가이드를 제시하는 것은 모두 비전을 바탕으로 한다. 스티븐 스필버그 감독의 톰 크루즈 주연 영화 <마이너리티 리포트>를 보면, 톰 크루즈가 특수장갑을 착용한 채 스크린을 제어하는 장면이 등장한다. 양손을 사용하여 자유자재로 허공에 활성화시킨 스크린을 제어하는데, 이 장면은 단지 영화 연출이 아닌 실제로 개발된 기술에서 영감을 얻은 장면이다. 기술의 명칭은 ‘G-스피크(G-Speak)’. 이 혁신적인 기술을 개발한 존 언더코플러(John Underkoffler)는 영화 자문 이후, ‘오블롱 인더스트리즈(Oblong Industries)’라는 회사를 설립했다. 사실 ‘G-스피크'를 구현하기 위한 개별 기술들은 당시에도 굉장히 많았다. 오블롱의 차별점은 이 다양한 개별 기술을 하나로 통합한다는 점이다. 오블롱의 행보를 관찰하며, 비전 기술의 활용도에 대해 일종의 확신을 강하게 품게 되었다. NUI(Natural User Interface) 기술이 보편화되면, 기존 오퍼레이션 시스템 환경은 크게 변화할 것이다. 그때 일반 소비자에게 편하게 와닿을 수 있는 새로운 인터페이스를 선도하는 회사가 시장의 선도자가 될 것이고, 비전 기술은 시장 선도자의 핵심일 것이라고 생각하고 있다.Q. 여러 프로젝트에 동시에 참여하고 있기 때문에, 각 팀마다 업무 방식이 어떻게 다른지를 경험했을 것 같다. 그 이야기를 듣고싶다.A. 기본적으로 분위기가 굉장히 다르다. 엔도어 솔루션은 기업의 사설연구소의 느낌이랄까, 굉장히 학구적인 느낌이 강하다. 딥러닝과 관련된 많은 논문을 읽고 깊이 있게 연구하고자 한다. 많은 실험도 필수적으로 병행되는데, 내부적으로는 각 논문과 실험을 통해 얻은 인사이트를 정리하고 공유하고자 노력하고 있다. 이러한 과정을 통해 기존의 다양한 모델을 조합하고 자체적인 모델 개발을 통해 최적의 결과물을 구축하려고 한다. 반면 Inno Lab의 다양한 프로젝트는 오히려 내가 기대했던 스타트업스러운 느낌이 있다. 기존에 없던 디바이스를 만들어 내기 위해 다같이 아이디에이션 과정을 진행했다. 그리고 빨리 구현하고 피드백을 취합한 후, 다시 개발에 들어가는 과정이 꽤 다이나믹하게 이뤄진다. 현재 개발 중인 샘 덕분에 주변의 신기하고 재미있는 디바이스를 검색해보고, 직접 써보고 있는데 덕분에 굉장히 얼리어답터가 된 듯한 느낌이다.사진3. 종훈 님의 일하는 모습을 몰래 촬영해보았다Q. 동시에 결이 다른 두 개의 프로젝트를 진행하기가 어려울 것 같다.A. 어렵다. 그래서 나는 아예 프로젝트마다 기한일을 설정한다. 한 분야에 몰입해서 쭉 끌고 나가는 것이 내게는 더 맞는 느낌이라, 각 프로젝트의 PM과 상의하여 샘 개발에 15일까지 참여한다면, 월 말까지는 엔도어 솔루션에 참여하는 식으로 조정한다.Q. 이전 직장과 스켈터랩스의 업무가 어떻게 다른지도 궁금하다.A. 이제 스켈터랩스에 합류한지 3개월이 좀 지났는데, 크게는 두 가지가 가장 다른 점이자 만족스러운 점인 것 같다. 첫 번째는 일단 개발 환경이다. 스켈터랩스는 개발 환경이 굉장히 빠르고 선진적이다. 개발을 워낙 잘 하시는 분들이 많기 때문에 협업하면서 배울 점도 많고 협업을 통한 시너지도 강하다. 여러가지 툴을 똑똑하고 빠르게 잘 활용하는 것도 업무 효율을 크게 향상시키는 부분이다. 구글 드라이브, 깃허브(GitHub) 뿐만 아니라, 유트랙(Youtrack)과 같은 이슈트래커(Issue Tracker)도 적극 활용한다. 클라우드 환경, 빌드 환경 등도 모두 유연하게 잘 갖춰져있다. 이전 회사가 폐쇄적으로 운영되었던 부분이 있어서 상대적으로 이런 부분을 더 만족스럽게 생각한다. 스타트업인 만큼, 신기술에 대해서 팔로우하고 적용시켜 보려는 과정이 빠르게 일어나고 있는 점도 좋다. 두 번째는 ‘함께 하고 있다'라 느낌이 강하다는 것이다. 이전에는 워낙 프로젝트의 규모도 컸기 때문에, 각자 맡은 업무의 경계선이 분명하게 그어져있었다. 그러나 스켈터랩스는 잦은 미팅을 통해 함께 기획부터 참여하기 때문에 ‘우리의 것'을 만들어낸다는 느낌을 준다.Q. 스켈터랩스에서 가장 애정하는 조직문화가 있다면?A. 맥주를 먹으면서 일할 수 있다는 것(스켈터랩스에는 맥주 디스펜서가 구비되어 있다)! 다이어트를 하고는 있지만 워낙 맥주를 좋아하는 나로서는, 개발이 잘 안풀릴 때 맥주를 먹으면서 일을 할 수 있다는 것 자체가 만족스럽다. 매주 금요일마다 함께 모여서 회사의 여러 프로젝트 진행 상황을 듣고, 구성원에 대해서 알아보는 시간인 올핸즈(All-hands)도 좋아한다. 보통 다른 회사의 경우 정보가 총체적으로 전달되지 않고, 쪼개진 정보만이 내려오는 경우가 많다. 하지만 올핸즈 덕분에 회사의 정보들이 모두에게 공유될 수 있고, 또한 참여할 수 있다고 생각한다.Q. 비슷한 질문이지만 회사 자랑을 위해 하나 더 묻고싶다. 스켈터랩스에서 가장 자랑하고 싶은 점을 꼽는다면 무엇일까.A. 두 가지를 꼽고 싶다. 먼저 자유로운 문화라는 점. 한국에서 정말 몇 안되는 실리콘밸리의 분위기를 풍기는 곳이라고 생각한다(단순히 나만의 의견이 아니라, 실제 실리콘밸리에서 근무하는 친구가 사무실에 놀러왔을 때 ‘실리콘밸리 같다'라고 표현했다). 겉으로는 허름한 창고같은 사무실이지만, 문만 열리면 다른 세계가 펼쳐지는 듯한 느낌을 받을 수 있다. 자유롭게 의견을 내고 토론을 하는 문화도 이 사무실의 분위기와 일맥상통한다. 두 번째는 개개인의 실력이 높아서 정말 배울 것이 많다는 점이다. 그게 한편으로는 스트레스기도 하다. ‘내 밑천이 바닥나면 안될텐데'라는 생각에 책과 다양한 소스를 통해 끊임없이 자발적으로 공부하게 만든다. 실제 개발자 중 몇 분은 구글에서 개발자 레벨의 최고 등급을 받은 것으로 알고있다. 개발 실력은 당연히 코드에 묻어나온다. 다른 개발자의 코드를 보면서도 많은 영감을 얻을 수 있고, 코드 리뷰에 참여하는 것 만으로도 개발 실력이 향상될 수 있다.Q. 자유로운 출퇴근 문화지만, 종훈 님은 꽤 일찍 출근하는 편으로 알고 있다. 하루 일과가 궁금하다.A. 집에서 아침 시간을 여유롭게 즐기는 편이다. 여섯시에 일어나 아침 밥을 집에서 챙겨먹고 출근하고 있다. 일찍 출근할수록, 그 날 내가 목표로 한 업무를 빨리 마치고 퇴근할 수 있기 때문에 너무 늦게는 출근하지 않으려 한다. 덕분에 규칙적으로 일곱시 쯤에는 퇴근을 마치고 운동을 한다. 주말에도 주로 운동을 즐기는 편인데, 요즘에는 토요일마다 꼬박 꼬박 딥러닝 스터디를 하고있다. 나는 전통적인 비전(Vision) 연구를 해왔기 때문에, 딥러닝 쪽은 바탕 지식이 얕은 편이다. 업무를 진행하는데 큰 어려움은 없지만, 회사 프로젝트의 좋은 결과물을 내기 위해서는 딥러닝을 썼을 때 효율적인 부분이 크다. 때문에 많은 시간을 공부에 할애하는 것 같다.Q. 스켈터랩스 헬스동호회 스켈터 스테로이드의 수장으로 알고있다. 동아리를 소개한다면?A. 동호회를 만들게 된 계기는 단순하다. 새 회사에 왔으니, 새로운 몸을 만들겠다는 마음이었다. 사실 헬스는 누군가랑 같이 하는 운동은 아니지않나. 그래도 동호회원들 덕분에 ‘오늘은 그냥 좀 운동을 쉴까’ 싶다가도 누군가가 먼저 나서면 ‘그래도 빠지지 말아야지'란 생각에 꼬박꼬박 운동을 가게된다. 일주일에 두 번이니, 부담스럽지 않은 양이기도 하다. 내가 수장인 만큼 본보기로 열심히 나가야한다는 일종의 책임감도 꾸준히 운동을 이어나가는 원동력이 되었다. 날씨가 추워지면서, 다들 몸을 만들겠다는 의지가 약해져서인지 최근에는 참여률이 떨어지고 있다. 실내에서 할 수 있는 다양한 운동 종목을 더해, 참여를 높이는 방법을 고민 중이다. Q. 운동을 꾸준히 해오고 있는데, 헬스 동호회를 통해 목표했던 성취는 이루었는지 궁금하다.A. 동호회 소개를 하며 ‘이틀 밤을 새도 지지않는 체력을 얻어갈 수 있습니다'라고 공표했는데, 변명이지만 목표가 너무 거창했던 것 같다. 이틀 밤을 새도 지지않는 체력이 갖기 위해 갈 길이 멀다. Q. 이제 인터뷰를 마무리할 단계다. 스켈터랩스가 어떤 회사가 되면 좋겠는가.A. 앞서 말했던 오블롱 인더스트리즈나 센스타임(Sensetime)처럼, 확고한 기술력으로 시장의 선두주자가 되었으면 한다. 이를 위해서는 논문도 많이 내야할 것이고, 더욱 많은 개발자와 함께 기술을 더 깊게 파고드는 과정이 지속되어야 한다. 또한 스타트업으로서 시장의 성패와 상관 없이 가치있고 재미있는 개발을 많이 하면 좋겠다. 현재로서는 Inno Lab이 이러한 성격을 띠고 있다. 그래서 일단은 프로젝트 중 하나인 샘을 성공적으로 런칭하는 것이 나의 목표다.Q. 진짜 마지막 질문. 앞선 질문과 비슷하지만, 개인적인 꿈이 있다면?A. 오래 일하고 싶다. 나이가 들어서도 시장의 흐름을 읽고, 새로운 기술에 대한 충분한 이해와 개발력을 갖춘 사람으로 오래오래 일하고 싶다. 사실 일반적으로 개발자의 수명은 길지 않다. 그래서 창업에 대한 욕심도 품고 있다. 스켈터랩스의 CEO인 테드 님을 보면서 한편으로는 기업 운영 노하우를 배워나간다는 생각도 있다. 향후에는 스켈터랩스의 경쟁사를 내가 세울 수도 있지 않을까(테드 님이 이걸 보면 뭐라하실지 걱정이긴 하다).#스켈터랩스 #사무실풍경 #업무환경 #사내복지 #기업문화 #팀원인터뷰 #팀원소개 #팀원자랑
조회수 1329

개발자의 시간 벌기

Overview지루한 작업은 저와 어울리지 않습니다. 한마디로 귀차니즘이 가득한 개발자입니다. 반복적인 일을 하고 있으면 딴 생각이 많이 떠오릅니다. 특히 개발 과정은 쿼리를 작성하고, 프로그램에 적용하고, 검증하는 일이 자주 발생하는데 필요 이상으로 내 시간을 낭비한다는 생각이 들었습니다. 매번 다시 작업해야 하는 쿼리의 조합을 책상 서랍에 착착! 정리해둔 물건처럼, 코드도 언제든 쓸 수 있게 착착! 준비해두면 시간도 절약되고, 업무도 편리해지지 않을까요. 도대체 최종 결과는....?개발언어를 PHP로 전향하면서 제일 오래 걸리는 부분은 프로그램에서 발생하는 쿼리를 다시 조합하고, 검증하는 작업이었습니다. 프로그램에 사용하는 조건을 체크하고, 대입되는 변수들을 체크하고, 치환할 부분에 넣어주는 작업을 반복해야 하고, 야근하고, 건강 잃고… 쿼리가 정상적으로 조합되지 않으면 어느 부분이 틀렸는지 매번 확인해야 합니다. 이 번거로운 작업을 안드로이드 개발에서 사용하는 logcat 같은 기능으로 만들면 좋을 것 같았습니다. 그래서 PHP용 Log 프로그램을 간단하게 만들기 시작했습니다.Logcat 화면, 한결 보기 편해 보인다. ㅂㄹ개발 컨셉손으로 쓱쓱 그려 보았습니다.PHP 쿼리 요청 코드// sql 디버깅 코드: 쿼리 시작 if (ENVIRONMENT == 'testing') {     if(function_exists('localDebugger')) localDebugger( 'sql_start', "0,".$sql);  } // Run the Query if (FALSE === ($this->result_id = $this->simple_query($sql)))  {     // 소스 생략     if ($this->db_debug)      {              // 소스생략 ...            $this->trans_complete();              // sql 디버깅 코드: 쿼리 에러           if (ENVIRONMENT == 'testing') {               if(function_exists('localDebugger'))  localDebugger( 'sql_error', '0, -- Error  Number: '.$error_no  ."\n--  message: ".$error_msg."\n");           }              // 소스생략 ...      }     return FALSE;  } // 소스 생략 // sql 디버깅 코드: 쿼리 종료 if (ENVIRONMENT == 'testing')  {     if(function_exists('localDebugger')) localDebugger( 'sql_done', ($em + $es) - ($sm + $ss).",");  } PHP 디버그 서버에 요청 코드$callNo = time();           /**           *로컬서버에 디버깅 메세지           * 지정된 서버에 디버깅 메세지 전달           * @access public           * @author BoseungChun           * @param string $message   디버깅할 메세지           */ function localDebugger( $type, $message ) {           global $callNo;           //debugger server           $url = 'http://127.0.0.1:3000';           $ch= curl_init($url);            // 요청 파일 분석           $trace= debug_backtrace();           $fileName= substr( $trace[1]['file'],strrpos($trace[1]['file'], '/') );           $line= $trace[1]['line'];           $fileName2= substr( $trace[2]['file'], strrpos($trace[2]['file'], '/'));           $line2= $trace[2]['line'];             // POST로 로깅 서버에 메세지 전달            curl_setopt($ch, CURLOPT_POST, 1);           curl_setopt($ch, CURLOPT_POSTFIELDS, $callNo.' '.$type.' '.uri_string().' '.$fileName2.':'.$line2."\n".$fileName.':'.$line.' '.$message);           curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);           $response = curl_exec($ch);           curl_close($ch);     } nodejs 일부 코드 // 서버 기동 const http = require('http');   const hostname = '127.0.0.1';  const port = 3000;   const server = http.createServer((req, res) => {       res.statusCode = 200;       res.setHeader('Content-Type', 'text/plain');       var body = '';       req.on('data', function (chunk) {           body += chunk;       }).on('end', function () {           var pos = body.indexOf(' ');           var no = body.substring(0, pos);           body = body.substring(pos+1);           pos = body.indexOf(' ');           var type = body.substring(0, pos);           body = body.substring(pos+1);           pos = body.indexOf(' ');           var uri = body.substring(0, pos);           body = body.substring(pos+1);           pos = body.indexOf(' ');           var file = body.substring(0, pos);           body = body.substring(pos+1);           pos = body.indexOf(',');           addSqlBlock( no, uri, file, body.substring(pos+1), body.substring(0, pos), type );      })      res.end('');  });   server.listen(port, hostname, () => {       console.log('Server running at http://${hostname}:${port}/');   }); // 코드 생략   function addSqlBlock( no, uri, file, sql, ms, type ) {      // UI를 구성해서 코드 블럭를 관리하는 태그에 붙여준다.   } 코드는 위의 코드와 같이 간단한 것들을 사용했습니다. 아래의 이미지는 nodejs를 이용해서 디버깅 메시지를 받을 서버를 만들고, 포트를 열어둔 것입니다. 정리하면 PHP 코드에서 발생하는 쿼리의 최종 내용을 디버깅 서버에 HTTP post 방식으로 전달해주는 구조입니다. 코드는 몇 줄 안 되지만, 꽤나 강력한 도구가 만들어졌습니다."어때요. 참 쉽죠?"짜란~~~ Logger 베타 버전이 도구는 페이지를 요청하는 즉시 쿼리가 잡힙니다. 어떤 페이지 요청에서 어떤 쿼리가 발생하는지 쉽게 분석할 수 있으니 번거롭게 쿼리를 조합하는 과정은 자연스럽게 사라졌습니다.색상으로 쿼리의 속도를 표현했다.이 프로그램의 제작자이지만, 유일한 사용자이기도 합니다. 불편한 게 느껴지면 바로 수정해야 했습니다. 어렸을 때 학습지 좀 풀었던 실력으로 알아서 척척척 스스로 기능을 보강했습니다. 위의 이미지처럼 색상만 추가해도 쉽게 분별할 수 있습니다. 쿼리 실행시간을 추가해 어떤 쿼리가 병목을 잡는지도 빠르게 찾을 수 있습니다.PHP 요청 패스를 넣었더니 개 이득!디버깅에 유용한 정보까지 추가했습니다. 요청된 경로, 쿼리가 실행된 파일의 이름, 라인 위치 모델을 요청한 상위 파일의 이름과 라인 위치를 추가해 트래킹을 보강했습니다. 이쯤 되니 거의 절대반지급입니다. 쿼리 이즈 마이 프레셔스..개발에 필요한 정보들이 노출되니 기쁘지 아니한가!이외에도 현재까지 아래의 기능들을 추가했습니다.쿼리 카피 기능과 신텍스 하이라이트, 쿼리 라인쿼리 에러 메시지 로깅url 요청 단위로 쿼리 묶어주기시간이 지난 쿼리 자동 지우기키워드 검색 기능필요한 걸 직접 만들어 사용하는 것이 귀찮을지도 모릅니다. D.I.Y도 아닌데 말입니다. 하지만 자신의 개발 능력을 활용해 업무 환경을 개선하고, 개선된 만큼의 시간을 다시 투자해 선순환 구조를 만든다면 행복한(?) 개발이 될 거라 생각합니다. (=더 많은 일을 하게 되는 건 안 비밀)오늘은 업무 전, 반복 작업을 개선하면 어떨까요. 참고(사용기술)nwjsPHP (codeigniter)CSS3 + HTML5JQuery글천보성 팀장 | R&D 개발2팀chunbs@brandi.co.kr브랜디, 오직 예쁜 옷만#브랜디 #기업문화 #조직문화 #업무환경 #인사이트 #경험공유
조회수 2313

React + Decorator + HOC = Fantastic!!

React + Decorator + HOC = Fantastic!!지난 포스팅에서는 ES7의 Decorator 문법을 이용해 선언된 클래스와 그 프로퍼티들을 디자인 시간에 변경하는 법을 알아보았습니다. 그렇다면 리액트 컴포넌트와 Decorator가 만나면 어떤 시너지가 발생할까요?만약 ES7의 Decorator에 대해 모르신다면 지난 포스팅을 읽고 오시는 걸 권장합니다. 이 포스팅은 독자들이 Decorator에 대해 이미 알고 있다고 가정하고 작성됐습니다.Higher Order Component리액트 공식 문서를 보면 Higher Order Component(이하 HOC)를 다음과 같이 설명하고 있습니다.리액트 컴포넌트 로직을 재활용할 수 있는 고급 기법리액트에서 공식적으로 제공하는 API가 아니라 단순히 아키텍쳐이 설명으로는 HOC가 어떤 역할을 하는지 이해하기는 역부족이기 때문에 간단한 예제를 통해 HOC를 어떻게 작성하는지 알아보겠습니다.function withSay(WrappedComponent) {     return class extends React.Component {     say() {       return 'hello'     } render() {       return (                   {...this.props}           say={this.say} />       )     }   } } withSay 함수는 WrappedComponent를 인자로 받아 원하는 속성들을 결합해 새로운 컴포넌트를 반환합니다. 이렇게 만들어진 withSay 함수는 아래와 같이 사용 가능합니다.@withSay class withOutSay extends React.Component {     render() {     return (               {this.props.say()}           )   } } withOutSay 컴포넌트는 say 메소드를 가지고 있지 않습니다. 하지만 withSay 함수를 사용하니 say 메소드를 사용할 수 있게 됐습니다. 이처럼 컴포넌트를 인자로 받아 입맛에 맞게 바꾼 뒤 새로운 컴포넌트로 반환하는 기법을 HOC라고 부릅니다.그렇다면 HOC는 리액트에서 어떻게 사용을 해야 효율적일까요?Cross Cutting Concerns개발을 하다 보면 다음과 같은 상황에 직면하는 경우가 종종 있습니다.개발 전반에 걸쳐 반복해서 등장하는 로직그럼에도 불구하고 모듈화가 쉽지 않은 로직예를 들어 방명록 작성, 게시글 작성, 게시글 스크랩을 하는 컴포넌트들에서 유저 인증과 에러 처리의 과정이 필요하다고 했을 때 어떻게 코드를 디자인해야 할까요? 컴포넌트와 직접적으로 연관이 없는 기능들이 컴포넌트와의 결합이 너무 강해 쉽게 모듈화를 시키지 못합니다.그림 1. Cross Cutting Concerns의 예시이렇듯 코드 디자인적인 측면에서 공통적으로 발생하지만 쉽게 분리를 시키지 못하는 문제를 Cross Cutting Concerns라고 합니다. 이 문제를 끌어안고 가면 프로젝트의 코드는 쉽게 스파게티가 되고 나중에는 유지 보수를 하기 힘들어집니다.하지만 우리게에는 HOC와 Decorator가 있고 이를 이용해 이 문제를 쉽게 해결할 수 있습니다.유저 인증 문제를 HOC로 해결아래는 인증이 안된 유저에게 다른 페이지를 보여주는 코드입니다.class TeamChat extends React.Component {     constructor() {     super()     this.state = {       unAuthenticated: false     }   } componentWillMount() {     if (!this.props.user) {       this.setState({ unAuthenticated: true })     }   } render() {     if (this.state.unAuthenticated) {       return     }     return I'm TeamChat   } } 유저 인증을 전통적인 if-else 구문으로 구현했습니다. 당장 이 컴포넌트를 본다면 문제가 없어 보입니다. 어떻게 보면 정답처럼 보이기도 합니다. 하지만 유저 인증이 필요한 컴포넌트가 많아지면 상황이 달라집니다.100개의 컴포넌트에서 위와 같은 방식으로 유저 인증을 하고 있는데 유저 인증을 하는 로직이 변경된 상황을 생각해 봅시다. 100개의 컴포넌트 모두 유저 인증 코드를 바꿔야 하는 상황에 직면하게 됩니다. 전부 다 바꾸는 것도 일이지만 실수로 몇 개의 컴포넌트를 수정하지 않을 확률이 농후합니다. 당장에는 간단하지만 잠재적 위험을 안고 있는 위 코드는 아래와 같이 수정되어야 합니다.function mustToAuthenticated(WrappedComponent) {     return class extends React.Component {     constructor() {       super()       this.state = {         unAuthenticated: false       }      } componentWillMount() {       if (!this.props.user) {         this.setState({ unAuthenticated: true })       }     } render() {       if (this.state.unAuthenticated) {         return       }       return     }    } } HOC를 이용해 확장이 용이한 유저 인증 로직이 탄생했습니다!! 이렇게 만들어진 HOC는 아래와 같이 적용이 가능합니다.@mustToAuthenticated class TeamChat extends React.Component {     render() {     return I'm TeamChat   } } @mustToAuthenticated class UserChat extends React.Component {     render() {     return I'm UserChat   } } 기존의 코드와 비교했을 때 코드가 훨씬 간단해진 것을 확인할 수 있습니다. 비단 코드만 간단해진 것뿐만 아니라 아래와 같은 추가 효과를 기대할 수 있습니다.유저 인증 로직이 컴포넌트와 분리가 되어 자신이 맡은 역할에만 집중할 수 있습니다.유저 인증 로직이 바뀌어도 코드를 수정해야 할 곳은 하나의 컴포넌트뿐입니다.예시로 작성한 HOC는 최소한의 코드로만 작성된 예시입니다. 실제 제품에서 사용되기 위해서는 몇 가지 고려해야 할 사항이 있는데 이는 리액트 공식 문서를 참고해주세요.i18n 컴포넌트를 HOC로 작성채널 서비스는 한국어, 영어, 일본어를 지원하기 때문에 번역 기능이 필요했습니다. 초기에는 번역 서비스를 아래와 같이 구현했습니다.@connect(state => ({   locale: getLocale(state) }) class Channel extends React.Component {     render() {     const local = this.props.locale     const translate = TranslateService.get(locale)     return (               {translate.title}         {translate.description}           )   } } 처음에는 위와 같은 방식으로 번역 서비스를 구현하는 것이 괜찮았습니다. 하지만 번역을 제공해야 하는 컴포넌트가 많아지면 많아질수록 중복되는 코드가 많아지는 것을 보고 아래과 같이 HOC를 이용해 코드의 중복을 제거했습니다.function withTranslate(WrappedComponent) { @connect(state => ({     locale: getLocale(state)   }))   class DecoratedComponent extends React.Component {     render() {       const locale = this.props.locale       const translate = TranslateService.get(locale) return (                   {...this.props}           translate={translate} />       )    }   } } 이렇게 작성된 HOC는 아래와 같이 사용이 가능합니다.@withTranslate class Channel extends React.Component {     render() {     const translate = this.props.translate     return (               {translate.title}         {translate.description}           )   } } HOC의 작성 방법은 예시로 작성한 두 개의 HOC에서 크게 벗어나지 않습니다. 이를 응용해 자신의 프로젝트에 맞는 코드를 작성해보세요.중첩 가능한 HOCHOC는 여러 개를 중첩해서 사용할 수 있습니다.. 예를 들어 유저 인증과 i18n 서비스를 동시에 제공하고 싶을 때 두 HOC를 중첩해서 사용하면 됩니다.@mustToAuthenticated @withTranslate class Channel extends React.Component {     render() {     return (               {`Hello!! ${this.props.user.name}`         {translate.title}         {translate.description}           )   } } 마무리이상으로 리액트에서 HOC를 사용할 수 있는 상황과 작성 방법을 알아보았습니다. 본 포스팅에서 다루지는 않았지만 만능처럼 소개한 HOC에도 몇 가지 단점은 존재합니다.Component Unit Test를 할 때 문제가 있을 수 있습니다.HOC를 몇 개 중첩하면 디버깅이 힘들 수 있습니다.WrappedComponent에 직접적으로 ref를 달 수 없어 우회 방법을 사용해야 합니다.비동기 작업과 같이 사용하다 보면 예상치 못한 결과를 만날 수 있습니다.하지만 이러한 단점에도 불구하고 상속을 제공하지 않은 리액트에서 HOC는 많은 문제를 효율적으로 해결해주는 단비와 같은 존재입니다. 유명한 리액트 라이브러리들(react-redux, redux-form 등)은 이미 예전부터 HOC를 사용해 사용자들에게 편의를 제공해 왔습니다. 이러한 라이브러리들과 자신의 프로젝트가 직면하고 있는 문제에 맞는 HOC를 작성해 같이 사용한다면 우아하고 아름다운 설계에 한층 더 다가간 프로젝트를 발견할 수 있습니다.마지막으로 한 문장을 남기고 본 포스팅을 마치도록 하겠습니다.React + Decorator + HOC = Fantastic!!본 포스팅은 2017 리액트 서울에서 발표한 내용입니다. 발표 자료와 발표 영상을 확인해보세요.#조이코퍼레이션 #개발자 #개발팀 #인사이트 #경험공유 #일지

기업문화 엿볼 때, 더팀스

로그인

/