스토리 홈

인터뷰

피드

뉴스

조회수 1492

내가 좋은 팀을 찾을 수 있었던 이유

"퇴사학교 입사 전 구직 활동 중에 작성한 글입니다"<나의 일/ 조직 선택 가치관>일을 선택할 때 고려해볼만한 여러 요소가 있다. 내가 그동안 떠오른 것들을 쭉 적어보자면,-기업이 추구하는 가치, 비전, 미션-조직 문화-내가 맡을 직무 내용과 특성-대표의 경영 철학 (내부 경영)-기업의 성장 가능성 (시장, 비즈니스 모델 등)-개인의 성장할 수 있는 환경-현재 재정 상황 (매출, 투자 유치 등)-급여-팀원 역량-인지도-복지-체계 (진급, 연봉 등)이 각각의 요소마다 <내가 원하는 기준>이 또 있다. 그러나 절대 <이 모두가 나와 맞는 곳>을 찾을 수 없다고 생각한다. 그냥 적기만 하면 내가 다 원하는 사람으로 보여서 분명하게 적지만, 위에 적은 것은 <나의 우선순위> 대로 재정렬해 위에서부터 나열한 것이다. 내가 일/조직을 선택할 때 가장 중요한 한 가지만 꼽자면 <추구하는 가치와 비전> 이다. 무엇을 위해 일하는지, 왜 일을 하는지가 중요한 나는 나의 비전과 최대한 비슷한 비전을 추구하는 조직을 찾고싶다. 비전이 비슷하면 어떤 일이든 해낼 의지가 있다. 기업이 추구하는 비전은 내가 맡을 일의 내용보다 더 중요한 가치다. (아직 내가 추구하는 가치를 혼자 실현할 역량이 부족하기에 비슷한 비전을 가진 팀과 동료를 찾고 있다. 적극적으로 찾고 먼저 두드리고 있다.)기업을 보다가 1순위인 비전이 나의 비전과 조금 덜 비슷한 곳이라면 조직문화를 살펴보고, 비전과 조직문화가 덜 맞는 곳이라면 직무 내용과 특성 또는 기타 아래의 것들을 살펴보는 셈이다. 그리고 이런 대부분의 상위권 요소들에는 <절대 포기하고 싶지 않은 최저치>가 있다. 곧 커리어 선택일지를 연재물로 쓸 생각이지만 생각이 명료하게 정리되어 누군가에게도 도움이 될 것 같아 일단 올려본다. 요즘 커리어를 찾아가는 과정을 공유하다보니 개인 메시지로 자세하게 물어보시는 분들도 생겼다. 내가 추구하는 비전과 비슷하거나 같은 비전을 추구하는 대표님들과의 캐주얼 미팅을 몇 번 진행했고, 오늘도 앞두고 있다. 비전, 조직문화 등을 포함해 궁금한 것을 꼼꼼하게 물어보고 와야겠다
조회수 819

앱 어트리뷰션 가이드 - 입문

앱 어트리뷰션 툴은 앱 마케팅의 필수 도구로 자리잡았고 갈수록 활용범위가 증가하고 있습니다. 그러나 툴을 사용하는 현장에서는 ‘어렵다’라는 반응이 여전합니다. 그래서 이번 ‘앱 어트리뷰션 가이드 (A Walkthrough of App Attribution)’에서는 툴 유저들이 공통적으로 느끼는 어려움을 해소할 수 있는 내용을 다뤄보려 합니다.가이드는 어트리뷰션과 연관된 주요 개념과 기술에 대한 설명을 주로 다루게 됩니다. 이를 통해 어트리뷰션 툴이 필요할 수 밖에 없는 이유와 애드테크 생태계에서의 역할, 그리고 복잡한 어트리뷰션 기능들이 왜 필요하며 어떤 원리로 동작하는지에 대한 이해를 높이는 것이 목적입니다.첫번째 글인 ‘앱 어트리뷰션 가이드 – 입문’에서는 어트리뷰션 툴이 등장하게 된 배경과 문제 해결 방법을 설명합니다. 등장 배경: 과금 기준이 다르다웹에서 집행하는 키워드 광고를 클릭하면 바로 웹사이트로 연결되고 사이트에 방문한 상태가 됩니다. 광고 클릭 자체가 사이트 방문인 셈입니다. 광고 클릭이 트래픽을 늘려 주었으니 클릭당 비용(Cost Per Click, CPC)을 지불하는 것이 합리적입니다.그러나 앱 광고를 클릭하면 앱이 열리지 않습니다. 스토어를 거쳐 단말기에 앱을 설치한 후 실행까지 해야 앱을 방문한 상태가 됩니다. 결국 광고 클릭이 앱의 트래픽을 직접적으로 늘려주지 못하며, 설치된 앱이 실행 되어야만 트래픽이 늘어납니다. 그래서 설치된 앱의 최초 실행수(Cost Per Install, CPI)를 기준으로 비용을 지불하는 것이 합리적입니다.트래픽을 늘려준 액션에 광고비를 지불하는 것이 합리적이다. 그래서 앱은 CPC가 아닌 CPI를 사용한다.이런 이유로 CPI는 앱 생태계의 광고비 과금 기준으로 자리잡습니다. 하지만 기준을 CPI로 변경하는 초기에는 장애물이 있었습니다. 광고를 통해서 몇 개의 앱이 설치 되었는지를 정확하게 알 수 없었기 때문입니다. 앱 설치 숫자를 확인하는 것은 간단한 일인데 왜 문제가 되는지 의문을 가질 수도 있겠지만, 조금 깊이 들여다보면 생각보다 어려운 문제임을 알 수 있습니다.우선 전체 앱 설치 중에 광고를 통한 설치가 몇 건인지 분리해 내기가 쉽지 않습니다. 플레이 스토어나 앱스토어에서 그날 그날의 설치 개수를 확인할 수 있지만, 그 중에 몇 개가 유료 광고로 인한 설치인지는 보여주지 않기 때문입니다. 이렇게 되면 광고 매체에 확인해 볼 수 밖에 없습니다.하지만 매체 역시 앱 설치 개수를 모르는 것은 마찬가지 입니다. 매체는 자신이 관리하는 영역에서 클릭이 발생한 것을 감지함으로써 유저가 광고를 클릭하고 스토어로 넘어간 것은 알 수 있으나, 스마트폰에서 앱이 실행되는 것은 매체의 관리 영역 바깥의 일이므로 유저가 클릭 이후에 앱을 받아서 실행을 했는지 그렇지 않은지는 분명하게 알 수 없습니다. 결국 광고주와 매체 모두 광고를 통한 앱 설치 숫자를 알지 못하기 때문에 CPI를 기준으로 광고비를 산정할 수 없는 문제가 남게 됩니다. 어트리뷰션 툴이 문제를 해결하는 방법이 문제를 해결하기 위해 등장한 것이 앱 어트리뷰션 툴입니다. 어트리뷰션 툴의 핵심 역할 중 하나는 성공적으로 설치된 앱들 중에서 광고의 영향을 받은 앱 설치가 얼마나 되는지를 측정해 내는 일입니다. 광고주와 매체 모두 정확하게 측정할 수 없었던 이 수치를 어트리뷰션 툴이 어떤 방법으로 측정하는지를 요약하면 다음과 같습니다.1. 트래킹 URL 활용유저에 의해 광고가 클릭 되는 것을 분석하기 위해 광고물에 트래킹 URL을 세팅합니다. 트래킹 URL이 설정되어 있는 광고를 유저가 클릭하게 되면, 어트리뷰션 툴은 어떤 매체의 광고가 언제 누구로부터 클릭 되었는지를 알 수 있게 됩니다. 어트리뷰션 툴은 이 정보를 측정한 뒤 유저를 앱 설치 페이지로 리다이렉트 시킵니다.2. 분석 SDK를 앱에 삽입설치된 앱이 실행까지 되는지를 분석하기 위해서 앱 자체에 분석 도구를 삽입합니다. 분석 SDK는 앱의 네이티브 영역(OS의 언어로 작성되었으며 앱의 구조를 이루는 부분)에 적용하며 앱이 실행되는 시점에 함께 동작하는 것이 장점입니다. 앱 실행 직후에 분석 SDK가 동작함으로써 앱 실행에 영향을 준 트래픽 소스(광고인지 아닌지, 광고라면 어떤 매체인지)를 검출하게 됩니다.3. 클릭 데이터와 실행 데이터를 대조광고를 통해 앱이 설치(또는 실행)되었는지를 정확하게 확인하기 위해 1번의 클릭 데이터와 2번의 실행 데이터를 대조합니다. 클릭 데이터를 통해서는 누가 언제 어떤 매체를 클릭 했는지를 알 수 있으며, 실행 데이터를 통해서는 누가 언제 어떤 매체로 유입되어 앱을 실행 했는지를 알 수 있습니다. 따라서 클릭 데이터와 실행 데이터가 정확하게 일치하는 경우에는 광고를 통한 앱 설치로 판단하게 됩니다.어트리뷰션 툴 사용자가 트래킹 URL을 만들어서 배포하는 일, 앱 개발자가 분석 SDK를 앱에 삽입하는 일, 트래킹사가 데이터를 대조하여 리포팅 하는 일 모두가 결국 광고를 통한 앱 설치를 분류해 내기 위해서 반드시 필요한 작업입니다. 어느 하나라도 부족하면 정확한 측정이 어려울 수 밖에 없겠지요.다음 글에서는 어트리뷰션의 한 축을 담당하는 트래킹 URL에 대해서 알아보도록 하겠습니다.
조회수 1125

커피, 와인 그리고 투자

요즘 날씨가 좋다. 따뜻한 봄날이다.  얼마 전 회사 동료들과 점심을 먹고 날씨를 만끽하며 잠깐 산책을 하고는 커피숍으로 향했다. 너무도 당연한듯한 발걸음으로 말이다.지난해(2016년) 우리나라 국민의 커피 소비량은 약 250억 잔이라고 한다. 국민 한 사람당 약 500잔을 마셨단다. 하루에 2잔 정도 마신 것이다. 불과 몇 년 전까지 커피를 전혀 마시지 않았던 내가 하루에 2잔은 마시고 있는 듯하니 통계가 얼추 맞는 듯하다.많은 사람들이 커피를 즐기게 됐다. 커피가게는 동네 구석구석까지 생겨났다. 내가 일하는 회사 근처에도 수십 개의 커피가게가 있다. 브랜드가 있는 가게, 프랜차이즈부터 개인이 하는 곳까지 형태도 맛도 다양하다. 아메리카노 한잔 가격이 몇천 원부터 1,500원까지 가격도 다양하고 맛도 다양하다. 편의점에서 파는 1,200원짜리 커피도 나쁘지 않다. 거꾸로 고급화 전략으로 나가는 곳들도 있다. 너무 다양해 맛을 구분하기는커녕 이름을 외우기도 어렵다.통계적인 근거를 찾아보진 않았지만 고급화, 다양화한 커피집이 오히려 장사가 잘 되는 것 같기도 하다. 사람들은 맛있는 커피를 마시고 싶지만, 커피를 공부하고 싶어 하진 않는다. 누가 알아서 추천해주면 그냥 그걸 마신다.비슷한 경험이 또 있다. 지인 중에 와인 강의를 하시는 분이 있다. 그 분과의 저녁 모임은 즐겁다. 음식에 어울리는 다양한 와인을, 음식 순서에 맞춰 마시면 그 맛이 일품이다. 굳이 비싼 와인이 아니어도, 입의 즐거움은 부족하지 않다. 그에 곁들여지는 와인에 대한 설명은 맛을 한층 업그레이드한다.잠시 와인을 공부해본 적이 있다. 책을 사서 봤는데, 반쯤 읽다 말았던 기억이 있다. 와인에 대한 애정이 부족했거나, 혹은 다른 이유가 있었을거다. 좋아는 하지만, 공부하고 싶진 않았다.그냥 소주와 맥주로 회귀했다. 투자 역시 커피나 와인에서의 경험과 다르지 않다.사람들은 돈을 벌기 위해 직장을 다니거나 사업을 한다. 애써 모은 돈을 어떻게 해야 할지 모르는 사람들이 많다. 돈을 좋아하긴 하지만, 돈을 공부하고 싶진 않은 것이다. 커피나 와인을 공부하고 싶지 않은 것과 같다.누군가가 나 대신 공부해서 알아서 굴려주면 좋겠다 싶은 것이다. 이러한 사람들의 습성이 변하진 않을 것이다. 커피나 와인은 기호품이지만, 돈은 기호품이 아닌데도 그렇다.남의 손을 빌리면 돈이 든다. 그 '남'에게 수고비를 줘야 하는 것이다. 돈을 굴려주는 값을 치러야 한다.가장 대표적인 게 펀드다. 돈을 모아 굴려주는 펀드에 사람들이 돈을 넣는다. 나보다는 더 잘할 것이라는 기대 때문이다. 펀드에 들어가는 수수료는 결코 싸지 않다. 1~2%의 수수료를 받아 가지만, 그 수수료 이상의 수익을 매년 주지는 않는다. 수익과 상관없이 수수료를 받아 간다. 좋은 커피와 와인을 즐기기 위해 공부를 해야 하듯이, 돈 역시 좋은 수익을 위해서는 공부를 해야 한다. 하지만 모든 사람이 공부를 좋아하는 것도 아니요. 돈을 공부하지도 않는다. 결국 아무 커피나 마시듯 아무렇게나 돈을 놔둔다. 실질금리 마이너스 시대에 돈을 예금에만 넣어두는 것은 돈을 잃는 행위다. 몰라서 놔두는 경우가 대부분이고 나머지는 귀찮아서 그렇다.커피나 와인은 대충 아무거나 마셔도 상관없을 수 있다. 하지만, 애써 모은 내 돈을 아무렇게나 굴려도 되겠는가? 생각 외로 안전한 투자법도 많다. 조금은 공부를 하자.
조회수 3231

JANDI CONNECT 개발기

지난 1월 말, 새해를 맞아 잔디에 새로운 기능이 업데이트되었습니다. 바로 잔디 커넥트에 관한 내용인데요, 협업에서 많이 쓰이는 몇 가지 외부 서비스를 잔디와 쉽게 연동해서 더욱 효율적인 업무 커뮤니케이션을 할 수 있게 되었습니다. 많은 고객분들이 이번 업데이트를 기다려주신 만큼, 저희 개발팀 또한 기대에 보답하고자 지난 몇 주의 스프린트 동안 열심히 준비했습니다. 이번 글에서는 커넥트 동작 방식을 설명하고 그 개발 과정에서 저희가 겪은 시행착오를 비롯한 여러 값진 경험들을 공유하고자 합니다.Integration? Webhook!연동: [기계] 기계나 장치 따위에서, 한 부분이 움직이면 다른 부분도 함께 잇따라 움직임.앞서 말한 대로 잔디 커넥트는 여러 웹 서비스들과 잔디를 연동할 수 있는 기능입니다. 서로 다른 웹 서비스를 연동하기 위해선 한 서비스 내에서 특정 이벤트가 발생 했을 때 다른 서비스로 해당 이벤트를 알려주는 연결 고리가 필요합니다. 이때 해당 연결 고리 역할을 위해 대표적으로 사용되는 기법이 웹훅(WebHook) 입니다. 웹훅은 user-defined HTTP callbacks, reverse APIs 등으로 불리는데, 간단히 설명하자면 웹 서비스에서 공개한 API가 아닌 사용자가 직접 지정한 주소(URL)로 특정 이벤트가 발생 시 HTTP Request를 보내주는 기법입니다. 예를 들어,새로운 일정이 등록된 경우(Google Calender)요청한 Pull Request가 Merge된 경우(GitHub)카드에 새로운 코멘트가 작성된 경우(Trello)이러한 이벤트가 발생했을 때 사용자가 매번 이벤트가 발생했는지 확인하지 않아도 서비스가 먼저 알려줄 수 있도록 일종의 알림을 등록하는 것이죠. 잔디 커넥트는 이와 같은 특징을 이용해서 각각의 웹 서비스에서 제공하는 웹훅을 잔디의 메시지 형태로 전달하는 기능입니다.일반적으로 웹훅은 이벤트에 대한 알림을 외부로 전달하는 것을 말합니다. 이 부분에서 중요한 것은 전달 방향인데, 서비스 내부에서 외부로 전달하기 때문에 이를 Outgoing Webhook으로 부르기도 합니다1. 같은 맥락에서 반대로 생각해보면 외부에서 서비스 내부로 특정 데이터를 전달하는 경우이니 Incoming Webhook이 됩니다. 앞서 웹훅을 reverse API라고 했는데 이를 다시 뒤집으니 결국 서비스 내부로 통신하는 제한적인 API와 같은 역할을 합니다. 굳이 용어를 구분한 이유는 API와 달리 접근하려는 서비스의 별도 인증 절차를 거치지 않고도 사용자가 생성한 웹훅의 URL을 인증 토큰으로 사용하며 약속된 Request Body 포맷만 알고 있다면 자유롭게 사용할 수 있기 때문입니다.개념 설명이 다소 길어졌지만, 이번 잔디 커넥트 기능에 대해 용어나 개념이 낯설다는 피드백이 생각보다 많았기 때문에 이번 글을 통해 더 많은 분들이 웹훅을 이해하는 데 도움이 될 수 있으면 좋겠습니다.구현에 앞서서비스를 운영한지 1년 정도 지난 시점에서 저희 내부적으로는 백엔드의 기술 스택 변경 및 각 서비스 분리에 대한 갈증이 있었습니다. 하지만 이미 서비스를 운영 중이기 때문에 안정성이 최우선시 되는 만큼 꽤 부담스러운 숙제로 미뤄둘 수밖에 없었고요. 때마침 커넥트 기능은 숙제를 시험해볼 만한 좋은 기회임에는 분명했지만, 새로운 기술 스택을 바로 서비스에 적용하기엔 오히려 개발 효율이 떨어질 것이라는 판단하에 일단 서비스 분리에만 집중하기로 했습니다.기본적으로 API와 DB를 기존 서버와 분리하고 웹훅 데이터를 저장하기 위한 큐와 해당 데이터를 처리하는 배치 서버 또한 모두 기존 서비스와 분리해서 최대한 결합도를 제거했습니다. 이런 설계 덕분에 추후 사업 전략이나 각 국가의 특성에 맞춰 커넥트 기능을 어렵지 않게 포함하거나 제외할 수 있게 되었습니다. 전반적인 저희 잔디 백엔드 아키텍쳐에 대해서는 아직 한 번도 소개 해드린 적이 없으니 다음에 따로 주제로 선정해 집중적으로 다뤄보도록 하겠습니다.동작 방식잔디 커넥트가 동작하는 방식은 기본적으로 다음과 같습니다.Incoming Webhook URL 생성 - 외부 서비스 웹훅 등록 - 웹훅 수신 - 메시지 작성 연동 대상 서비스마다 조금씩 차이가 있지만, 기본적으로 모두 위와 같은 방식으로 동작하기 때문에 단계마다 나누어 설명하겠습니다.1. Webhook URL 생성Webhook URL은 https://wh.jandi.com/connect-api/webhook/{teamId}/{webhook-token}와 같은 형태로 생성됩니다. hostname을 별도로 설정함으로써 기존 API 서버와의 분리는 물론이고, nginx의 Limiting the Request Rate 설정을 이용해서 호출되는 웹훅 요청 수를 효과적으로 제한할 수 있었습니다. webhook-token은 중복을 피하면서 각 웹훅에 대한 유효성을 검증할 수 있도록 여러 키를 조합한 md5 hash 값을 이용했습니다.이렇게 생성된 URL은 Incoming Webhook 뿐만 아니라 Google Calendar 등의 서비스에 등록하는 콜백 URL로 사용합니다.2. 외부 서비스 웹훅 등록웹훅을 등록하는 방법은 서비스에 따라 API를 이용하거나 수동으로 직접 등록할 수 있습니다. 사용자가 직접 웹훅을 등록하는 방법은 웹훅 URL만 생성해서 전달하면 등록 과정의 추가 처리가 필요 없어서 간단하지만, 서비스마다 등록하는 방법이 조금씩 다르고 다소 복잡하게 느껴지는 문제가 있습니다. 반대로 각 서비스에서 제공하는 API를 이용해 웹훅을 등록하면 사용자의 부담을 많이 줄일 수 있지만, 그만큼 내부적으로 처리해야 할 작업이 많아집니다. 그래서 구현 초기에 꽤 많은 시간을 투자할 수밖에 없었고 그 과정에서 아래와 같은 어려움을 겪었습니다.웹훅 관련 API를 사용하려면 먼저 인증을 받아야 하는데 서비스마다 제공하는 인증 방식이 조금씩 달라서 이를 통합하는 모델을 만들기가 쉽지 않았습니다. 요약하자면 기본적으로 accessToken을 사용하지만, 인증 방식에 따라 부가적으로 필요한 데이터가 서로 조금씩 다른것이죠. 가령, 구글캘린더는 만료 일시와 토큰 갱신을 위한 refreshToken 값을 별도로 갖고 있어야 합니다. 또 한가지 놓치기 쉬운 부분은 인증 폐기(revoked) 관련한 데이터 처리인데 저희가 경험한 바로는 인증이 폐기되었을 때 별도로 웹훅 알림을 주지 않기 때문에 반드시 인증의 유효성을 확인하는 추가 로직이 필요합니다.대부분의 사무실이 그렇듯이 저희 또한 공유기를 이용해 내부 네트워크를 구성하고 있습니다. 게다가 백엔드 파트는 개개인의 로컬 가상 서버에 동일한 환경을 설정해놓고 개발을 하므로2보통 경우엔 외부(public network)에서 들어오는 요청을 받을 수 없습니다. 그렇다고 매번 외부 네트워크에 있는 서버에 배포 후 테스트하기가 어려우니, 저희는 각 로컬 서버마다 고유 포트 번호를 나눠 갖고 WAN이 물린 공유기의 포트 포워딩을 알맞게 설정한 뒤에 네트워크 터널링 유틸리티인 ngrok을 이용해 내부와 연결되는 public 주소를 생성해서 외부 서비스와 문제없이 통신할 수 있었습니다.3. 웹훅 수신웹훅을 통해 들어오는 Request는 일단 정상 응답을 하는 게 좋습니다. 서비스마다 최초 웹훅 등록 시 유효한 URL인지 확인하는 테스트 요청을 하는데 이때 정상 응답을 하지 못하면 아예 등록조차 처리되지 않습니다. 또한, 정상적으로 등록된 이후 특정 이벤트에 해당하는 웹훅 요청에 대한 응답에도 주의할 필요가 있는데, 만약 에러 응답이 반복되면 일정 시간 동안 각 서비스에서 아예 해당 웹훅을 발송하지 않도록 제한이 걸려 더 이상 테스트를 진행할 수 없는 경우도 있었습니다.따라서 일단 웹훅 요청이 들어오면 teamId와 webhook-token 값으로 올바른 웹훅인지 검증한 후 서비스별 큐에 Request header와 body를 포함한 데이터를 전달한 뒤 바로 응답하고, 큐에 쌓인 데이터는 커넥트 종류별로 배치 서버가 돌면서 처리하게 됩니다. SQS를 사용함으로써 늘어나는 데이터에 대한 안정성을 확보하고 각각의 배치 서버를 독립적으로 분리해서 구현함으로써 자연스레 확장성(scalability)도 보장할 수 있게 되었습니다.4. 메시지 작성웹훅 데이터를 잔디의 메시지로 변환하는 역할은 배치 서버가 담당합니다. 서비스별로 데이터 포맷이 다르므로 해당 데이터를 파싱 및 처리하는 Worker 또한 각각 구현했습니다. 사실 커넥트 기능에서 가장 핵심적인 역할을 하는 부분인 만큼 가장 많은 공수가 드는 작업이였던 것 같습니다.서비스마다 정해놓은 웹훅 이벤트와 잔디 커넥트에서 제공하고자 하는 알림이 서로 완전히 일치하지 않아서 이를 서로 연결하는 작업연동 서비스의 문서가 잘 정리되어 있지 않아서 일일이 필요한 동작을 취하고 그에 따라 들어오는 데이터를 정리하는 작업잔디 계정 언어에 따라 메시지 L10N3을 적용하는 작업커넥트 메시지를 전달하기 위해 기존 멤버와 다른 커넥트 봇을 구현하는 작업등 요약하기 어려울 정도로 크고 작은 이슈들이 많았습니다. 그 내용이 너무 다양해서 모두 상세히 기록하긴 어렵지만, 개중에 도움이 될만한 내용을 추려서 아래 따로 정리했으니 관심 있으신 분들은 참고하시면 좋을 것 같습니다.서비스별 집중 탐구커넥트 구현 일정을 최대한 앞당기기 위해 저희는 개발자들끼리 각각의 커넥트 종류 별로 전담해서 작업하는 전략을 취했습니다. 제가 대표로 글을 작성하기는 하지만 보다 정확하고 구체적인 정보를 전달하는 것이 좋겠다는 생각에 개발을 담당하신 분들과의 짧은 인터뷰 형식을 빌려 공유하겠습니다.- Google CalendarQ. 기술적으로 난이도가 높았던 작업을 소개해달라.전반적으로 어려운 작업이 있었다기보단, 캘린더 특성상 세세하게 처리할 부분들이 많아 설계와 구현이 어쩔 수 없이 복잡해졌다. 가장 골치 아팠던 작업은 일정 알림을 타임존(Time Zone)에 따라 각각 알맞은 시간에 전달하는 작업인데, “잔디 계정의 타임존”, “구글 캘린더의 타임존”, “개별 일정의 타임존” 이렇게 3가지를 모두 고려해서 경우마다 기준이 되는 타임존을 결정하는게 엄청 까다로웠다. 심지어 구현 후 테스트를 하는 과정에서도 출력된 시간이 올바로 표시된 것인지조차 헷갈려서 디버깅하는데 한참 고생할 수 밖에 없었다.웹훅을 등록하고 관리하는 부분도 꽤 복잡했는데, 구글 답게(?) 웹훅에도 만료 기간이 존재한다는 것이 포인트다. 때문에 만료되기 전에 반드시 재등록 및 과거 웹훅 삭제 작업을 하는데, 효과적으로 처리하기 위해 “웹훅을 받을 때마다 만료 기간을 확인”, “등록된 일정이 많지 않아 웹훅을 받지 못하는 경우도 있으니 별도의 배치서버가 하루 단위로 확인” 이렇게 두 가지 로직을 넣어서 자동으로 웹훅을 유지하도록 구현했다.또한, 다른 연동 서비스와 달리 구글은 웹훅 콜백으로 들어오는 요청에 해당 이벤트에 대한 데이터를 직접 담아주지 않기 때문에 key를 가지고 한 번 더 API 호출을 통해 필요한 데이터를 가져와야 한다는 점도 주의해야 한다. 요청해야 할 API 문서는 비교적 잘 정리된 편이지만, 같은 요청에 대해서도 인자를 어떻게 보내는지에 따라 그 응답이 제각각이기 때문에 응답 값에 대해 무조건 신뢰하고 처리해서는 안 된다. 당연히 존재할 것으로 생각한 필드 값에 빈 배열이 들어와서 일정 관련된 데이터를 일부 날리고 나서야 깨달았다.. -_-Q. 가장 처리해야 할 이슈가 많았다고 알고 있는데, 그중에서도 기억에 남는 이슈가 있을 것 같다.너무 많은 이슈를 동시에 처리하다 보니 특별히 기억에 남는 이슈는 없다. 다만 아직도 왜 그랬는지 확실한 이유는 알 수 없지만, 언젠가 한 번 구글에서 웹훅을 아예 전달해주지 않았던 경우가 있었다. 과도한 요청으로 limit이 걸린 것도 아니었는데, 갑자기 웹훅이 안들어오니깐 우리로서는 어떻게 풀어볼 방법이 없었다. 그러다 나중에 확인해보니 대략 12시간쯤 지나고 나서 그동안 밀려있던 웹훅 데이터가 한 번에 밀려서 들어와 있더라. 다행히 그 이후로 지금까지 한 번도 재현되지 않는걸 보니, 혹 동일한 증상을 겪는다면 당황하지 말고 기다려 보시라.반복 일정을 다루는 것도 꽤 골치 아픈 이슈인데, 왜냐하면 일정이 있을 때 마다 웹훅 알림을 주지 않고 처음 등록된 시점에서 한 번만 정보를 알려주기 때문에 등록된 시점 이후의 일정은 내부적으로 계속 등록해줘야 한다. 기본적으로 구글 캘린더는 RFC-55454 표준을 따르지만, 실제 전달되는 데이터 중 일부는 표준과 조금 다른 부분이 있었다. 특히 반복 일정(recurrence) 관련 데이터 포맷이 조금 다르므로 캘린더 데이터를 파싱하기 위해 만약 외부 library를 사용한다면 별도의 예외처리가 필요하다. 더욱 더 까다로운 건 사실 등록된 반복 일정이 수정되거나 삭제되는 경우인데, 이때 “특정 일정만 삭제”, “지금 시점 이후의 일정 모두 수정” 등 워낙 케이스도 많고 각각을 테스트 하는 것도 쉽지 않기 때문에 작업 시간이 꽤 오래 걸렸다. (심지어 아직 확인하지 못한 드문 케이스에서는 잠재된 버그가 있을 수도…)Q. 그 밖의 도움이 될만한 노하우나 꿀팁이 있다면?구글 캘린더 API는 Webhook 보단 Push Notification 키워드를 많이 사용한다. 푸시 노티라는 게 좀 다른 카테고리에서 많이 쓰이는 용어이기도 하다 보니 코드 리뷰 등의 커뮤니케이션을 할 때 혼동이 좀 있었던 것 같다.물론 서비스 요구사항마다 다르겠지만, 잔디 같은 경우엔 요구사항에 맞춰 계속 설계를 변경 및 개선하다 보니 결과적으로 너무 복잡해져 효율이 떨어지는 코드를 작성할 수밖에 없었다. 처음부터 연동을 생각하기보다는 아예 캘린더 자체 기능을 베이스로 설계하고 데이터만 구글에서 가져온다 생각했다면 개발 생산성이 더욱 좋았을 것 같다.- TrelloQ. 기능을 구현하면서 느낀 아쉬웠던 점과 좋았던 점을 짚어달라.트렐로 공식 API 문서가 더 명확했다면 좀 더 개발이 수월했을 것이다. 문서가 RESTful하게 end-point path는 간결하게 잘 정돈되어 있지만, 각 요청 parameter에 대한 설명이나 response 데이터 등이 명확하게 정리되지 않아서 적합한 API를 찾거나 불명확함을 걷어내기 위한 테스트를 하다 보니 전반적으로 시간이 길어지고 비효율적이었던것 같다.그에 반해 트렐로에서 웹훅 이벤트를 발생시키기 위한 유저 액션들이 비교적 간단하고, 그에 따른 콜백 리퀘스트 또한 누락 없이 빠르게 잘 들어와서 그나마 쉽게 테스트를 할 수 있었다.Q. 기능 구현을 위해선 반드시 알아야 할 웹훅 이벤트 종류 및 데이터에 대한 문서는 정리가 전혀 안 되어있다고 하던데 정말인가?그렇다. 처음엔 좀 당황했지만, 그래도 방법이 없으니 일일이 경우마다 테스트해보면서 직접 정리를 하려고 했다. 하지만 각 웹훅마다 큰 구분만 있고 세세한 데이터는 너무 다양해서 깔끔하게 정리하기가 어려워 따로 공유를 위한 문서를 만들지는 못했다. 예를 들자면 트렐로에서 updateCard 라는 action type의 웹훅 데이터를 보내주는데, 그 데이터만 보고 “Card Archive”, “Description 수정/삭제”, “Due date 등록/수정”, “카드 이동” 등의 여러 가지 서로 다른 이벤트를 구분해야 한다. 근데 그 구분하는 방법이 특정 flag가 있는 게 아니라서 각 data를 모아놓고 역으로 분리하다 보니 코드를 깔끔하게 작성하기가 어려움은 물론, 추후 트렐로 측 데이터의 변동이 있을 때의 품질을 보장할 수 없는 리스크를 안고 구현할 수밖에 없었다.Q. 그 밖의 도움이 될만한 노하우나 꿀팁이 있다면?만약 트렐로와 어떤 형태로든 연동하려고 한다면, 설계 전에 모든 API에 대해 꼼꼼히 살펴보고 웹훅 이벤트 또한 직접 테스트해서 일단 전체적으로 리스트업을 정리하는 게 보다 생산성에 도움이 될 것이다. 트렐로를 잘 알고 있더라도 서비스 내부에서 “보드”, “리스트”, “카드”가 어떤 상관관계를 가지는지 미리 정리해보는 것도 좋다.사소하지만 좀 특이했던 점은 웹훅을 처음 등록할 때 해당 URL로 확인 요청을 한번 하는데, 이때 요청은 HTTP method가 POST가 아닌 HEAD로 들어온다. 그래서 반드시 동일한 URL의 HEAD 요청에 대해서도 정상 응답을 할 수 있도록 구현해야 한다.마무리잔디 커넥트를 구현하면서 특히 서비스 품질과 개발 속도 간의 밸런스에 대한 고민을 많이 했습니다. 초반에 서비스 종류별로 작업을 분리하고 각각의 방식으로 설계한 뒤 나중에 정리하는 전략이다 보니 공통으로 가져갈 수 있는 DB 모델이나 서비스 로직이 많아서 이를 통합하기 위해 반복 작업을 할 수밖에 없었는데 이 부분이 저희 내부적으로 느낀 가장 아쉬운 부분이 아니었나 생각합니다. 기능 중 많은 부분이 외부 서비스에 의존적이다 보니 생각하지도 못한 크고 작은 이슈들이 발생해서 일정 산출에도 꽤 어려움을 겪었습니다.커넥트 기능을 출시한 이후로 꽤 시간이 지났음에도 불구하고 이슈 백로그(Backlog)를 보니 아직도 개선할 부분이 많이 남아있는 듯 합니다. 그렇지만 이번에 기반이 되는 작업을 최대한 튼튼히 하기 위한 많은 시행착오를 거쳤기에, 추후 연동되는 커넥트 종류를 늘려나가는 시점5에 보다 효과적으로 개발할 수 있을 것이라 기대하면서 이번 글을 마치겠습니다.Slack API 문서 참고 ↩vagrant의 box로 서로의 로컬 개발 환경을 동일하게 유지하고 있습니다. 참고로, 현재 저희 서버 환경은 Local - Dev - Staging - Production으로 구성되어 단계별로 상황에 알맞게 배포하고 있습니다. ↩Localization의 약어. 잔디는 아시아 시장에 최적화된 서비스를 제공하고자 한국어, 일본어, 중국어 간체자(중국), 번체자(대만/홍콩), 영어 총 5가지 언어를 지원합니다. ↩아이캘린더(iCalendar)로 불리는 인터넷 캘린더의 데이터 포맷에 관한 표준. IETF 문서참고 ↩구체적인 시점은 말씀드리기 어렵지만, 더욱 좋은 사용성을 제공하고자 유저분들의 설문조사를 진행하고 있으니 많은 참여 부탁드립니다. ↩#토스랩 #잔디 #JANDI #개발후기 #일지 #인사이트
조회수 4061

PHP Codeigniter 환경에서 VUE 사용해보기

Overview이번에는 PHP Codeigniter 기반의 서비스에 VUE를 적용시키려고 고민했던 것들을 나누려고 합니다. VUE JS는 가상 DOM을 활용하여 실시간으로 반응 컴포넌트를 제작할 수 있는 프레임워크입니다. 또한, VUE-ROUTER 및 VUEX라는 컴페니언 라이브러리를 통해 url 라우팅 및 전역상태를 관리하기에도 탁월하죠. VUE와 다른 프레임워크와의 비교 부분은 여기를 참고해주세요. 브랜디의 관리자 서비스는 PHP Codeigniter 프레임워크로 제작되었습니다. 하지만 관리자 서비스의 규모가 점점 커지고 기능이 다양해지면서 “자주 사용하는 기능을 묶어 컴포넌트화하자!”라는 숙제가 남아 있었죠. 요즘 잠깐의 여유가 생겨 이때다 싶었습니다. 관리자 서비스에 VUE를 도입하기 위한 시도를 시작했는데요. 얼마 지나지 않아 문제점에 봉착했습니다. 바로 IE9.0…. 개발자의 숙적 IE가 또 한 번 발목을 잡았습니다. 임포트가 되지 않아….VUE를 좀 더 편리하게 사용하려면 JS의 모듈화가 필요했지만, ES2015에서는 import 혹은 require 구문을 지원하지 않아 불편하고, arrow 함수 또한 사용할 수 없습니다. 게다가 VUE의 JAX 탬플릿 구문을 사용할 수도 없었죠!! 뭔가 배보다 배꼽이 더 커질 것 같은 조짐이 보였습니다.결국 Webpack의 도움 없이 VUE를 적용하려던 시도는 여러 가지 난관을 만났고, Codeigniter 프로젝트 내부에서 Webpack을 사용하는 방법을 연구하기 시작했습니다. Webpack은 모듈 번들러입니다. Webpack의 메인 페이지를 방문하면 아래 네 개의 슬로건이 빙글빙글 돕니다.Bundle your scriptsBundle your imagesBundle your stylesBundle your assets아래의 이미지는 Webpack이 무엇을 하는 녀석인지 잘 설명해줍니다.Webpack은 실제로 번들러라고 광고하는것 처럼 Only Webpack 빌드만으로는 소스 파일들을 모아줍니다. 만약 webpack-dev-server로 실행하면 websocket을 통해 소스가 변경됐을 때 실시간으로 화면을 갱신해주는 개발 툴 제공 정도의 역할 밖에 없습니다. (…충분히 훌륭하잖아?)대부분의 기능은 엄청난 확장성을 가진 webpack의 설정으로 모듈로서 작동할 수 있죠. 예를 들면 Babel은 우리의 발목을 잡았던 IE를 위해 ES6로 작성된 js 문법을 IE에서 사용할 수 있는 ES5문법으로 너무나 쉽게 트랜스컴파일할 수 있습니다.하지만… 관리자 서비스는 위에서 언급했듯이 Codeigniter 기반입니다. 따라서 완벽히 VUE와 API서버를 분리하려면 로그인, 메뉴구성, 헤더, 푸터 등 PHP 기반으로 제작된 모든 기능들과 인증 등 기존 방식을 전부 새로 만들어야만 VUE를 온전히 사용할 수 있습니다.문제점들을 모두 해결하고 넘어가기엔 여유가 부족하기 때문에 조금씩 적용하자고 생각했습니다. 덕분에 webpack-dev-server의 실시간 소스 반영 기능을 포기해야만 했죠.(눈물) 우리의 서버는 node기반이 아닌 apache-php 기반이었기 때문입니다.자, 그럼 Codeigniter 프로잭트 하위에 웹팩을 포함시켜 Hello World까지 가는 짧은(?)여정을 시작해봅시다.Hello world로 가는 여정Node, npm 설치맥에서도 유사한 명령어로 제작할 수 있도록 CMD 위주로 진행하겠습니다. 먼저, 여기를 클릭해 Node를 설치합시다. 8.11.3 LTS버전으로 진행했습니다.맥에서는 Homebrew를 통해 간편하게~brew install node 설치 확인npm 잘 설치되었네요.web pack 폴더 생성 및 이동mkdir webpack cd webpack nom init으로 초기화npm init webpack, vue, babel 설치npm install -D webpack webpack-cli webpack-dev-server npm install -D vue-loader vue-template-compiler npm install -D babel-core babel-loader babel-preset-es2015 여기서 VUE는 설치하지 않습니다! 왜냐하면 VUE.js는 로딩만 하면 되고 필요하지 않습니다! (읭?) VUE는 Codeigniter view에서도 사용해야 하기 때문에 해당 view에서 import 해줍니다. 따라서 VUE 컴포넌트가 들어가는 시점에는 이미 전역에 vue.js 가 있습니다. 따라서 굳이 각 모듈마다 VUE를 import 했다가 webpack 설정에서 다시 vue.js를 제외할 필요는 없습니다.VUE와 template 태그를 로딩할 수 있는 로더도 설치하고, 트랜스컴파일을 위한 바벨, IE9를 지원하기 위한 es2015프리셋도 함께 설치합니다.webpack 빌드명령어 package.json의 script부분에 추가"scripts": { "build": "webpack --mode production", "build-dev": "webpack --mode development",   } 이제 VUE를 빌드할 명령어를 작성합니다. 위처럼 두 가지 명령어를 제작해두면, 추후 env를 통해 webpack.config.js를 분기시켜 원하는 환경으로 빌드할 수 있습니다. 또한 production 모드로 빌드할 땐 자동으로 옵티마이저 - uglify 내장 플러그인이 적용되어 익숙한 min.js형태로 빌드되며 development를 빌드할 땐 사람이 알아볼 수 있는 형태로 빌드되고, debugger 코드 또한 살아있습니다.weboack.config.js 작성const { VueLoaderPlugin } = require('vue-loader'); module.exports = {   entry: {     HelloWorld: './src/main.js'   },    module: {     rules: [       {         test: /\.vue$/,         loader: 'vue-loader',       },       {         test: /\.js$/,         loader: 'babel-loader',       }     ]   },    resolve: {     alias: {       'vue$':'vue/dist/vue.esm.js'     }   },    plugins: [     new VueLoaderPlugin()   ]  } webpack.config.js 가 없다면 생성한 후 위와 같이 작성합니다..babelrc 작성{     "presets": ["es2015"] } 테스트용 파일 작성1)main.js 작성import HelloWorld from './HelloWorld.vue' Vue.component('hello-world', HelloWorld); 2)HelloWorld.vue 작성 [removed] export default {   name: 'app',   data: () => {     return {       word1: 'Hello',       word2: 'World'     }   }  } [removed] 테스트 빌드npm run build-dev 빌드를 할 땐 기본적으로 ‘/dist/’ 하위에 소스코드가 떨어집니다. 자, 여기까지 진행하셨다면 폴더 구조는 다음과 같을 것입니다.지금까지 진행한 파일 모습입니다.뷰 컴포넌트가 잘 제작되고 등록되는지 확인하려면 기본 빌드 폴더인 dist 폴더에 Test.html을 작성해 브라우저로 열어봅시다.확인용 html 파일 작성<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <title>VUE Test</title>     <!-- VUE 플러그인 -->     [removed][removed] </head> <body>                     [removed][removed]     [removed]         new Vue({             el: '#vue'         })     [removed] </body> </html> 잘 나옵니다.정상적으로 VUE가 적용된 것을 확인합니다.코드이그나이터 설치이제 코드이그나이터 프로젝트 내부에서 VUE 컴포넌트를 출력해보기 위해 코드이그나이터 프로젝트를 생성합시다. 먼저 Codeigniter와 XAMPP를 다운로드 받습니다.Codeigniter 받으러 가기XAMPP 받으러 가기프로젝트 폴더 하위에 Codeigniter 프로젝트용 폴더를 생성합니다.mkdir codeigniter-with-vue-webpack cd codeigniter-with-vue-webpack 다운받은 Codeigniter를 해당 폴더에 압축 해제하면 Codeigniter 설치가 끝납니다.XAMPP 설치 및 DocumentRoot 변경XAMPP를 설치하고 DocumentRoot를 테스트 프로젝트 폴더로 설정한 뒤 아파치를 실행합니다.Codeigniter 프로젝트가 생성되었고, 서버 실행이 완료되었습니다. webpack 폴더를 Codeigniter 프로젝트 하위로 이동node-modules는 너무 크기 때문에 기본 파일만 복사하고, npm install로 설치합니다.Codeigniter에서 VUE를 사용하기 위한 webpack dist설정기존의 프로젝트에서 스크립트를 모아두는 폴더 하위로 빌드 결과 파일을 보내기 위하여 webpack 빌드 시 dist 폴더가 아닌 /application/scripts/vue/hello_world 하위로 빌드 결과 파일이 생성되도록 설정합니다.// 기존 module.exports = {   entry: {     HelloWorld: './src/main.js'   },    //... 생략 } // 변경후 module.exports = {   entry: {     '../../application/scripts/vue/hello_world/HelloWorld.js': './src/main.js'   },    //... 생략 } Codeigniter의 load->view 기능을 활용하여 파일 작성1)header.php// application/views/common/header.php <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <title>VUE Test</title>     <!-- VUE 플러그인 -->     [removed][removed] </head> 2)실제 view// application/views/vue/hello_world/vueTestPage.php <?php $this->load->view( 'common/header' ); ?> <body>                 [removed] [removed]     [removed]         new Vue({             el: '#vue'         })     [removed] </body> <?php $this->load->view( 'common/footer' ); ?> 3)footer.php// application/views/common/footer.php </html> 실제 프로젝트 구성과 유사하게 header, body, footer로 나누어 파일을 작성해봅니다. 실제로는 더 복잡하지만 이 정도만 나누겠습니다.Codeigniter 테스트용 컨트롤러 작성// application/controllers/Vue.php <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');   class Vue extends CI_Controller {      public function index()     {         $this->load->view('vue/vueTestPage');     }  } 정말 심플(?)한 테스트용 파일 작성이 모두 끝났습니다! 이제 잘 작동하는지 확인해볼까요?코드이그나이터에서 helloworld 출력짜잔이번엔 문제의 IE에서 확인해봅시다.IE9.0 환경에서 확인IE에서도 무사히 출력되는군요. 이제 코드이그나이터 환경의 프로젝트에서도 IE까지 지원하며 무사히 VUE를 사용할 수 있게 되었습니다! (시간이 없어서 가상머신에 IE9가 설치된 윈도우7까지 테스트하진 못했습니다!) 모든 작업이 완료한 후, 파일 폴더 구조는 아래와 같습니다.붉은 네모 부분이 실제로 제작하거나 수정한 파일들입니다.Conclusion여기까지가 Codeigniter 프래임워크 환경에서 webpack + vue를 사용하기 위한 웹팩의 설정 과정 및 테스트 결과였습니다. php 서버를 사용해야 하기 때문에 webpack-dev-server의 핫리로드 기능을 사용하지 못하는 건 매우 안타까운 일입니다. 하지만 짧은 시간에 신기술을 도입하면서도 수많은 리스크를 회피할 수 있다는 건 나쁘지 않은 선택이라 생각합니다.위의 웹팩설정을 조금만 활용한다면 다른 프레임워크 프로젝트에서도 무리없이 VUE를 사용할 수 있을 겁니다! 비슷한 고민을 하셨던 개발자님들… 집에 가기 전 말고 오전에 Webpack을 설치해보세요. 안 그러면 저처럼 집에 못갈 수도 있으니까요!참고.gitignore 작성, index.php 제거 등은 내용에 포함하지 않았으며, 아래의 링크로 자세히 알 수 있음.Codeigniter index.php 없애기글강원우 과장 | R&D 개발2팀[email protected]브랜디, 오직 예쁜 옷만 #브랜디 #개발자 #개발팀 #인사이트 #경험공유 #PHP
조회수 1363

영어공부 꾸준히 하는 법

파파고나 구글 번역기와 같은 통번역 기기가 속속 등장하고 있다.기술이 발전하면 외국어가 더 필요 없어질 것이라고 생각했는데, 영어는 일상생활에 더욱 깊숙이 파고든다.출장과 해외여행이 점차 늘고, 길에서 마주치는 외국인도 많아졌다.업무에서도 영어자료를 쓸 일이 점점 늘어난다. 영어에 대한 문턱이 낮아진만큼 기대는 높아졌다. 번역기가 나오면 천국일 줄만 알았는데, 번역기 덕에 외려 부담감이 더 늘어가는 느낌이다. 기기에 의존하든 스스로의 능력에 기대든, 어쨋든 영어는 점점 생활의 일부가 되어가고 있다.나는 중학교때부터 영어를 끊임없이 배워왔다. 고등학교까지 나는 대학에 들어가기 위해 영어를 공부했고, 대학에서는 취직을 위해 영어를 배웠다. 그리고 지금은 세상에 뒤쳐지지 않고, 더 나은 정보를 얻기 위해 영어를 읽는다. 하지만 여전히 영어는 울렁울렁 거린다.나도 영어 잘하고 싶다..직장에 들어와 영어 공부를 한다고 학원도 다녀보고, 영어 신문도 보고 영어 잡지도 봤지만 결국은 오래가지 못했다. 시작할 때는 그 의지가 제법 호기로웠지만, 작심삼일이라는 단어는 꽤나 무거웠다. 하지만 그렇다고 영어공부를 포기할 수는 없다. 타의든 자의든 영어를 해야만 더 많은 기회에 노출되는 것이 현실이기 때문이다.마주친 현실과 꿈쩍않고 낮은 의지 사이에서 많은 고민을 했다.도대체 어떻게 해야 영어를 꾸준히 공부할 수 있을까 나란 놈에게 맞는 영어공부법을 찾기 위해 지난 실패들을 한번 돌아봤다. 학원은 공부하는 것보다 가는 게 힘들었다. 직장 동료와 술자리도 가져야 하고 친구도 만나야 하는 일정속에서, 학원갈 시간이 살아남을 틈은 없었다. 영어 신문과 잡지는 솔직히 어려웠다. 트럼프나 시진핑의 대화는 그렇게 까지 관심이 가진 않았다. 내 친구도 이야기도 아닌데. 그러다보니 자연스럽게 공부와 멀어졌다. 하지만 영어는 꾸준히 공부해야 했다.경제학과 세상에 대해 공부하기에 참 좋은 잡지지만, 어렵다인터넷을 뒤지다 마지못해 재미있는 영어공부법이라 하는 미드보기를 뒤늦게 시작했다. 남들은 10년전에 이미 경험했던 그 미드보기다. 나이 서른에 뒤늦게 24시도 보고, 프리즌 브레이커도 봤다. 영어 공부한다는 핑계로 한글 자막을 틀어놓고 매일을 킬킬거렸다. 영어공부가 이렇게 재미있을 수가. 영어가 느는지 알 수는 없었지만 아무튼 하루에 1-2시간씩 영어발음을 꾸준히 들었다. 당연히 크게 효과는 없었다. 두달 가량을 거의 매일 미드를 봤으니 못해도 50시간은 공부했을 텐데, 영어 말하기는 제자리였다. 드라마에서 수도 없이 나왔던 "범인이 아직 잡히지 않았어" 라는 문장을 나는 두달후에도 여전히 "he is still our there" 로 표현했다. (이 표현도 틀린건 아니지만, 드라마에서 계속 나왔던 표현은 The criminal is still at large 라는 표현이었다) 대통령 케빈스페이시와 영부인 로빈라이트의 영어발음은 정말 좋다 ⓒ Netflix Original House of Cards재미로 미드보기의 효과없음을 여실히 느끼고 나는 그날부터 영어자막을 틀어놨다. 그제서야 영어공부를 하는 것 같은 느낌을 조금 받을 수 있었다. 잘 모르겠는데 중요한 표현 (중요한 표현 같다는 느낌이 있다!) 은 뭐라고 한건지 다시한번 돌려도 보고, 이해가 안되면 이해가 되는 장면으로 되돌려 보기도 했다. 그렇게 직장인이 되고 처음으로 작심삼일의 엄벌을 피해 영어 공부를 꾸준히 하기 시작했다. yay!하지만 어디 완벽한 공부법이란게 있을까. 영어자막 미드보기는 영어 듣기랑 빠른 독해에 큰 도움이 됐지만, 영어로 말하기에는 별반 차이를 주지 못했다. 외국 바이어와 드라마 이야기를 하면서 친해지는 데에는 큰 기여를 했다. 그래서 두달 전부터는 미드에서 나오는 표현들을 하루에 두세개씩 노트에 적기 시작했다. 어떤 날은 한문장을 적기도 하고, 간혹 느낌이 충만한 날에는 10문장을 쓰기도 했다. 하지만 10문장을 쓴 다음날은 어쩐지 한문장도 쓰기가 싫어졌다. 그렇게 한달이 지난 시점부터는 하루에 3문장을 꾸준히 쓰고 있다. 부담이 되면 또다시 작심삼일의 엄벌에 처해질 것을 알기에, 지금은 욕심을 더 내지 않고 딱 하루 3문장만 쓰고 있다.노트에 계속 적으면 복습에도 도움이 된다그럼 이제 사람들이 가장 궁금해 할 3문장 쓰기의 효과에 대해 이야기를 해보겠다.무엇이 달라졌을까? 혹시 엄청난 기대를 하고 있다면 정신을 바로 차려야 한다. 애초에 기대가 너무 크면 안된다. 고작 하루 5분의 시간을 투자했을 뿐이다. 하지만 5분의 시간을 투자한 것 치고는 대단한 변화가 있었으니, 1. 우선 생활영어 표현이 엄청나게 많이 늘었다. 똑같은 표현은 훨씬 자연스러워졌다. 바이어를 만나면 취미가뭐냐고 물을 때 이제는 "What's your hobby?" 대신 "what do you do for fun?" 을 쓴다. (우리도 시간날 때 뭐하냐고 묻지 취미가 뭔지 묻지를 않는다!) 2. 자연스러운 표현을 쓴다는 자신감을 얻으니, 외국인과의 대화를 더 많이 시도하게 됐다. 초면인 사람을 만나면 뭐라고 말할지 몇번을 미리 연습했고, 영어 실력때문에 ice-braking 을 포기했었던 나지만, 지금은 나름 몇마디를 할 수 있다. 자연스레 영어가 늘어가는 재미도 느꼈다. 새로 배운 표현을 외국인이 바로 알아들었을 때의 그 쾌감은 정말 이루말할 수가 없다. 3. 끝으로 한가지를 덧붙이자면, (개인적으로는 이게 가장 만족스럽다) 무엇보다 드디어 영어를 꾸준히 공부하는 방법을 찾았다는 것이다. 영어 실력을 늘려야하고, 정해진 공부법은 맞지 않아 꾸준히 할 수 없어 답답했던 마음이 지금은 완전히 사라졌다. 어쩌면 무언가를 해야한다는 강박을 해결했기 때문일 수도 있다. 하지만 나는 이제 영어를 꾸준히 공부하고 있고, 그 성과도 매일매일의 업무에서 확인하고 있다.하루 3문장 영어쓰기는 이제 고작 2달이 지났다. 문득 내가 이 습관을 계속 유지할 수 있을까 걱정이 되기도 한다. 하지만 또 어느순간 포기하면 어떠랴. 새로운 방법을 다시 찾으면 된다. 우선은 지금의 공부법을 할 수 있는 한 유지해보려고 한다. 당장은 미드를 보고 있지만, 나중에는 그동안 실패했던 영어 신문과 영어 잡지도 똑같은 방법으로 공부를 해볼 수 있지 않을까 생각하고 있다. 6개월에 되는 시점에 다시한번 글을 써보겠다. 부디 그때까지 꾸준히 이 습관을 계속 유지할 수 있기를!끝으로, '파파고와 구글 번역기가 더 발전해서 영어능력이 정말 필요없어지면 어쩌지' 라는 쓸데 없는 걱정도 해본다. (가진자의 걱정이 이런거구나 싶다)by 아직도 영어가 고픈 30대 직장인챌린저스, 확실한 목표달성 꾸준한 습관형성 앱www.chlngers.com
조회수 843

보고 듣고 깨달은 업무의 40가지 진실

요 근래 많은 대표님들이 큰 영감님들을 주셔서 하루하루 재미있는 에피소드와 신기한 요지경 업무세상에 대한 인사이트를 넓혀가고 있는 중입니다. 그래서 이 재밌는 걸 정리해서 써보았습니다. 지엽적인 사견이 가득하니 그냥 웃고 말자는 식의 글로 봐주시면 되겠습니다.1. 내가 원하는 대로 뭔갈 만들어서 가져오는 사람은 원래 없습니다. 교수님이 원하는 과제퀄리티와 같은 느낌인 것 같습니다.  2. 보통 10마디를 지시하면 청자의 머릿속엔 1문장 중에 목적어와 희미한 서술어정도만 기억에 남는 듯 합니다. "에빙하우스의 망각곡선"은 진리였습니다.3. 스타트업엔 크리에이티브한 사람보다 일을 땋땋땋,챡챡챡하는 사람이 더 필요합니다.4. 쾌활하고 끼가 많은 것과 크리에이티브함과는 아무 상관관계가 없습니다.5. 기발한 발상과 아무말은 다릅니다.6. 전략/기획자 뽑기보다 메일 잘 보내는 사람 뽑기가 더 어렵습니다.7. 똑똑한 사람보다, 상식이 많은 사람이 일할 땐 더 좋은 듯 합니다.8. 업무지시는 3형식이 좋은 것 같습니다. "너는 보고서를 만들어""보고서의 중요한 부분을 표시해" "그걸 나에게 가져와"9. 8번을 끊지않고 한 문장으로 지시하면 혼란한 종이를 받을 수 있습니다.10. 생각보다 자기가 일을 잘한다고 생각하는 사람이 많습니다. 일잘은 내가 아니라 남이 인정하는 겁니다.11. 그리고 상상이상으로 일 못하는 사람들이 많습니다. 물론 나와 다르게 일을 하는 것을 제외하고서라도 말입니다.12. 10명기준으로 1명정도는 평타이상의 업무능력을 보여주는 보배가 등장합니다. 10명 미만이면 보통 대표가 그 사람입니다.13. 대표님들은 항상 지병이 있습니다.14. 제가 만나본 대표님들은 항상 후즐근한 옷과 피곤한 표정, 급하게 뛰어오시고, 끝나고 항상 어디가야하고, 끊임없이 울리는 카톡과 전화에 '잠시만요.' 를 자주 언급하십니다.15. 제 사견으론 3차면접은 면접 대신 엉망진창이 된 파일더미를 주고 15분 내에 폴더정리를 해보렴. 이라고 과제를 준 후 그렇게 정리한 이유와 이걸 어떻게 활요할 건지 묻는 과제형테스트가 있었으면 좋겠습니다.16. 정리는 상당한 고급종합스포츠입니다. 드러운 것을 보고 깨끗한 그림을 그릴 수 있어야 하고, 일단 꺼내고 다시 정리하면서 순서, 구상, 작업, 체계, 활용여부, 마무리를 지을 수 있어야 합니다. 아무나 하는게 아님.17. 네트워킹파티가 많이 열릴수록 명함인쇄업체와 리멤버의 매출이 올라갑니다.18. '가치'란 말은 종종 불확실함과 나도 잘 모르겠음을 커버치는 보자기로 활용됩니다.19. 대부분의 디자인은 이론을 구현하는 게 아니라 상대의 욕망을 구현하는 작업입니다. 물론 공공/서비스 등 큰 영역에선 예외입니다.20. 도가 넘치게 상상이상의 놀라움을 보여주는 직원이 한 명씩 나타납니다. 우리의 멘탈과 인내심은 이러한 분들로 하여금 한발 더 성장할 수 있습니다.21. 무슨 컨퍼런스가서 뽐뿌받고 열정넘쳐서 '새로운 나로 다시 태어난 것 같다.' 라고 하는 건 좋은데 손과 머리는 그대로일 수도 있습니다. 성장은 느낌이 아닌 결과로 보여지는 겁니다.22. 말이 많은 것과 말을 잘하는 것은 다릅니다.23. 가치는 매출로 증명합니다.24. 현실적인 것과 시니컬한 것은 구별해야 합니다. 시니컬한 사람은 자길 현실적이다라고 하는데, 그건 그냥 시니컬한겁니다.25. 일 잘하는 사람들은 항상 뭔가 힘듭니다.26. 누군가가 똥을 싸놓으면 자연분해되서 없어지는 것 같지만, 그런 건 없습니다. 내가 모르는 누군가가 치운겁니다.27. '멋져요!' 란 말은 사실 그냥 하는 말입니다.28. 좋아요수는 매출이 아닙니다. 그리고 내 페친이 2,000명이라고 해서 그 중 10%는 사주지 않을까?라는 생각은 이상한 겁니다.29. 수평적문화에는 앞에 '경우에 따라' 라는 말이 생략되어 있습니다.30. 인간은 맞아야 말을 듣는건가?...라는 생각을 종종 하고 있다면 정상입니다.31. 내가 이상한 거 아닌가?라는 생각이 드는 것도 정상입니다. 이상한 사람들은 자기가 이상하다고 생각하지 못합니다.32. 우리 회사만 이상한 게 아닙니다. 다 도찐개찐입니다.33. 멍청한 사람들이 모이면 양으로 발산할 가능성이 높지만, 똑똑한 사람들이 모이면 음으로 수렴할 가능성이 높습니다.34. 종종 드는 생각입니다만..직무교육이 지옥캠프같다면 어떨까 싶습니다. 3일간 가둬놓고 메일만 72시간 내내 쓰게 하는 것도 나쁘지 않다고 생각합니다.35. 동기부여는 체화가 곁들여져야 의미가 있습니다. 침대에 누워서 의지만 가득한 건 어딘가 이상합니다.36. 보통 인간은 '정기적인 무언가'를 지독하게 못합니다.그런 것이 정착되기까진 못해도 3개월 이상이 걸립니다.37. 종종 디자인은 부족한 내실을 가리기 위한 가면처럼 쓰이기도 합니다.38. 일은 배운다고 되는 것이 아닌 것 같습니다. 교육과 경험을 통한 성장은 분명하지만, 그 한계량은 정해진 듯한 느낌입니다.39. 일못하는 사람은 일잘러의 육체를 상하게 하고, 인성이 나쁜 사람은 일잘러의 마음을 상하게 합니다.40. 일못러는 다른 업무로 변환이 가능하지만, 인성이 나쁜 사람은 빨리 잘라야 합니다. 나쁜 사람이 일을 잘한다고 해도 잘라야 합니다. 원래 암세포는 못나거나 망가져서 그런게 아닙니다. 돌연변이로 인해 자기 깜냥 이상의 분열능력을 지니고 있기 때문에 암세포가 되는 겁니다.
조회수 815

우리에게 보이기 시작한 세상

무지몽매하고,좁은 시각으로 지금 당장 닥치는 앞날만보였는데...조금은 세상이 다르게 해석되고,안 보이던 것들이 보이기 시작했다.넓은 모래사장에서 작은 조개껍데기 하나를 발견한 수준이지만공유하고, 나누고자 글을 남긴다.1. 멀티태스킹이 아니라, 멀티인프라!잘하는 것을 특화하고,못하는 것은 잘하는 놈에게 맡겨라.내가 알고 있는 것보다,우리가 알고 있는 것이 많고내가 모르는 것보다우리가 모르는 것이 적다.따라서,우리는 다재다능보다다양한 사람, 다양한 기업과협력할 수 있는 인프라가 중요하다.일면식이 없던 사람을 설득하기보다알음알음 통해서 알게 된 사람을 설득하기가 쉽다.2. 신기한 나라의 엘리스의 빨리 달리는 여왕에게 배운다이제는 생산공장이 수요처로 갈 것이다.딜리버리가 중요해진다.스마트 팩토리 다음에는 스피드 팩토리고...지금 그렇게 흘러간다.개인의 맞춤형 시대, 신속함의 시대가 도래할 것이며, 다품종 소량 생산을 어떻게 빠르게 제공할 것인가가 관건이다.작은 기업의 강점은 스피드!남들과 같은 속도가 아니라 그보다 빠른 속도여야 앞서게 된다.지구가 돌아가는 속도보다 빠르게 달리는 여왕처럼시장이 변화하는 속도보다 빠르게 리드해야 한다.(물론 너무 빠르면 역으로 gap이 발생하니까 약간 더 빨리)3. B+프리미엄의 시대보편적이고 합리적인 가격에서 익숙한 기존의 것에 추가의 가치가 더해지는 형태가소비의 주축이 될 것이다.같은 값이면 다홍치마가 되어야 한다.디자인/콘텐츠의 중요도가 높아지고,고객의 눈높이는 첫눈에 반하는 제품으로 좁혀 들고 있기에 본질은 기본이고,디테일에 더 집중해야 한다.따라서,"No frills chic"가격은 저렴하지만 디자인이 매우 우수하여 럭셔리한 이미지를 풍기는 제품으로 나아가자.장식이 많이 없지만 멋진 제품들은 벤치마킹하자.설레지 않으면 버린다.그래서 정리하고 버리고 사지 않는 소비패턴이미니멀리즘의 증명이다.4. 구매 결정은 내가 한다.지금까지 구매 결정은 타인의 후기, 제품 추천정보에 의한비중이 컸으나 이제는 데이터의 축적으로 인해나만의 데이터 풀이 형성되고 있다.그리고 그러한 데이터를 기반으로고객 스스로 구매 결정을 내릴 수 있는 시대가 곧 열릴 것이다.예를 들어,내가 구매했던 이력들과 구매 제품의 정보들이중복/추출/정제되어 자료에서 정보로 탈바꿈될 것이며,가격대, 소요자금, 구매시기 등의 정보들과 연관되어나에게 맞추어진 구매 범위가 산출될 것이다.여기에 더 필요한 것은 신뢰도!그 신뢰도를 어떻게 확보하느냐를제품에 녹여야 한다.4차 산업혁명이다, 6차 산업이다,O2O, O4O, IoT 등 여러 그럴듯한 단어로정의하고 있지만그냥 쉽게 생각해서데이터를 통해 얼마나 고객의 입맛대로제품을 공급할 것이냐가제조업의 해결해야 할 문제이다. 5. 노동력의 종말? 섣부른 단정은 금물많은 사람들과 언론은 인공지능의 시대에는대규모 실업사태와 노동력의 드라마틱한 감소를 예단한다.과연 그럴까?어느 정도 동의는 하지만,그것이 모든 것을 바꾸진 않으리라.농업과 가내수공업 등으로 사람 손이 절대적인 시대에서증기기관과 화석연료로 인한 산업화로 넘어가던 시절에직업의 변천은 있었지만, 여전히 노동력이 필요했다.오히려 많은 인구는 도시로 몰려들었고,다양한 직업이 발생하였다.인터넷이 발달하고, 컴퓨터의 발전으로 급격한 세상의 발전이 되었을 때도업무의 양은 늘어났고, 이동속도도 빨라지고,서비스업의 발달을 통해 더 많은 직업이 탄생하였다.굴뚝청소부가 사라지고,보일러 수리공이 나타났다.은행 지점이 줄어들지만,수많은 인터넷 은행, P2P 거래업체가등장하게 되었다.자율주행차가 나오면 자가 소유 차량이 감소할 것이지만,차량 대여/공유 중개사들이 생길 것이다.사물인터넷을 적용한 공장자동화로많은 생산직 자리가 사라지겠지만,공장을 유지/보수/관리하는 자리가 늘 것이다.물론 기존의 직업에서 새로운 직업으로 바뀌는 양보다사라지는 양이 더 많아질 것임은 분명하지만,각 국의 정부들이 그 충격을 그대로 받아들이게놔두지는 않을 것이고, 서서히 연착륙하도록제도를 만들어갈 것이다.(기초소득제, 맞춤형 복지, 기계에 대한 세금 논의 등)인공지능으로 대체될 수많은 직업이 있음은 나 역시 공감하지만그로 인해 직업은 더 세분화하고, 새로이 만들어질 직업의규모와 사이즈가 어느 정도 될 런지 알 수 없다.다만, 인공지능이 세상 전부를 덮지는 못 할 것이다.아직도 인터넷과 모바일이 덮지 못하는 세상과 시장이 존재하고,그 간격은 새로운 니즈를 발생하며그 안에서 비즈니스와 가치가 창출되고 있다.6. 다른 분야를 관찰하라.다양하게 남의 기술을 적용해서 내 것으로 만들어라.하늘 아래 새롭게 창조되는 것은 없지만새롭게 변형되고, 조합되는 것은 있다.초기에는 획기적인 기술개발보다익숙하지만 무언가 다른 것이 더 낫다.공들이고,시간을 들이고,비용을 들여야 하는 진짜 핵심기술은 오늘을 살아내야 하는 스타트업에게는큰 부담이다.이번에는 급하게 쓰다 보니좀 글이 러프하다.세상이 어떻게 흘러가고 있는지예의 주시해야 바다 위에 돛단배 같은 우리가살아남을 수 있다.문득 뉴스 기사들을 보다가 생각난 김에 휘갈겨보았다. 
조회수 1175

[인터뷰] Clara의 인턴 직무 인터뷰 제3화 _iOS developer 민트를 만나다

안녕하세요:)인턴들의 하루하루를 전해드리는 클라라입니다오늘은 저번 시간에 말씀드렸던 Tech unit의  미녀 인턴과의 인터뷰를 진행했습니다!그녀의 이름은 상쾌한 Mint!본명에 '박하'가 들어가서 민트라는 이름을 지었다고 하네요~센스 만점이죠?이름처럼 상큼한 민트와의 인터뷰바로 만나보시죠!고고고☞Q. 안녕하세요 민트, 간단한 자기소개와 요즘 어떤 일을 하시는지 소개해주세요~M.네! 안녕하세요~ 저는 iOS 개발을 하고 있는 개발자입니다. 많은 분이 개발자가 코딩을 하고 이런 것들은 어렴풋이 알고 계실 텐데, 지금 저는 iOS 앱에서 개선할 부분을 조사하고 더 잘 구현하고자 열심히 개발하고 있습니다. 아직은 주로 UX/UI 의 개선에 집중하고 있고, 하는 일보다 배우는 일이 더 많은 것 같네요!M.네! 안녕하세요~ 저는 iOS 개발을 하고 있는 개발자입니다. 많은 분이 개발자가 코딩을 하고 이런 것들은 어렴풋이 알고 계실 텐데, 지금 저는 iOS 앱에서 개선할 부분을 조사하고 더 잘 구현하고자 열심히 개발하고 있습니다. 아직은 주로 UX/UI 의 개선에 집중하고 있고, 하는 일보다 배우는 일이 더 많은 것 같네요!Q. 개발자는 그 안에서도 하는 일이 다양하다고 들었어요. 요즘 민트의 주 업무에 대해 더 자세하게 설명해주실 수 있을까요?M.그럼요~지금 저는 아이폰의 OS인 iOS에 특화된 방식으로 개발하는 네이티브 방식을 활용하고 있어요. 네이티브 방식이란 안드로이드나 iOS와 같은 특정 OS에 최적화된 방식으로 앱을 개발하고 있다는 뜻입니다. 그렇지 않은 개발 방식도 있거든요! 모바일 웹페이지를 앱처럼 꾸며서 보여주는 등 여러 방식이 있습니다.M.그럼요~지금 저는 아이폰의 OS인 iOS에 특화된 방식으로 개발하는 네이티브 방식을 활용하고 있어요. 네이티브 방식이란 안드로이드나 iOS와 같은 특정 OS에 최적화된 방식으로 앱을 개발하고 있다는 뜻입니다. 그렇지 않은 개발 방식도 있거든요! 모바일 웹페이지를 앱처럼 꾸며서 보여주는 등 여러 방식이 있습니다.iOS개발은 안드로이드 앱 개발과 비교했을 때 제약 조건도 많고, 생소한 스타일의 개발 언어를 써야 하는 게 어려워요. 하지만 동시에 iOS 특유의 사용감과 안정성이 매력이에요. 그리고 아까 UX/UI라는 용어를 사용했는데 이는 User Experience와 User interface의 약자, 즉 사용자 경험을 의미합니다. 저희는 사용자 경험을 더욱 편리하게 하는 쪽으로 앱을 유지 보수하는 일을 하고 있는 거예요. 미미박스는 고객을 소중히 여기기 때문에 이런 UX/UI에 있어서도 많은 신경 쓰고 있습니다.Q. 그럼 개발자로서 미미박스는 어떤 장점을 가지고 있나요? 저희 회사 자랑 좀 해주세요!!!M. Q. 그럼 개발자로서 미미박스는 어떤 장점을 가지고 있나요? 저희 회사 자랑 좀 해주세요!!!M. 음, 저는 미미박스가 개발자의 의견을 듣고 반영하고자 하는 회사임을 가장 말씀드리고 싶어요! 미미박스 개발팀에서는 디자인팀+앱 개발팀+PM 팀, 세 팀이 모여서 정기적으로 회의를 하고 있습니다. 이 회의를 스크럼이라고 하는데, 프로젝트와 관련된 모든 사람들이 모여서 계획하고 피드백하는 것이죠.이걸 하면 좋은 이유는 개발을 담당하는 사람이 직접 기획에도 참여할 수 있다는 거예요. 보통 한국에서 개발 직무는 보통 상명하달식으로 이루어진다고 해요. 위에서 개발이라는 직무를 이해하지 않고 일방적으로 일정을 정해서 던져주는 거죠. 그런데 미미박스는 그렇지 않고 자신의 생각을 내고 반영할 수 있어서 좋아요.   Q. 오오오~ 그렇군요! 민트와 저는 자리가 멀잖아요. 업무적인 것과 별개로, Tech 유닛의 분위기는 어떤가요??? M.저희 유닛 분위기 완전 좋아요! 그리고 저는 사수 분들이 똑똑하셔서 배울 점이 많다는 생각으로 회사를 다니고 있어요. 서로 돕고 정보를 공유하는 분위기여서 무려 시니어 분들이 제게 본인의 코드를 다 오픈해주세요. 근데 그 코드가 다 샘플 코드의 수준이고요!(샘플 코드란 일종의 '교과서'같은 존재로, 코딩의 수준이 아주 높다는 뜻입니다.)iOS 직무는 신입의 진입장벽이 높거든요. 사전 지식 없이는 독학으로 따라잡을 수 없는 부분이 많기 때문에 코드와 그에 대한 설명을 들을 수 있다는 건 엄청난 거죠. 마치 최고의 영업사원이 자신의 영업 비밀을 공개해주는 그런 경우라고 할까요? 애플 워치의 코드까지 알려주는 회사, 흔치 않습니다! (엄지 척)  민트에게 몰려든 고양이들~Q. 와우! 애플 워치도 코딩을 하는 거군요. 제겐 너무나 신세계인데요...!  이제 마지막 질문입니다. 여성 개발자로서 강점은 무엇일까요?M.저는 사실 특정 산업 군이나 성별에 구애받지 않는 작업을 한다고 생각해요. 그럼에도 화장품을 온라인으로 사 본 개발자과 그렇지 않은 개발자는 차이가 있다고 생각해요. 여성이 주 고객층인 뷰티 쇼핑몰에 대한 경험이 쌓이면 새롭고 좋은 UX에 대한 아이디어도 더 잘 나오지 않을까 싶네요.  민트와의 인터뷰 어떠셨나요?저 클라라처럼 컴알못이거나개발자의 하루가 궁금하셨던 분들은 이번 인터뷰가 큰 도움이 되셨으면 좋겠습니다.민트를 마지막으로 인턴의 생활을 엿볼 수 있는 클라라의 인터뷰가 마무리 되는데요 :)미미박서의 일과 삶에 대해서 조금이나마 더 알아가셨다면,그래서 '미미박스에서 일해보고 싶다'는 마음이 스멀스멀 생기셨다면!클라라는 그것만으로도 보람찰 것 같습니다.그럼 또 미미박스의 소식으로 찾아올게요~
조회수 5271

피부처럼 사용하는 업무용 Tool

1위. Meistertask (https://www.meistertask.com/)올 타임 1위였던 슬랙을 제치고 Meistertask가 당당하게 내가 가장 많이 쓰는 툴로 자리 잡았다. Task management Tool로 Asana, Jira, Trello.... 등을 썼었는데 뭔가 한 끗 차이로 마음에 안 듦. 그래도 전체 flow를 볼 수 있고 Kanban 방식을 적용할 수 있었던 Trello로 한동안 만족했었다. 전체 흐름을 보기 편하고 이쁘다!그러다가.. 우연한 계기로 '예쁜' Trello를 발견하게 되었다. Slack integration app에서 소개된 Meistertask. 아무런 의도 없이 그냥 한번 써볼까 하고 가입했는데 괜찮았다. 뭔가 손에 착착 달라붙는 느낌 ㅎㅎ 거의 모든 기능은 Trello와 비슷하지만 앱도 훌륭하고, 디자인이 Trello와 넘사벽. 슬랙과 integration도 훌륭.. 한데 돈 내야 한다. 근데 뭐 적절하게 IFTTT으로 연동해서 부족한 만큼 쓸 수 있다. 한번 써보시라. 개인적으로 Trello의 지루한 UI 보다 훨씬 신선하고 좋다. 팀원이 말하는 불만은 한 가지. 업무 assign이 한 명밖에 안된다는 것! 근데 나는 사실 한 명한테만 assign이 되는 게 더 좋은 거 같다. Task owner는 언제나 1명일 때가 좋다. 2위. IFTTT (https://ifttt.com/)IF That Then That 풀어쓴 서비스 명이 모든 걸 설명한다. 이거 실행되면 저거 자동으로 실행하기.슬랙을 2위로 할까 하다가 슬랙을 기반으로 얽기 설기 굉장히 복잡하게 얽혀있는 IFTTT을 2위로 선정했다.처음엔 재미 삼아서 이런저런 기능 연결해서 쓰다가, 이제는 내가 쓰는 거의 모든 앱, 서비스들이 IFTTT로 복잡하게 연동되어 있다. 설명이 어렵다. 이걸 실행하면 저걸 실행해준다 정도?내가 IFTTT를 쓰는 수십 가지 중에서 많이 쓰는 것들....- 아이폰에 연락처 저장하면 구글 스프레드시트에 저장해주기- 아이폰에서 스크린숏은 다른 앨범에 저장하기- facebook에 특정 해쉬태그 달면 슬랙 채널에 쏴주기- facebook에 포스팅하면 evernote에 저장해주기- 인스타그램에 포스팅하면 evernote에 아카이브 해주기- pocket으로 저장할 때 특정 tag 달면 slack 채널에 쏴주기- 내일 비 올 때 아이폰으로 푸시 주기- Fitbit에서 일어나면 slack 채널에 쏴주기- 내가 선정릉역에 도착하면 alert 채널에 사장님 도착하심 메시지 쏴주기 등등등이외에도 수십 가지 더 된다. 뭘 해놨는지 까먹을 정도.. IFTTT은 언젠가 IOT의 종합 플랫폼이 될 거다. alexa가 있다면 할 수 있는 게 10배는 늘어날 듯. 3위.  슬랙 (https://slack.com/)어쩌다 보니 3위까지 밀렸는데, 아직도 하루 중 가장 많은 시간을 슬랙 안에서 보낸다. 항상 내 옆에 있는 거 같아서 가끔 질리기도 하지만 오후 8시부터는 Push를 죽이는 snooze 기능을 만들어내는 것을 보면, 미워할 수 없다. 팀 커뮤니케이션은 많이도 방황했는데 결국 결론은 슬랙이다. (울지 마 잔디야...)업무와 일상을 완벽하게 분리하고 싶어서 절대 업무용으로 카톡을 쓰지 않기로 했고, 업무별로 채널을 나누고, 해당 업무는 그 채널에서만 이야기를 나눌 수 있어서 좋다. 처음에는 조금 불편해하는 팀원도 있었지만 결국 슬랙으로 대동단결슬랙의 묘미는 바로 다양한 서비스들과 integration이다. 예를 들면, 관심 있는 아티클을 페북에서 보다가 Pocket을 통해서 저장하고 특정 Tag를 달아놓는다면 자동으로 지정된 슬랙 채널로 쏴줄 수 있다. 팀원들과 마케팅 계획에서 얘기를 하다가 할 일이 생겼다. task mangement를 하는 trello를 켜고 입력할 필요가 없다. 슬랙에서 /trello add를 통해서 간단하게 업무를 더할 수 있다. 뭐 이런 integration은 수두룩 하다. 슬랙 봇은 몇 가지 재미난 게 있지만 결국 그냥 재미용으로 결론을 내림. 4위. 에버노트 (https://evernote.com/)언제부터 썼는지 기억도 안 나지만 5년도 넘게 모든 문서는 에버노트에 빼곡히 기록했다. 얼마 전에 'First Dead Unicorn'으로 잠시 유명세를 탔다. 코끼리야 죽지 마....  얼마 전에 동기화 기기를 2개로 제한하면서 많은 사람들이 떠나갔지만 나는 코끼리에게 프리미엄 결제로 보답했다. 엔간하면 결제를 안 하는 내가 결제를 했으니 내 손을 떠날 수 없는 운명인가 보다. 맥북 에어에서 버벅대는 모습을 보면 화가 나기보다는 애처로운 생각이 든다. 5년 넘게 내 일상을 기록하다 보니 뭔가 감정적으로도 연결된 듯.죽지마 코끼리야..쉽고 빠르게 기록할 수 있는 본질에서 살짝 비켜나면서 굴곡이 있었지만 잘 버텨주길 바란다. 좀 잘하란 말이다. 이렇게 계속 버벅대면 언제 갈아탈지도 모르겠다. 요즘은 에버노트를 팀 위키로 어떻게 활용할 수 있을지 고민 중이다. 지금 위키로 쓰고 있는 구글 사이트 관리자는 너무 느리고, 모바일에서도 굉장히 불편함. 에버노트는 이상한 기능 추가하지 말고 에버노트 위키 기능이나 만들어 주지...5위. Mindmeister (https://www.mindmeister.com/)사실 이건 Meistertask가 너무 마음에 들어서 이 회사에서 만든 다른 서비스는 없나? 하고 둘러보다가 알게 된 서비스이다. 역시 하나를 보면 둘을 안다니깐... 이 서비스도 훌륭하다. 한마디로 마인드맵을 쉽게 만들 수 있는 서비스이다.  요즘 모든  기획을 빡세게 하려고 하면 mindmeister를 켠다. 매우 직관적으로 생각을 잘게 쪼개고 발전시킬 수 있는 툴이다. 꼼꼼한 기획자들에게 강추...안타깝게 순위권에서 떨어진 서비스들..- Pocket : 아티클 간편 저장- Wunderlist : To-do list 작성- beat : 노동요 청취 (푹 쉬렴)- Pomodoro : 25분 일 + 5분 쉬는 것을 도와주는 타이머. 멀티태스킹을 방지해줌결론 : 일 잘하는 사람은 A4 이면지,  모나미 펜만 있어도 충분하다. 그런데 적절한 업무 Tool의 활용은 효율성을 극대화 해준다.#삼분의일 #업무환경 #업무프로세스 #협업 #협업툴 #꿀팁 #스킬스택 #스택소개
조회수 1619

칭기즈칸에게서 배우는 스타트업

이전에 브런치에서 조선의 왕들을 통해스타트업 창업자가 배워야 할 점들을정리하였다.이제는 글로벌 시대이니,잠시 세계사에 관심을 가져볼까 한다.특히나 거대 제국을 세웠던동양의 정복자이자,기존 세계관을 뒤엎었던 왕이었던칭기즈칸을 통해 스타트업을 이야기해 보자 광활한 땅에 말발굽 소리는흡사 지진과 폭풍을 몰고 오듯이세상을 흔들리게 하였다.누군가에게는 동쪽에서 온 악마였고,누군가에게는 북쪽에서 온 약탈자였다.그가 정복한 땅은 인류 역사상 가장 넓었고,그의 시대는짧은 시간에 세상을 뒤집은혁명의 순간이었다.테무진!우리는 그를 칭기즈칸(또는 징기스 칸)이라고 부른다.몽골 초원의 지배자에서동서남북으로 뻗은 유라시아 대륙의절대자가 되었던 왕!처음은 작은 부족에서 시작하여,온갖 고난과 역경을 이기고새로운 역사를 쓴스타트업의 멋진 표본이다.그를 뒤쫓아보고,무엇을 배울 수 있을는지정리해 보자.1. 야생성을 잃지 말 것!1) 헝그리 할 때, 가장 날카롭다.몽골이라는 나라를 가 본 적은 없지만,울란바토르가 수도라는 정도랑목축산업이 주요 산업이라는 점,허르헉이라는 음식 정도는 다큐멘터리를 통해 알고 있다.현대사회에서도유목민의 삶을 고집하는인구가 많은 그들은 어느 한 곳에 머물기보다는이동이 일상인  민족이다. 그들은 한 곳에 오래 거주하지 않는다.머물러 있기보다,새로운 풀과 물을 찾아떠나는 것에 주저하지 않는다.그렇기에변화에 민감하다.야생의 환경에 익숙해지면지형에, 날씨에, 전세에 민감해진다.이민족을 상대하고,다른 지역을 전전하다 보니사소하게 놓칠 수 있는 부분까지도빠르게 파악하고, 전략을 세울 수 있다.그리고야생은 헝그리하다.헝그리하다는 것!부족하다는 것은항상 날이 선 상태로 유지시키는 팽팽한 긴장감을 가져온다.신경이 곤두선 야생동물의 사냥 직전과 같은위험함이 칭기즈칸의 군대가 더욱 강하게 보이도록적을 두려움에 떨게 하였다.칭기즈칸은 항상 굶주려있는 전사와 가깝다.정복전쟁을 통해 많은 전리품과승자로서 정착할 수 있었지만영토 확장을 위해 계속적인 출정을 반복한다.18년 동안 칭기즈칸은 동서남북으로 직접 출병하여 진두지휘한다.현장을 직접 뛰는 최전선의 전사는가장 효과적으로 적을 이기는 방법을 터득한다.항상 칼은 날이 서리게 벼려있고,말은 언제든지 달릴 수 있도록 준비되어져 있다.누구보다 빠르게 진군할 수 있는 기동력!당시 몽고군의 송곳니같은 날카로움은극한으로 끌어올린 기동력이었다.야생은 자신이 가진 최대 장점을 살려살아남는 것이고, 승리하는 것이다.2) 무뎌진 이빨은 무섭지 않다.몽고군이 승승장구하는 시절에꽤 강적이라고 볼 수 있는 나라들이 있었다.서아시아의 호레즘 제국,이슬람의 바그다드의 아바스 왕조,북쪽의 러시아 공국,당시 유럽 최강의 헝가리/폴란드와 유럽연합군 등경쟁자로서 후들후들한 스펙을 가진군대들을 계속 격파해 간다. (물론 칭기즈칸 이후에 정벌도 포함되어 있지만,이는 그의 유지를 이어받은 후대 칸들의 정복전쟁이기에칭기즈칸의 연장선상이라고 볼 수 있다.)하지만 면면히 살펴보면,그 시대의 강자들은 자신의 것을 지키는 전쟁을 하고 있었고,몽고군은 빼앗는 전쟁을 하고 있었다.기본적으로 지키는 쪽이 공격하는 쪽보다유리하다는 것이 정설인데어떻게 몽고군은 연전연승할 수 있었을까?그 이유는 돌아갈 길이 없었다는 점에서지극히 절실한 군대였다고 보인다.몽고군의 특징은 군장(군인들의 짐)을 최소화하여기동력을 높였다는 점이다.그럼 식량이나 필요한 물품을 어떻게 조달하였냐면 점령지에서 빼앗았다.머나먼 길을 원정 온 그들이승리하지 못하면,다 죽을 수도 있다는 절실함이 그들의 전투력을 배가 시켰다.당시 호레즘 제국이나 바그다드는무역을 통해 물자가 매우 많았다.러시아 공국은 침략자의 손이 닿지 않은 땅이었으며,유럽연합군은 최강이라는 중기병의 위용이 있었다.그리고 자신들의 영역에서,자신들이 유리한 지형에서그들은 패배하였다.특이한 점은원나라의 성장 속도만큼 빠르게 세력이 약화되었다는 것이다.가장 큰 이유는 한족과 융화되고, 문화와 관습을 따르며,안주하기 시작하면서가 아닐까?원나라 황실은지배자로서 누리는 삶은 향락과 방탕함으로 이어졌고,이전에 날카로웠던 칼과 화살은창고에서 녹이 슬어갔다.백성들은 원나라의 지배에서 벗어나고자 하는운동들이 각지에서 일어나기 시작했고,야금야금 그들의 지배력을 약화시켰다.2. 칭기즈칸은 다양성을 좋아해.칭기즈칸이 정복전쟁을 벌이고 있었을 때,우리에게는 익숙하지 않지만,19인의 영웅들이 항상 칭기즈칸을 따라다녔다.그들은 용맹하였고, 지략에 뛰어났으며,산전수전을 함께 이겨낸 역전의 용사들이었다.19인의 용사를 살펴보자면 특이한 점을 발견하게 된다.색목인, 아랍인, 출신성분이 낮거나 귀화한 사람 등...다양한 사람들이 모여서 칭기즈칸의 대장군들로활약을 하였다.생김새와 출신, 행동양식은 달라도,그들은 제국을 만드는데 하나의 힘으로 뭉쳤다.무력뿐만 아니라 지략에서도 좋은 예가 있다.칭기즈칸의 옆에서 전략을 담당한 사람! 바로 야율초재. 그는 거란 황실 출신이었지만 칭기즈칸 이후로도 30여 년간 재상으로 활약했다. 오직 정복만을 알았던 몽고인들에게식량 생산과 세금, 지배의 방법을 알려준 인물로 알려져 있다. 스타트업은 항상 인재에 목마르다.초기에는 능력 있는 인재보다는주변에서 쉽게 만날 수 있는 인력을선호하다 보니 어느 정도 연고주의가 적용된다.하지만 성장하기 위해서는그러한 인력풀 바운더리에서 벗어나서다양성과 능력 있는 인재를 찾아 합류시켜야 한다.칭기즈칸의 멤버 구성의 원천은 관용이었다.칭기즈칸은 항복한 적에게 관대하여,회유와 포섭을 권유하였으며,투항한 적은 심복으로 삼았다.조직 내에서 꼭 나와 잘 맞는 사람만 존재하지 않는다.나와 성향이 다르고, 성격이 안 맞는 사람도 존재한다.그러나 다양성을 존중하고, 인정해 갈 때,우리는 더 많은 의견과 생각을 얻고성장해 나갈 수 있다.칭기즈칸이 그래서 얻은 것이 중국에게는 화약을, 고려에게는 말과 활을, 아랍에게는 과학과 정보를 얻었기에더욱 강대할 수 있었다.후일담이지만 칭기즈칸의 5대손인쿠빌라이 칸이 죽고 난 뒤,원나라는 한족에 대한 차별정책으로너무 많은 지역적 봉기를 유발하였고,국력이 빠르게 소진되어갔다고 한다.고위직을 모두 몽고인으로 대체하였으며,이로 인해 타민족의 민심이반이 커졌다.마치 스타트업이 어느 정도 안정적인 포지셔닝이 되었을 때,혈연, 지연, 학연 등의 연고주의로 낙하산이 경영진으로 내려오면서회사가 기울어 가는 모습이 떠오르는 것은지나친 상상일까?3. 확실한 마케팅칭기즈칸은 굴복하지 않는 적을 무자비하게 몰살시켰다.그래서 칭기즈칸의 적들은 공포심에 싸워보기도 전에 항복하는 경우가 많았다.소문은 전쟁 승패보다 빠르게 전해지면서싸우다 몰살하기보다투항해서 같은 편이 되는 선택을 강요하였다.몽고군이 온다고 하면,다들 벌벌 떨고, 짐 싸서 도망가기 바쁘다.아니면...몽고군을 환영하고, 성문을 열어주든가.사실 몽고군이 아무리 기동력이 뛰어난 군대였다고 하여도그 넓은 땅과 수많은 민족, 적들을 다 이겼다는 점은상식적으로 이해하기 어려웠다.하지만, 실제 전투의 횟수보다 투항의 횟수가 더 많은 점에서뛰어난 마케팅으로 직접적인 손실을 줄이고,오히려 군세를 더 확대하는 방식으로 세력을 키워간다.4. 강한 동기칭기즈칸은 어린 시절부터우여곡절로 고생을 많이 한 인물이다.아버지가 독살되기도 하고,전쟁의 포로가 되기도 하고,아내를 적에게 빼앗기기도 하고,중과부적의 상황에서 싸우기도 하였으며,내부적으로도 칸이라는 지위를호시탐탐 노리는 위협을 극복하였기에입지적인 인물로 소개된다.이러한 아슬아슬했던 환경과아팠던 시간들을칭기즈칸은 강한 원동력으로 삼았다.누군가에게는 이러한 배경들이자포자기하고, 타협할 수 있는 근거로 쓰이겠지만누군가에게는 이러한 배경이었기 때문에더 악으로, 깡으로, 절실하게밀어붙일 수 있는 강력한 동기가 되기도 한다.어두웠던 환경의 핑계를 대지 말자.과거의 이유를 들먹이지 말자.부족함을 근거로 피하지 말자.결핍의 논리로 포기하지 말자.어두웠기에 빛을 향해 나가야 할 목적이 생기고과거보다 더 나은 미래를 위해 달려야 할 이유가 되고부족함은 겸손과 배움을 통한 채움을 깨닫게 해 주며없음은 오히려 내게 힘을 채울 수 있는 공간이다.저 넓은 땅을 갈망하라.저 산 너머의 달콤한 열매를 탐하라.강렬한 동기는 확실한 목표를 향해 달리는 힘이 되어 줄 것이다.5. 동고동락훗날 쿠빌라이 칸에 의하여, 수도가 몽골에서 중국으로 옮겨지면서 거대 제국 원나라가 세워지기 전까지칭기즈칸 이후, 4대에 걸쳐 초원 생활을 하였다.(몽골 전통 가옥 게르)당연히 초대 왕인 칭기즈칸은 궁궐이 아닌 초원의 천막(게르)에서병사들과 함께 생활을 하였다.(물론 좀 더 크고, 더 갖춘 천막이었지만...)이에 대하여 몇 가지 가설은몽골 유목민의 생활양식이기 때문이다,정착, 거주 생활에 익숙하지 않았다,국가의 기틀이 다져지지 않았기 때문이다등의 여러 의견이 있는데...전우들이 불편한 삶을 감당하고 있고,언제든지 적이 공격해 올 수 있고,급하게 추격을 해야 할 수도 있는 전시상황의 연속선 상에서쉽게 등 따시고, 안전한 곳에 숨어있을 위인은 아니었을 테다.오히려 쉼 없이 말을 달리고,전우들과 마유주를 밤새 퍼마시기도 하고,다음 날 아침에 말린 고기를 물에 불려 질겅이며,모래바람을 마주하는 모습이 더 어울리는 위인이다.정복전쟁(또는 통일전쟁)을 하기 위해달려야 할 곳들이 너무나 넓었고,싸워야 할 적이 너무나 많았다.단지 명령만 내려서 이룰 수 있는 업적이 아니다.장수들을 못 믿어서가 아니라,장수들과 함께 이루어야 할 일들이기 때문이다.그들과 전장을 누비며,승리의 달콤함을 공유하였고,그들과 도망 다니기도 하고,그들과 굶기도 하고,그들과 축배를 들기도 한다.그것이 초기 창업자의 멋들어진 삶이었으리라.그것이 칭기즈칸의 전성기(클라이맥스)였으리라.칭기즈칸을 좀 미화한 감은 있지만,오직 내가 배워야 할 좋은 점을 찾아 내 것으로 만드는 것이다.오늘의 내가 살아가야 하는 방향을역사 속 칭기즈칸에게서 전달받는다.바통 터치!자! 말 달리자!#클린그린 #스타트업 #창업가 #창업자 #마인드셋 #조언
조회수 4546

RESTful API를 설계하기 위한 디자인 팁

올라왔었던 REST 아키텍처를 훌륭하게 적용하기 위한 몇 가지 디자인 팁의 글에서 언급되지 않았던 추가적인 내용에 대해서 좀 더 얘기해보고자 합니다. 혹시 이전 포스팅을 읽지 않으셨다면 이전 포스팅을 먼저 읽으신 후 이 포스팅을 읽어주시기 바랍니다.Document?컬렉션에 관해서는 앞서 소개한 이전 글에서 자세히 설명해놓았으니 읽어보시기 바랍니다. 지금 제가 언급할 것을 도큐먼트인데요. 도큐먼트는 컬렉션과는 달리 단수명사나 명사의 조합으로 표현되어 URI에 나타납니다.http://api.soccer.restapi.org/leagues/seattle/teams/trebuchet/players/claudio 위의 예제에서 leauges라는 컬렉션 리소스가 있는 것을 알 수 있습니다. 그 컬렉션의 자식 리소스 중 하나가 seattle이라는 리소스인데요, 바로 이 리소스가 도큐먼트입니다. 도큐먼트는 하위 계층으로 또 컬렉션을 가질 수 있습니다. 이 예제에서의 teams가 seattle의 자식 컬렉션 리소스가 되겠지요. 즉, 단수 리소스는 도큐먼트라 칭하고 복수 리소스는 컬렉션으로 칭한다고 알아두시면 됩니다.이 URI는 또한 문서의 계층 구조를 표현하고 있습니다. 즉 슬래시 기호(/) 다음으로 나타내는 명사가 그 앞에 나오는 명사의 자식 계층이 되는 것이지요. 이러한 도큐먼트의 응답으로써, 요청에서 명시된 Content-Type 헤더에 1:1대응하는 응답을 주는 것이 의미 있을 때가 있습니다. 가령,URI : dogs/1 1) Content-Type: application/json 2) Content-Type: application/xml 3) Content-Type: application/png 이와 같은 URI에 3개의 요청이 주어졌고, 각각 Content-Type이 다음과 같을 때 어떤 응답이 보내져야 할까요? 물론, 그것은 응답을 설계한 사람의 맘이지만 일반적인 기준을 적용해본다면 1번과 2번 요청에는 각각 json, xml 형식으로 구조화된 데이터가 그리고 3번 요청에 대해서는 해당 강아지의 사진이 담긴 png 파일을 보낼 수 있을 것입니다. 또한, Content-Type에 대해서 명시하여 원하는 리소스를 선택할 수 있으므로 URI 내에는 파일 확장자를 포함하지 않는 것이 좋습니다.dogs/1.xml 위와 같은 URI를 만드는 것보다, dogs/1 위의 URI에 Content-Type: application/xml헤더를 포함하여 요청을 보내는 것이 더 적절한 선택입니다. 어째서 파일에 확장자를 붙이지 않는 것이 더 나은 선택일까요? URI는 고유한 리소스를 나타내는 데 쓰여야 합니다. 그런데 URI에 확장자를 붙이는 순간 마치 다른 리소스인 것처럼 느껴집니다. 확장자를 달리하여 같은 리소스에 대한 다른 표현 양식을 주문하는 것이지 해당 리소스가 달라지는 것은 아닙니다. 또한, URI에 직접 확장자가 붙게 되면 해당 리소스 URI가 응답으로 지원하는 확장자만큼 새로운 URI들이 생기게 되겠지요. 결코, 이것은 좋은 디자인이 아닙니다.Controller?기본으로 GET, PUT, POST, DELETE 요청에 1:1매치 되는 개념인 CRUD가 있습니다. CRUD의 앞글자들을 풀어보면 Create, Read, Update, Delete가 될 텐데, 각각 POST, GET, PUT, DELETE에 대응되는 개념입니다. 그런데 사실 URI를 디자인 하다 보면 이러한 방식으로 나타내기 참 어려운 경우를 많이 만나게 됩니다. 그 중 가장 많은 경우가 어떤 특정한 행위를 요청하는 경우입니다. 많은 분이 이럴 때 동사를 쓰는데, 앞선 포스팅에서 밝혔듯이 동사를 써서 URI를 디자인하는 것은 대체로 옳지 않은 방식으로 여겨집니다.이럴 때 컨트롤러 리소스를 정의하여 이 문제를 해결할 수 있습니다. 컨트롤러 리소스는 URI 경로의 제일 마지막 부분에 동사의 형태로 표시되어 해당 URI를 통해 접근했을 때 일어날 행위를 생성합니다. (개념적으로는 이렇게 받아들이시면 됩니다.) 생성과 관련된 요청이 POST이기 때문에 컨트롤러 리소스에 접근하려면 POST 요청을 보내야 합니다. 예제를 살펴보시면 이해하기 빠르실 겁니다.http://api.college.restapi.org/students/morgan/register 리소스 morgan을 등록 http://api.ognom.restapi.org/dbs/reindex 리소스 dbs를 재색인 http://api.build.restapi.org/qa/nightly/runTestSuite 리소스 nightly에 테스트를 수행 그리고 마치 프로그램의 함수처럼 컨트롤러 리소스에는 입력값을 전달할 수 있습니다. 그것은 POST 요청의 엔티티 바디에 포함되어야 합니다. 그리고 역시 함수에서 반환값을 돌려주듯이 컨트롤러 리소스에서는 해당 입력 값에 대한 응답 값을 돌려주면 되겠습니다.URI 뒤에 붙는 쿼리의 용도흔히 GET 요청을 보낼 때 뒤에 추가로 쿼리 스트링(?,=,& 기호를 이용하여)을 전달하곤 합니다. 여기서는 그 쿼리 스트링을 어떻게 디자인 하는 게 좋은지에 대한 논의와 함께 실제 서비스에서 사용되는 사례를 살펴봅니다.가령 특정 컬렉션 리소스에 대하여 질의를 보낼 때 그 컬렉션의 집합이 너무 거대할 수 있으므로 필요한 정도의 정보만을 요구하기 위해서 페이징 값 혹은 구분 값을 쿼리 스트링에 포함할 수 있습니다. 예를 들어 보면/resources?pageSize=10&pageStartIndex=0 페이징을 위한 정보 전달 /dogs?color=red&state=running&location=park 구체적인 검색 제약사항 전달 이런 식으로 써서 페이징을 한다든가 혹은 다른 파라메터(color=red)따위를 던져서 검색 범위를 제한할 수 있습니다. 흔히 쿼리 스트링을 저런 용도로 많이 사용하기 때문에 아마 관찰력이 좋으신 분들은 저런 종류의 쿼리 파라메터를 네이버, 구글 같은 포털사이트의 검색 서비스를 이용하시면서 본 적이 있으실 것입니다.이와는 약간 다르게 실제 DB에서 사용하는 SQL의 select 문과 같은 결과를 낼 수 있도록 돕는 쿼리 스트링을 URI에 나타내려는 시도도 많은 편인데요. 물론 SQL에서 제공하는 구문의 모든 의미를 다 제공할 필요는 없겠지만, 기본적으로 서비스에서 필요한 정도의 인터페이스를 적절히 제공한다면 사용자가 선택할 수 있는 옵션이 많아진다는 측면에서 좋은 방법이겠죠. 이와 관련된 예제를 몇 개 소개하겠습니다. 이것은 실제 서비스에서 API로 제공되었던 URI들입니다. 구조나 의미가 SQL 문과 상당히 유사합니다.LinkedIn /people:(id,first-name,last-name,industry) 이 경우 people 리소스를 요청하되 마치 SQL 쿼리에서 가져올 필드를 제한하는 것처럼 필요한 필드에 대해서만 괄호로 묶어서 지정한 것을 볼 수 있습니다. Facebook /joe.smith/friends?fields=id,name,picture 이 경우 이름(혹은 계정이름)이 joe.smith인 사람의 정보를 가져오되 LinkedIn의 예와 같이 필드를 제한(id,name,picture)해서 가져오도록 한 예입니다. Google ?fields=title,media:group(media:thumbnail) 구글도 마찬가지네요. 이쯤 오면 대략 저 URI가 무엇을 의미하는지 알아채셨으리라 생각합니다. URI 설계시에 주의해야 할 점URI에는 소문자를 사용해야 합니다. 왜냐하면, RFC 3986은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하기 때문이지요.http://api.example.restapi.org/my-folder/my-doc HTTP://API.EXAMPLE.RESTAPI.ORG/my-folder/my-doc 위의 두 URI는 같은 URI입니다. 호스트에서는 대소문자를 구별하지 않기 때문이지요. http://api.example.restapi.org/my-folder/my-doc http://api.example.restapi.org/My-Folder/my-doc 하지만 위의 두 URI는 다른 URI입니다. 뒤에 붙는 path가 대소문자로 구분되기 때문입니다. 물론 소문자가 아닌, 대소문자를 섞어 쓰거나 혹은 대문자만 쓰는 것도 가능하지 않으냐는 반론이 나올 수 있습니다. 하지만 대소문자를 섞어 쓰면 URI를 기억하기 어려울 뿐만 아니라 실제 사용 시 실수하기 쉽다는 단점이 있습니다. 만약 대문자만 쓴다면 상관은 없겠으나 일반적으로는 URI에 대문자를 잘 쓰지 않기 때문에 소문자로 쓰는 것을 권장합니다.HTTP HEADERHTTP 요청과 응답을 보낼 때 특정 헤더를 포함해 요청, 응답 그리고 리소스에 대한 메타 정보를 전달할 수 있습니다. 요청 헤더와 응답 헤더에 포함되면 좋을 만한 헤더 정보들에 대하여 알아보겠습니다.요청 헤더Accept응답으로 받고 싶은 미디어 타입을 명시하기 위하여 사용됩니다. 예제를 들어 설명하겠습니다.GET /magna-opus HTTP/1.1 Host: example.org Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 이 요청은 mangna-opus 리소스에 대해서 기본적으로는 html이나 xhtml의 형식으로 응답을 받고 싶되, 만약 상황이 여의치 않으면 xml을 만약 그것도 여의치 않다면 모든 응답(*/*)을 받아들이겠다는 것을 말합니다. 옆에 붙은 q가 선호도를 나타내게 되지요. (q 생략 시 1값을 가짐) 만약 앞의 예에서 모든 응답에 대한 표시가 없다고 가정하고 서버에서 앞의 세 가지 미디어 타입을 모두 지원할 수 없는 상황이라면 응답으로 406 상태코드를 내보내야 합니다.Accept-Charset응답으로 받고 싶은 캐릭터셋에 대하여 명시하는 헤더입니다.Accept-Charset: iso-8859-5, unicode-1-1;q=0.8 가령 위의 예제는 일단 iso-8859-5를 선호하지만 unicode-1-1도 괜찮다는 메시지를 전달합니다.User-Agent현재 요청을 보낸 Agent의 정보를 표시하기 위해 사용됩니다.User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0 파이어폭스 버전 21.0의 UA스트링, OS에 대한 정보도 담겨져있다. Referer해당 요청을 보내기 바로 직전에 참조하던 리소스 혹은 주소에 대한 정보를 나타내기 위해 사용합니다.Referer: http://en.wikipedia.org/wiki/Main_Page 응답 헤더Content-Length요청과 응답 메시지의 엔티티 바디가 얼마나 큰지에 대한 정보를 나타내기 위해 사용합니다. 단위는 바이트입니다.Content-Length: 348 Last-Modified해당 리소스가 마지막으로 갱신된 시간을 나타내기 위하여 사용됩니다. 캐싱 정책과 관련되어 중요한 헤더중 하나입니다.Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT 캐시나 쿠키정책과 관련된 헤더 정보는 글의 분량을 고려하여 생략하였지만, 매우 중요한 헤더 중 하나이므로 다른 관련 문서들을 검색하여 일독을 권합니다.HTTP 상태 코드의미에 잘 맞는 URI를 설계하는 것도 중요한 일이지만 그 리소스에 대한 응답을 잘 내어주는 것 또한 중요한 일입니다. 그런데 혹시 HTTP의 상태코드 중 200이나 404코드 정도만 알고 계시지 않으신가요? 그 코드의 정확한 의미를 얘기하실 수 있으신가요? 사실 저도 흔하게 볼 수 있는 상태코드 몇 개 정도만 알고 있고 나머지 상태코드의 정확한 의미라든지 쓰임새에는 관심이 별로 없었던 것이 사실이었습니다. 하지만 전문적으로 웹 개발의 길을 걸어갈 사람이라면 그보다는 좀 더 자세히, 많이 알고 있을 필요가 있겠지요. 사실 우리가 생각하는 것보다 훨씬 많은 상태코드가 존재하고 각각 그 쓰임이 다 다릅니다. 그 중 몇 개를 살펴보겠습니다.200 : OK일반적인 요청 성공을 나타내는 데 사용합니다. 단, 주의해야 할 점이 있다면 200코드를 에러 응답에 사용하면 안 된다는 것입니다. 가령 코드는 200인데 에러메시지를 포함한다든가 하면 의미에 맞지 않은 응답코드를 보낸 것이겠지요. 이런 적절치 못한 상황을 처리하는 경우에는 4XX대 코드를 사용하여야 합니다.201 : Created리소스 생성 성공에 대한 응답 코드입니다. CRUD 요청에서 Create 요청에 대한(즉, 컬렉션에 도큐먼트 추가 같은) 응답으로 내보낼 수 있는 응답코드입니다. 응답 헤더의 Location 필드에 생성된 리소스에 접근할 수 있는 URI를 포함할 수 있다면 브라우저에서 그 값을 참조하여 적절히 대응할 수 있겠습니다.202 : Accepted대체로 처리 시간이 오래 걸리는 비동기 요청에 대한 응답으로 사용됩니다. 즉, 이 요청에 대한 응답이 결과를 포함하지 않을 수 있다는 것이죠. 하지만 최소한 응답 헤더나 응답데이터에 해당 처리를 모니터링할 수 있는 리소스 페이지를 안내하거나 혹은 해당 리소스가 처리되기까지의 예상 경과 시간 따위를 안내하는 것이 더 좋은 설계라고 할 수 있겠습니다.301 : Moved Permanently리소스가 이동되었을 경우의 응답코드입니다. 새로 리소스가 이동된 URI를 응답 Location 헤더에 명시해야 합니다. 이 응답을 받은 클라이언트는 새 URI로 이동하든지 아니면 URI를 갱신하고 캐싱을 한다든지 하는 행위를 해야 되겠지요.400 : Bad Request일반적인 요청실패에 사용합니다. 대체로 서버가 이해할 수 없는 형식의 요청이 왔을 때 응답하기 위해 사용됩니다. 무턱대고 400에러를 응답으로 주지 말고, 다른 4XX대의 코드가 더 의미를 잘 설명할 수 있는지에 대하여 고민해야 합니다.401 : Unauthorized말 그대로 리소스 접근 권한을 가지고 있지 않다는 것을 의미하기 위한 응답코드입니다. 리소스를 획득하기 위하여 요청자는 인증에 필요한 헤더(가령 Authorization 헤더 같은)나 데이터를 첨부해야 할 것입니다. 필요한 헤더나 데이터는 서버 쪽에서 요구하는 스펙을 충실히 따라야겠지요.403 : Forbidden감춰진 리소스에 접근하려 할 때의 응답코드입니다. 401과 달리 인증의 여부와 관계없이 리소스를 보여주지 않습니다. 기본적으로 클라이언트 쪽에 정보를 공개하고 싶지 않은 리소스임을 나타내기 위해 사용합니다.404 : Not Found해당 URI와 매치되는 리소스가 없다는 의미를 전달합니다. 어지간한 사람들은 다 한 번씩(?) 마주치게 되는 응답코드이지요.405 : Method Not Allowed지원하지 않는 요청(예를 들어 POST 요청을 받는 컨트롤러 리소스에 GET 요청을 보낸다든가)을 하였을 때 사용합니다. 가능하다면 응답 메시지에 Allow 헤더를 추가하고 그곳에 지원하는 메서드를 명시하여 클라이언트 측에서 정확한 요청을 보낼 수 있도록 유도합니다.Allow: GET, POST 406 : Not Acceptable해당 미디어 타입(MIME 타입)에 대해서 지원하지 않을 때 사용합니다. 요청 Accept 헤더에 명기된 타입(가령 Application/xml)에 대해서 지원이 불가능할 경우에 돌려주면 되는 코드입니다.409 : Conflict요청의 형식에는 문제가 없지만 리소스 상태에 의하여 해당 요청 자체를 수행할 수 없는 경우의 응답코드입니다. 즉, 이미 삭제된 리소스를 또 삭제한다든가 비어있는 리스트에서 무언가를 요청한다든가 하는 모순된 상황을 생각해보면 되겠습니다. 응답으로는 그 방법을 어떻게 해결할 수 있을지에(혹은 문제가 무엇인지) 대한 힌트가 포함되면 좋을 것입니다.500 : Internal Server Error일반적인 서버 에러에 대한 응답코드입니다. 4XX대의 에러코드가 클라이언트 측 에러를 나타내기 위해 사용된다면, 5XX대의 에러코드는 서버 측 에러를 나타내기 위해 사용됩니다.503 : Service Unavailable가장 두려운(?) 응답코드 중 하나일 503입니다. 현재 서버에 과부하가 걸려있거나 유지보수를 위하여 잠시 접근이 거부될 때 필요한 응답코드입니다.그냥 맨 앞의 숫자별로 퉁쳐서 상태코드를 내보내지 않고, 이렇게 디테일한 의미까지 따져가면서 상태코드를 내보내는 것에 대해서 그 효용성에 의문을 제기하시는 분들이 있을 것 같습니다. 하지만 브라우저에서 혹은 서버 단에서 특정 상태코드에 대해서 내부 구현을 달리하거나 최적화를 통해 더 쾌적한 환경을 제공할 가능성이 있으므로 되도록 의미에 걸맞은 상태코드를 사용하는 것을 생활화하는 것이 중요합니다. 또한, 이렇게 디테일한 상황을 가정하고 만든 URI들이 다음에 서비스를 확장할 때 큰 도움이 될 것임은 의심할 여지가 없겠지요.위에서 소개한 응답 코드 말고 또 다른 응답 코드들에 대해서도 전부 소개해 놓은 링크를 밑에 달아두었으니 참고하시기 바랍니다.정리지금까지 소개한 내용이 조금은 두서없게 느껴졌을 수도 있겠다는 생각이 들어 한 번 전체 내용 정리를 해보려 합니다.컨트롤러의 정확한 쓰임을 알고 적절한 컨트롤러 URI를 구현하자.URI에 추가로 붙게 되는 쿼리 스트링의 형식을 잘 디자인하여 사용자로 하여금 적재적소에 쓸 수 있도록 하자.가능하다면 이용 가능한 HTTP 헤더를 적절하게 첨가하자.HTTP 상태코드의 의미에 대해서 생각해보고 상황에 맞는 적절한 상태 코드를 응답으로 보내줄 수 있도록 하자.이 글을 쓰면서 한빛 미디어의 일관성 있는 웹 서비스 인터페이스 설계를 위한 REST API 디자인 규칙과 apigee사의 web API design eBook을 참고하였습니다. 둘 다 내용이 좋은 서적이고 이 글에서 다루지 않은 심층 내용을 다루니 기회가 되시면 읽어보세요.referencesUniform resource identifierapigee api design best practicesrestful uri designHTTP status codesList of HTTP status codesURI schemeMIME typesMIMEfun and unusual http response headers#스포카 #디자인 #디자이너 #디자인팀 #개발 #개발자 #개발팀 #협업 #코워킹 #Co-working #업무프로세스 #꿀팁 #인사이트

기업문화 엿볼 때, 더팀스

로그인

/